为什么我的 Elasticsearch 多匹配查询只查找前缀?

Why does my Elasticsearch multi-match query look only for prefixes?

我正在尝试编写一个 Elasticsearch 多匹配查询(使用 Java API)来创建一个 "search-as-you-type" 程序。查询应用于两个字段,titledescription,它们被分析为 ngrams。

我的问题是,Elasticsearch 似乎只尝试查找像我的查询一样的单词 beginning。例如,如果我搜索 "nut",那么它会匹配包含“nut”、“nuts”、“Nutella”等,但它不匹配带有“walnut”的文档,应该匹配。

这是我的设置:

{
    "index": {
        "analysis": {
            "analyzer": {
                "edgeNGramAnalyzer": {
                    "tokenizer": "edgeTokenizer",
                    "filter": [
                        "word_delimiter",
                        "lowercase",
                        "unique"
                    ]
                }
            },
            "tokenizer": {
                "edgeTokenizer": {
                  "type": "edgeNGram",
                  "min_gram": "3",
                  "max_gram": "8",
                  "token_chars": [
                    "letter",
                    "digit"
                  ]
                }
            }
        }
    }
}

这是我映射的相关部分:

{
    "content": {
        "properties": {
            "title": {
                "type": "text",
                "analyzer": "edgeNGramAnalyzer",
                "fields": {
                    "sort": { 
                        "type": "keyword"
                    }
                }
            },
            "description": {
                "type": "text",
                "analyzer": "edgeNGramAnalyzer",
                "fields": {
                    "sort": { 
                        "type": "keyword"
                    }
                }
            }
        }
    }
}

这是我的查询:

new MultiMatchQueryBuilder(query).field("title", 3).field("description", 1).fuzziness(0).tieBreaker(1).minimumShouldMatch("100%")

你知道我做错了什么吗?

那是因为您使用的是 edgeNGram tokenizer instead of nGram。前者仅索引前缀,而后者将索引前缀、后缀以及数据的子部分。

将您的分析器定义更改为此,它应该会按预期工作:

{
    "index": {
        "analysis": {
            "analyzer": {
                "edgeNGramAnalyzer": {
                    "tokenizer": "edgeTokenizer",
                    "filter": [
                        "word_delimiter",
                        "lowercase",
                        "unique"
                    ]
                }
            },
            "tokenizer": {
                "edgeTokenizer": {
                  "type": "nGram",         <---- change this
                  "min_gram": "3",
                  "max_gram": "8",
                  "token_chars": [
                    "letter",
                    "digit"
                  ]
                }
            }
        }
    }
}