Elasticsearch return 带搜索的拼音标记

Elasticsearch return phonetic token with search

由于语音转换,我使用弹性搜索中的 phonetic analysis plugin 进行一些字符串匹配。

我的问题是,如何在查询结果中进行弹性搜索处理的语音转换?

首先,我使用 metaphone 转换创建索引:

request_body = {
    'settings': {
        'index': {
            'analysis': {
                'analyzer': {
                    'metaphone_analyzer': {
                        'tokenizer':
                        'standard',
                        'filter': [
                            'ascii_folding_filter', 'lowercase',
                            'metaphone_filter'
                        ]
                    }
                },
                'filter': {
                    'metaphone_filter': {
                        'type': 'phonetic',
                        'encoder': 'metaphone',
                        'replace': False
                    },
                    'ascii_folding_filter': {
                        'type': 'asciifolding',
                        'preserve_original': True
                    }
                }
            }
        }
    },
    'mappings': {
        'person_name': {
            'properties': {
                'full_name': {
                    'type': 'text',
                    'fields': {
                        'metaphone_field': {
                            'type': 'string',
                            'analyzer': 'metaphone_analyzer'
                        }
                    }
                }
            }
        }
    }
}

res = es.indices.create(index="my_index", body=request_body)

然后,我添加一些数据:

# Add some data
names = [{
    "full_name": "John Doe"
}, {
    "full_name": "Bob Alice"
}, {
    "full_name": "Foo Bar"
}]

for name in names:
    res = es.index(index="my_index",
                   doc_type='person_name',
                   body=name,
                   refresh=True)

最后,我查询了一个名字:

es.search(index="my_index",
          body={
              "size": 5,
              "query": {
                  "multi_match": {
                      "query": "Jon Doe",
                      "fields": "*_field"
                  }
              }
          })

搜索 returns:

{
    'took': 1,
    'timed_out': False,
    '_shards': {
        'total': 5,
        'successful': 5,
        'skipped': 0,
        'failed': 0
    },
    'hits': {
        'total':
        1,
        'max_score':
        0.77749264,
        'hits': [{
            '_index': 'my_index',
            '_type': 'person_name',
            '_id': 'AWwYjl4Mqo63y_hLp5Yl',
            '_score': 0.77749264,
            '_source': {
                'full_name': 'John Doe'
            }
        }]
    }
}

在搜索中return我想在elastic search中获取名称的语音转换(也来自查询名称,但不太重要)当我执行搜索。

我知道,我可以使用 explain API 但我想避免第二次请求,而且 explain API 看起来有点 "overkill" 为了我想要达到的目标。

谢谢!

在 Elasticsearch 查询中实现它看起来并不容易,但您可以尝试 analyze API and scripted fields with fielddata enabled, and term vectors 可能会派上用场。方法如下。

从任意查询中检索标记

Analyze API 如果您想了解 Elasticsearch 究竟如何标记您的查询,这是一个很好的工具。

使用你的映射你可以做,例如:

GET myindex/_analyze
{
  "analyzer": "metaphone_analyzer",
  "text": "John Doe"
}

并得到这样的结果:

{
  "tokens": [
    {
      "token": "JN",
      "start_offset": 0,
      "end_offset": 4,
      "type": "<ALPHANUM>",
      "position": 0
    },
    {
      "token": "john",
      "start_offset": 0,
      "end_offset": 4,
      "type": "<ALPHANUM>",
      "position": 0
    },
    {
      "token": "T",
      "start_offset": 5,
      "end_offset": 8,
      "type": "<ALPHANUM>",
      "position": 1
    },
    {
      "token": "doe",
      "start_offset": 5,
      "end_offset": 8,
      "type": "<ALPHANUM>",
      "position": 1
    }
  ]
}

这在技术上是一个不同的查询,但仍然可能有用。

从文档的字段中检索标记

理论上,我们可以尝试从与我们的查询匹配的文档中检索在上一节中分析 API return 的完全相同的标记。

实际上 Elasticsearch 不会存储 text field it has just analyzed: fielddata 的令牌,默认情况下是禁用的。我们需要启用它:

PUT /myindex
{
  "mappings": {
    "person_name": {
      "properties": {
        "full_name": {
          "fields": {
            "metaphone_field": {
              "type": "text", 
              "analyzer": "metaphone_analyzer",
              "fielddata": true
            }
          }, 
          "type": "text"
        }
      }
    }
  }, 
  "settings": {
    ...
  }
}

现在,我们可以使用 scripted fields 请求 Elasticsearch return 那些标记。

查询可能如下所示:

POST myindex/_search
{
  "script_fields": {
    "my tokens": {
      "script": {
        "lang": "painless",
        "source": "doc[params.field].values",
        "params": {
          "field": "full_name.metaphone_field"
        }
      }
    }
  }
}

响应如下所示:

{
  "hits": {
    "total": 1,
    "max_score": 1,
    "hits": [
      {
        "_index": "myindex",
        "_type": "person_name",
        "_id": "123",
        "_score": 1,
        "fields": {
          "my tokens": [
            "JN",
            "T",
            "doe",
            "john"
          ]
        }
      }
    ]
  }
}

如您所见,完全相同的标记(但顺序随机)。

我们还可以检索有关这些标记在文档中的位置的信息吗?

检索代币及其位置

term vectors 可能会有帮助。为了能够使用它们,我们实际上不需要启用 fielddata。我们可以查找文档的术语向量:

GET myindex/person_name/123/_termvectors
{
  "fields" : ["full_name.metaphone_field"],
  "offsets" : true,
  "positions" : true
}

这会 return 像这样:

{
  "_index": "myindex",
  "_type": "person_name",
  "_id": "123",
  "_version": 1,
  "found": true,
  "took": 1,
  "term_vectors": {
    "full_name.metaphone_field": {
      "field_statistics": {
        "sum_doc_freq": 4,
        "doc_count": 1,
        "sum_ttf": 4
      },
      "terms": {
        "JN": {
          "term_freq": 1,
          "tokens": [
            {
              "position": 0,
              "start_offset": 0,
              "end_offset": 4
            }
          ]
        },
        "T": {
          "term_freq": 1,
          "tokens": [
            {
              "position": 1,
              "start_offset": 5,
              "end_offset": 8
            }
          ]
        },
        "doe": {
          "term_freq": 1,
          "tokens": [
            {
              "position": 1,
              "start_offset": 5,
              "end_offset": 8
            }
          ]
        },
        "john": {
          "term_freq": 1,
          "tokens": [
            {
              "position": 0,
              "start_offset": 0,
              "end_offset": 4
            }
          ]
        }
      }
    }
  }
}

这提供了一种获取文档字段标记的方法,就像分析器生成的标记一样。

遗憾的是,据我所知,无法将这三个查询合并为一个查询。另外 fielddata 应谨慎使用,因为它会占用大量内存。


希望对您有所帮助!