Elasticsearch 荧光笔误报

Posted

技术标签:

【中文标题】Elasticsearch 荧光笔误报【英文标题】:Elasticsearch highlighter false positives 【发布时间】:2018-08-12 06:46:35 【问题描述】:

我在 ES 6.1.1 中使用 nGram 标记器并得到一些奇怪的亮点:

多个相邻字符 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_phrasefvh高亮类型,这样可能会得到正确的高亮。

<em>samp</em>le

我希望这可以帮助您,因为您不需要更改标记器,也不需要增加max_gram

但我的问题是我想使用simple_query_string,它不支持使用phrase 进行默认字段查询,唯一的方法是使用引号来包装字符串,如"samp",但是因为其中有一些逻辑查询字符串,所以我不能为用户做,并且要求用户也不做。

@piotr-pradzynski 的解决方案可能对我没有帮助,因为我有很多数据,增加 max_gram 将导致大量存储使用。

【讨论】:

以上是关于Elasticsearch 荧光笔误报的主要内容,如果未能解决你的问题,请参考以下文章

普通荧光笔“order”:“none”在 Elasticsearch 中不起作用

登录报内部错误500 no access to elastic

ElasticSearch第一天

ELK 实验elasticsearch集群搭建

ElasticSearch的备份迁移方案

ElasticSearch Client详解