2

由于语音转换,我使用弹性搜索中的语音分析插件进行一些字符串匹配。

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

首先,我创建一个带有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'
            }
        }]
    }
}

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

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

谢谢 !

4

1 回答 1

2

在 Elasticsearch 查询中实现它看起来并不容易,但您可以尝试在启用的情况下分析 API脚本字段,术语向量可能会派上用场。就是这样。fielddata

从任意查询中检索令牌

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

使用您的映射,您可以执行以下操作,例如:

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": {
    ...
  }
}

现在,我们可以使用脚本字段要求 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"
          ]
        }
      }
    ]
  }
}

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

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

检索令牌及其位置

术语向量可能会有所帮助。为了能够使用它们,我们实际上不需要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应谨慎使用,因为它使用大量内存。


希望这可以帮助!

于 2019-07-22T18:22:05.937 回答