当单词以n-gram开头时,Elasticsearch Edge NGram令牌生成器得分更高

时间:2018-11-10 11:44:29

标签: elasticsearch search n-gram

假设Edge NGram令牌生成器具有以下映射:

{
  "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应该出现在结果中。

还使用了Highlighter,因此给定的解决方案不应该弄乱它。

查询中使用的荧光笔是:

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

将其与match_phrase_prefix配合使用会弄乱突出显示,仅搜索<H><I><T><S> FIND SOME时会产生H

3 个答案:

答案 0 :(得分:4)

您必须了解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

布尔查询通常用于在需要特定用例的情况下构建复杂的查询。使用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"
          }
                }
            }
    }
  }
}

答案 1 :(得分:3)

在这种特殊情况下,您可以向查询中添加一个match_phrase_prefix词,该词在文本的最后一个词上没有前缀匹配:

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

match项将在所有三个结果上都匹配,但match_phrase_prefixTRENDING HI上将不匹配。结果,您将获得结果中的所有三个项目,但是TRENDING HI的得分会降低。

引用docs

  

match_phrase_prefix查询是穷人的自动完成[...]有关按类型搜索的更好解决方案,请参见完成建议器和“按时间搜索按类型搜索”。

顺便说一句,如果要引入bool查询,则可能要根据所需结果查看minimum_should_match选项。

答案 2 :(得分:1)

此问题的可能解决方案是使用multifields。它们允许以不同的方式索引源文档中的相同数据。在您的情况下,您可以将name字段索引为默认text,然后索引为ngrams,也索引为edgengrams。然后,查询将必须是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"
                        }
                    }
                }
            ]
        }
    }
}