在搜索结果中使用ngram过滤器时,我可以优先考虑更精确的匹配吗?

时间:2013-06-29 20:13:31

标签: elasticsearch

当使用带有elasticsearch的ngram过滤器时,当我搜索“test”之类的东西时,我返回一个文档“latest”,“tests”和“test”。是否有一种方法可以使“完全匹配查询”测试的“文档”总是在搜索结果中返回更高的位置?

3 个答案:

答案 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"
          }
        }]
      }
    }
  };
}