【问题标题】:Elasticsearch return phonetic token with searchElasticsearch 使用搜索返回语音标记
【发布时间】:2019-11-30 03:15:27
【问题描述】:

由于语音转换,我使用弹性搜索中的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"
                  }
              }
          })

搜索返回:

{
    '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'
            }
        }]
    }
}

在搜索返回中,我想在执行搜索时获取弹性搜索中名称的拼音转换(也来自查询名称,但不太重要)。

我知道,我可以使用explain API,但我想避免第二次请求,而且explain API 对于我想要实现的目标来说似乎有点“矫枉过正”。

谢谢!

【问题讨论】:

    标签: python elasticsearch elasticsearch-phonetic


    【解决方案1】:

    在 Elasticsearch 查询中实现这看起来并不容易,但您可以尝试启用 fielddataanalyze APIscripted fieldsterm 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 完全相同的标记。

    实际上,Elasticsearch 不会存储它刚刚分析的 text 字段的标记: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 返回这些令牌。

    查询可能如下所示:

    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
    }
    

    这将返回如下内容:

    {
      "_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 应谨慎使用,因为它会占用大量内存。


    希望这会有所帮助!

    【讨论】:

    • 我没有看到你的回答通知。这对我有很大帮助。
    猜你喜欢
    • 2018-01-09
    • 1970-01-01
    • 1970-01-01
    • 2018-12-30
    • 2018-02-03
    • 2019-05-24
    • 1970-01-01
    • 1970-01-01
    • 2020-10-09
    相关资源
    最近更新 更多