当使用带有elasticsearch的ngram过滤器时,当我搜索“test”之类的东西时,我返回一个文档“latest”,“tests”和“test”。是否有一种方法可以使“完全匹配查询”测试的“文档”总是在搜索结果中返回更高的位置?
答案 0 :(得分:6)
这对ngrams来说有点问题:你的排名会得到很多误报。解决方案是将ngrams与带状疱疹相结合。基本上除了ngram之外,您还可以将完整单词索引为单独的术语或甚至是单词的组合。带状疱疹基本上就像是ngrams,但是用文字而不是字符。
这样,与瓦片术语的精确匹配得分高于只匹配ngrams的东西。
<强>更新即可。以下是自定义分析器的示例。定义它之后,您可以在映射中使用它。在这种情况下,我使用icu_normalizer和折叠以及我的suggestions_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
}
}
}
答案 1 :(得分:0)
您需要多字段和多匹配查询。
我有类似的问题。我需要按名字搜索,所以如果我把搜索词“And”,我首先得到'Andy',而不是'Mandy'。只有nGram,我无法实现这一目标。
我添加了一个使用前端NGGram的分析器(下面的代码用于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;
对于我使用multimatch的查询,我首先指定'firstName.autoComplete',而不只是'firstName'
QueryBuilders.multiMatchQuery(searchTerm, new String[]{"firstName.autoComplete", "firstName"})
这似乎运作正常。
在你的情况下,如果你需要完全匹配,也许你可以使用'edgeNGram'代替'edgeNGram'。
答案 2 :(得分:0)
您可以通过映射将字段内容复制到字段。例如:
"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"
}
}]
}
}
};
}