【问题标题】:Elasticsearch highlighter false positivesElasticsearch 荧光笔误报
【发布时间】: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

标签: elasticsearch highlighting


【解决方案1】:

这里的问题不在于突出显示,而在于您如何使用 nGram 分析器。

首先当您以这种方式配置映射时:

"mappings": {
  "my_type": {
    "properties": {
      "text": {
        "type"       : "text",
        "analyzer"   : "trigrams",
        "term_vector": "with_positions_offsets"
      }
    }
  }
}

您对 Elasticsearch 说您想将它用于索引文本并提供搜索词。在你的情况下,这仅仅意味着:

  1. 文档 9 = "betrag auftragen" 中的文本被拆分为三元组,因此在索引中您有如下内容:[bet, etr, tra, rag, auf, uft, ftr, tra, rag, age, gen]
  2. 文档 7 = "auftragen" 中的文本被拆分为三元组,因此在索引中您有如下内容:[auf, uft, ftr, tra, rag, age, gen]
  3. 您的搜索词 =“auftrag”也被拆分为三元组,Elasticsearch 将其视为:[auf, uft, ftr, tra, rag]
  4. 最后,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 将导致大量存储使用。

【讨论】:

    猜你喜欢
    • 2011-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-12
    • 2012-07-31
    • 2011-05-06
    • 2011-06-01
    相关资源
    最近更新 更多