当使用带有 elasticsearch 的 ngram 过滤器时,当我搜索“test”之类的内容时,我会返回一个文档“latest”、“tests”和“test”。有没有办法让“与查询“test”完全匹配的文档总是在搜索结果中返回到更高的位置?
3 回答
这是 ngrams 的一个问题:你的排名中有很多误报。一种解决方案是将 ngram 与带状疱疹结合起来。基本上除了 ngram 之外,您还可以将完整的单词索引为单独的术语,甚至是单词的组合。带状疱疹基本上类似于 ngram,但使用的是单词而不是字符。
这样,与 shingle 术语的精确匹配比仅匹配 ngram 的分数更高。
更新。这是自定义分析器的示例。定义后,您可以在映射中使用它。在这种情况下,我使用 icu_normalizer 和折叠以及我的建议_shingle。所有这些都设置为默认分析器,因此我的所有字符串都以这种方式处理。
{
"analyzer":{
"default":{
"tokenizer":"icu_tokenizer",
"filter":"icu_normalizer,icu_folding,suggestions_shingle"
}
},
"filter": {
"suggestions_shingle": {
"type": "shingle",
"min_shingle_size": 2,
"max_shingle_size": 5
}
}
}
您可以通过映射将字段内容复制到字段。例子:
"fullName": {
"type": "string",
"search_analyzer": "str_search_analyzer",
"index_analyzer": "str_index_analyzer",
"fields": {
"fullWord": { "type": "string" },
"raw": {
"type": "string",
"index": "not_analyzed"
}
}
}
注意 str_index_analyzer 在这里使用 nGram。然后,您可以构建您的搜索来搜索这些字段。例子:
{
"query": {
"bool": {
"should": [{
"multi_match": {
"fields": [
"firstName.fullWord",
...
"query": query,
"fuzziness": "0"
}
}],
"must": [{
"multi_match": {
"fields": [
"firstName",...],
"query": query,
"fuzziness": "AUTO"
}
}]
}
}
};
}
您需要多字段和多匹配查询。
我有类似的问题。我需要按名字搜索,所以如果我输入搜索词“And”,我会得到第一个“Andy”,然后是“Mandy”。仅使用 nGram,我无法实现这一目标。
我添加了一个使用 front edgeNGram 的分析器(下面的代码用于 Spring Data Elasticsearch,但你可以理解)。
setting.put("analysis.analyzer.word_parts.type", "custom");
setting.put("analysis.analyzer.word_parts.tokenizer", "ngram_tokenizer");
setting.put("analysis.analyzer.word_parts.filter", "lowercase");
setting.put("analysis.analyzer.type_ahead.type", "custom");
setting.put("analysis.analyzer.type_ahead.tokenizer", "edge_ngram_tokenizer");
setting.put("analysis.analyzer.type_ahead.filter", "lowercase");
setting.put("analysis.tokenizer.ngram_tokenizer.type", "nGram");
setting.put("analysis.tokenizer.ngram_tokenizer.min_gram", "3");
setting.put("analysis.tokenizer.ngram_tokenizer.max_gram", "50");
setting.put("analysis.tokenizer.ngram_tokenizer.token_chars", new String[] { "letter", "digit" });
setting.put("analysis.tokenizer.edge_ngram_tokenizer.type", "edgeNGram");
setting.put("analysis.tokenizer.edge_ngram_tokenizer.min_gram", "2");
setting.put("analysis.tokenizer.edge_ngram_tokenizer.max_gram", "20");
我将必填字段映射为多个字段:
@MultiField(mainField = @Field(type = FieldType.String, indexAnalyzer = "word_parts", searchAnalyzer = "standard"),
otherFields = @NestedField(dotSuffix = "autoComplete", type = FieldType.String, searchAnalyzer = "standard", indexAnalyzer = "type_ahead"))
private String firstName;
对于我使用多重匹配的查询,我首先指定“firstName.autoComplete”,而不仅仅是“firstName”
QueryBuilders.multiMatchQuery(searchTerm, new String[]{"firstName.autoComplete", "firstName"})
这似乎工作正常。
在您的情况下,如果您需要完全匹配,也许您可以只使用“标准”而不是“edgeNGram”。