Elasticsearch 荧光笔误报
Posted
技术标签:
【中文标题】Elasticsearch 荧光笔误报【英文标题】:Elasticsearch highlighter false positives 【发布时间】:2018-08-12 06:46:35 【问题描述】:我在 ES 6.1.1 中使用 nGram
标记器并得到一些奇怪的亮点:
tra
在文档 9 中被错误地突出显示
查询 auftrag
与预期的文档 7 和 9 匹配,但在文档 9 中 betrag
未正确突出显示。这是荧光笔的问题 - 如果问题出在查询 doc 8 也会被返回。
示例代码
#!/usr/bin/env bash
# Example based on
# https://www.elastic.co/guide/en/elasticsearch/guide/current/ngrams-compound-words.html
# with suggestions from from
# https://github.com/elastic/elasticsearch/issues/21000
如果存在则删除索引
curl -sS -XDELETE 'localhost:9200/my_index'
printf '\n-------------\n'
创建新索引
curl -sS -XPUT 'localhost:9200/my_index?pretty' -H 'Content-Type: application/json' -d'
"settings":
"analysis":
"analyzer":
"trigrams":
"tokenizer": "my_ngram_tokenizer",
"filter": ["lowercase"]
,
"tokenizer":
"my_ngram_tokenizer":
"type": "nGram",
"min_gram": "3",
"max_gram": "3",
"token_chars": [
"letter",
"digit",
"symbol",
"punctuation"
]
,
"mappings":
"my_type":
"properties":
"text":
"type": "text",
"analyzer": "trigrams",
"term_vector": "with_positions_offsets"
'
printf '\n-------------\n'
填充索引
curl -sS -XPOST 'localhost:9200/my_index/my_type/_bulk?pretty' -H 'Content-Type: application/json' -d'
"index": "_id": 7
"text": "auftragen"
"index": "_id": 8
"text": "betrag"
"index": "_id": 9
"text": "betrag auftragen"
'
printf '\n-------------\n'
sleep 1 # Give ES time to index
查询
curl -sS -XGET 'localhost:9200/my_index/my_type/_search?pretty' -H 'Content-Type: application/json' -d'
"query":
"match":
"text":
"query": "auftrag",
"minimum_should_match": "100%"
,
"highlight":
"fields":
"text":
"fragment_size": 120,
"type": "fvh"
'
我得到的点击是(缩写):
"hits" : [
"_id" : "9",
"_source" :
"text" : "betrag auftragen"
,
"highlight" :
"text" : [
"be<em>tra</em>g <em>auf</em><em>tra</em>gen"
]
,
"_id" : "7",
"_source" :
"text" : "auftragen"
,
"highlight" :
"text" : [
"<em>auf</em><em>tra</em>gen"
]
]
我尝试了各种解决方法,例如使用统一/fvh 荧光笔并设置所有似乎相关的选项,但没有运气。非常感谢任何提示。
【问题讨论】:
嗯...我正在使用您的上述设置对您的所有三个测试文档进行点击...上面是否可能缺少某些内容? 如果我使用快速查询 API,我也会得到三个点击,例如curl -sS localhost:9200/my_index/_search?q=auftrag
。但是上面的脚本返回 2 个点击,我认为是因为 minimum_should_match
。如果这很重要,我会像这样运行 ES:docker run -it -p 9200:9200 docker.elastic.co/elasticsearch/elasticsearch:6.1.1
【参考方案1】:
这里的问题不在于突出显示,而在于您如何使用 nGram 分析器。
首先当您以这种方式配置映射时:
"mappings":
"my_type":
"properties":
"text":
"type" : "text",
"analyzer" : "trigrams",
"term_vector": "with_positions_offsets"
您对 Elasticsearch 说您想将它用于索引文本并提供搜索词。在你的情况下,这仅仅意味着:
-
文档 9 = "betrag auftragen" 中的文本被拆分为三元组,因此在索引中您有如下内容:[bet, etr, tra, rag, auf, uft, ftr, tra, rag, age, gen]
文档 7 = "auftragen" 中的文本被拆分为三元组,因此在索引中您有如下内容:[auf, uft, ftr, tra, rag, age, gen]
您的搜索词 =“auftrag”也被拆分为三元组,Elasticsearch 将其视为:[auf, uft, ftr, tra, rag]
最后,Elasticsearch 将搜索中的所有三元组与您的索引中的三元组匹配,因此您将分别突出显示“auf”和“tra”。 'ufa'、'ftr' 和 'rag' 也匹配,但它们与 'auf' 和 'tra' 重叠并且没有突出显示。
首先您需要对 Elasticsearch 说您不想将搜索词拆分为克。您需要做的就是将search_analyzer
属性添加到您的映射中:
"mappings":
"my_type":
"properties":
"text":
"type" : "text",
"analyzer" : "trigrams",
"search_analyzer": "standard",
"term_vector" : "with_positions_offsets"
现在,standard
analyzer 将搜索词中的词视为单独的词,因此在您的情况下,它将只是“auftrag”。
但是这个单一的改变对你没有帮助。它甚至会中断搜索,因为“auftrag”与索引中的任何三元组都不匹配。
现在您需要通过增加 max_gram
来改进您的 nGram 标记器:
"tokenizer":
"my_ngram_tokenizer":
"type": "nGram",
"min_gram": "3",
"max_gram": "10",
"token_chars": [
"letter",
"digit",
"symbol",
"punctuation"
]
这样,索引中的文本将分为 3-gram、4-gram、5-gram、6-gram、7-gram、8-gram、9-gram 和 10-gram。在这 7-gram 中,您会找到“auftrag”,这是您的搜索词。
经过这两项改进后,搜索结果中的突出显示应如下所示:
"betrag <em>auftrag</em>en"
对于文档 9 和:
"<em>auftrag</em>en"
用于文档 7。
这就是 ngram 和高亮如何协同工作。我知道ES documentation is saying:
将 min_gram 和 max_gram 设置为相同的值通常是有意义的。长度越小,匹配的文档越多,但匹配的质量越低。长度越长,匹配越具体。三元组(长度为 3)是一个很好的起点。
这是真的。出于性能原因,您需要尝试使用此配置,但我希望我向您解释了它是如何工作的。
【讨论】:
谢谢,这很有帮助。我有一个后续问题。如果我设置"search_analyzer": "standard"
和max_gram: 10
,我不会失去匹配超过 10 个单词的能力,例如包含Reiseversicherung
的文档不再匹配查询Versicherung
?我可以进一步增加max_gram
,但是磁盘上的索引大小不会爆炸吗? PS如果不清楚,用它搜索德语复合名词的用例
是的,完全正确。您必须根据需要增加max_gram
。您必须测试并调整此解决方案以满足您的需求。不幸的是,没有一种简单的方法可以拥有一切。【参考方案2】:
我在这里遇到同样的问题,使用ngram
(trigram) 标记器,得到不完整的突出显示,例如:
query with `match`: samp
field data: sample
result highlight: <em>sam</em>ple
expected highlight: <em>samp</em>le
将字段的term_vector
设置为with_positions_offsets
时使用match_phrase
和fvh
高亮类型,这样可能会得到正确的高亮。
<em>samp</em>le
我希望这可以帮助您,因为您不需要更改标记器,也不需要增加max_gram
。
但我的问题是我想使用simple_query_string
,它不支持使用phrase
进行默认字段查询,唯一的方法是使用引号来包装字符串,如"samp"
,但是因为其中有一些逻辑查询字符串,所以我不能为用户做,并且要求用户也不做。
@piotr-pradzynski 的解决方案可能对我没有帮助,因为我有很多数据,增加 max_gram
将导致大量存储使用。
【讨论】:
以上是关于Elasticsearch 荧光笔误报的主要内容,如果未能解决你的问题,请参考以下文章
普通荧光笔“order”:“none”在 Elasticsearch 中不起作用