【问题标题】:Elasticsearch Edge NGram tokenizer higher score when word begins with n-gram当单词以 n-gram 开头时,Elasticsearch Edge NGram 标记器得分更高
【发布时间】:2019-04-13 18:47:38
【问题描述】:

假设 Edge NGram Tokenizer 有以下映射:

{
  "settings": {
    "analysis": {
      "analyzer": {
        "autocomplete_analyzer": {
          "tokenizer": "autocomplete_tokenizer",
          "filter": [
            "standard"
          ]
        },
        "autocomplete_search": {
          "tokenizer": "whitespace"
        }
      },
      "tokenizer": {
        "autocomplete_tokenizer": {
          "type": "edge_ngram",
          "min_gram": 1,
          "max_gram": 10,
          "token_chars": [
            "letter",
            "symbol"
          ]
        }
      }
    }
  },
  "mappings": {
    "tag": {
      "properties": {
        "id": {
          "type": "long"
        },
        "name": {
          "type": "text",
          "analyzer": "autocomplete_analyzer",
          "search_analyzer": "autocomplete_search"
        }
      }
    }
  }
}

并索引了以下文档:

POST /tag/tag/_bulk
{"index":{}}
{"name" : "HITS FIND SOME"}
{"index":{}}
{"name" : "TRENDING HI"}
{"index":{}}
{"name" : "HITS OTHER"}

然后搜索

{
  "query": {
    "match": {
      "name": {
        "query": "HI"
      }
    }
  }
}

产生的所有分数都相同,或者TRENDING - HI 的分数高于其他分数。

如何配置,以更高的分数显示实际上以搜索者 n-gram 开头的条目?在这种情况下,HITS FIND SOMEHITS OTHER 的得分要高于TRENDING HI;同时TRENDING HI 应该在结果中。

还使用了荧光笔,所以给定的解决方案不应该搞砸。

查询中使用的荧光笔是:

 "highlight": {
    "pre_tags": [
      "<"
    ],
    "post_tags": [
      ">"
    ],
    "fields": {
      "name": {}
    }
  }

将它与match_phrase_prefix 一起使用会打乱突出显示,在仅搜索H 时产生&lt;H&gt;&lt;I&gt;&lt;T&gt;&lt;S&gt; FIND SOME

【问题讨论】:

    标签: elasticsearch search n-gram


    【解决方案1】:

    此问题的一个可能解决方案是使用multifields。它们允许以不同的方式从源文档中索引相同的数据。在您的情况下,您可以将name 字段索引为默认text,然后作为ngramsedgengrams。那么查询必须是bool query 与所有那些不同的fields 进行比较。

    文档的最终分数由每个文档的匹配值组成。这些匹配也称为signals,表示查询和文档之间存在匹配。匹配信号最多的文档得分最高。

    在您的情况下,所有文档都将匹配 ngram HI。但只有HITS FIND SOMEHITS OTHER 文档会获得edgengram 附加分数。这将使这两个文件得到提升,并将它们放在首位。复杂之处在于您必须确保edgengram 不会在空格上拆分,因为最后的HI 将获得与文档开头相同的分数。

    这是您的案例的示例映射和查询:

    PUT /tag/
    {
        "settings": {
            "analysis": {
                "analyzer": {
                    "edge_analyzer": {
                        "tokenizer": "edge_tokenizer"
                    },
                    "kw_analyzer": {
                        "tokenizer": "kw_tokenizer"
                    },
                    "ngram_analyzer": {
                        "tokenizer": "ngram_tokenizer"
                    },
                    "autocomplete_analyzer": {
                        "tokenizer": "autocomplete_tokenizer",
                        "filter": [
                            "standard"
                        ]
                    },
                    "autocomplete_search": {
                        "tokenizer": "whitespace"
                    }
                },
                "tokenizer": {
                    "kw_tokenizer": {
                        "type": "keyword"
                    },
                    "edge_tokenizer": {
                        "type": "edge_ngram",
                        "min_gram": 2,
                        "max_gram": 10
                    },
                    "ngram_tokenizer": {
                        "type": "ngram",
                        "min_gram": 2,
                        "max_gram": 10,
                        "token_chars": [
                            "letter",
                            "digit"
                        ]
                    },
                    "autocomplete_tokenizer": {
                        "type": "edge_ngram",
                        "min_gram": 1,
                        "max_gram": 10,
                        "token_chars": [
                            "letter",
                            "symbol"
                        ]
                    }
                }
            }
        },
        "mappings": {
            "tag": {
                "properties": {
                    "id": {
                        "type": "long"
                    },
                    "name": {
                        "type": "text",
                        "fields": {
                            "edge": {
                                "type": "text",
                                "analyzer": "edge_analyzer"
                            },
                            "ngram": {
                                "type": "text",
                                "analyzer": "ngram_analyzer"
                            }
                        }
                    }
                }
            }
        }
    }
    

    还有一个查询:

    POST /tag/_search
    {
        "query": {
            "bool": {
                "should": [
                    {
                    "function_score": {
                        "query": {
                            "match": {
                                "name.edge": {
                                    "query": "HI"
                                }
                            }
                        },
                        "boost": "5",
                        "boost_mode": "multiply"
                    }
                    },
                    {
                        "match": {
                            "name.ngram": {
                                "query": "HI"
                            }
                        }
                    },
                    {
                        "match": {
                            "name": {
                                "query": "HI"
                            }
                        }
                    }
                ]
            }
        }
    }
    

    【讨论】:

      【解决方案2】:

      您必须了解 elasticsearch/lucene 如何分析您的数据并计算搜索分数。

      1.分析 API

      https://www.elastic.co/guide/en/elasticsearch/reference/current/_testing_analyzers.html 这将向您展示 elasticsearch 将存储的内容,在您的情况下:

      T / TR / TRE /.... TRENDING / / H / HI
      

      2。得分

      https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-bool-query.html

      bool 查询通常用于构建需要特定用例的复杂查询。使用must 过滤文档,然后使用should 进行评分。一个常见的用例是对同一个字段使用不同的分析器(通过在映射中使用关键字fields,您可以对同一个字段进行不同的分析)。

      3.不要乱突出

      根据文档:https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-highlighting.html#specify-highlight-query

      您可以添加额外的查询:

      {
        "query": {
          "bool": {
                  "must" : [
                              {
                "match": {
                  "name": "HI"
                }
              }
                  ],
            "should": [
              {
                "prefix": {
                  "name": "HI"
                }
              }
            ]
          }
        },
           "highlight": {
          "pre_tags": [
            "<"
          ],
          "post_tags": [
            ">"
          ],
          "fields": {
            "name": {
                      "highlight_query": {
                              "match": {
                  "name": "HI"
                }
                      }
                  }
          }
        }
      }
      

      【讨论】:

        【解决方案3】:

        在这种特殊情况下,您可以在查询中添加一个 match_phrase_prefix 术语,它会与文本中的最后一个术语匹配前缀:

        {
          "query": {
            "bool": {
              "should": [
                {
                  "match": {
                    "name": "HI"
                  }
                },
                {
                  "match_phrase_prefix": {
                    "name": "HI"
                  }
                }
              ]
            }
          }
        }
        

        match 术语将匹配所有三个结果,但match_phrase_prefix 不会匹配TRENDING HI。结果,您将在结果中获得所有三个项目,但TRENDING HI 会以较低的分数出现。

        引用docs

        match_phrase_prefix 查询是穷人的自动完成[...] 如需更好的按您输入的搜索解决方案,请参阅完成建议器和索引时间按您输入的搜索。

        附带说明,如果您要引入 bool 查询,您可能需要查看 minimum_should_match 选项,具体取决于您想要的结果。

        【讨论】:

        • 但结果我需要TRENDING HI;只是分数较低。
        • @m3th0dman 整体结果是每个词条匹配结果的组合,所以TRENDING HI会出现在结果中,而且会以较低的分数出现。编辑了答案以使其更清楚。
        • 不幸的是,这弄乱了荧光笔。
        • @m3th0dman 这是一个新元素。您能否详细说明您是如何进行突出显示的,以及您所说的“混乱”到底是什么意思?
        • 当然;谢谢。我修改了问题以包括荧光笔。使用match_phrase_prefix 时,仅搜索H 时会返回类似&lt;H&gt;&lt;I&gt;&lt;T&gt;&lt;S&gt; FIND SOME 的内容。
        猜你喜欢
        • 1970-01-01
        • 2011-06-30
        • 1970-01-01
        • 1970-01-01
        • 2015-11-21
        • 2016-08-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多