Elasticsearch EdgeNGram copy_to字段部分搜索失效求助
我来帮你捋清楚这个问题哈!
问题根源
你遇到的核心问题,出在edgeNGram过滤器的特性上:它是前缀分词器,只会从每个单词的第一个字符开始生成连续的子串。就像你贴的分析结果里显示的那样,"PowerEdge"被拆成了p、po、pow...一直到poweredge,但完全不会生成edge这种从单词中间位置开始的子串。所以当你查询"edge"时,索引里根本没有对应的token,自然查不到结果。
解决方案
根据你的需求,有两种常见的处理方式:
场景1:需要支持任意子串匹配(比如查"edge"、"owe"都能返回结果)
把过滤器类型从edgeNGram改成普通的ngram,这样过滤器会生成所有可能的连续子串,包括单词中间的部分。修改后的完整映射如下:
{ "settings": { "analysis": { "filter": { "myNGramFilter": { "type": "ngram", // 这里改为普通ngram类型 "min_gram": 1, "max_gram": 40 } }, "analyzer": { "myNGramAnalyzer": { "type": "custom", "tokenizer": "standard", "filter": ["lowercase", "myNGramFilter"] } } } }, "mappings": { "test": { "properties": { "catch_all": { "type": "text", "fields": { "keyword": { "type": "keyword", "store": true, "ignore_above": 256 }, "grams": { "type": "text", "store": true, "analyzer": "myNGramAnalyzer" } } }, "hostname": { "type": "text", "copy_to": "catch_all" } } } } }
修改后需要重新创建索引并导入数据(Elasticsearch无法修改已存在字段的分析器配置),再用_analyze测试,你会看到"PowerEdge"会生成包括edge在内的所有连续子串,这时查询"edge"就能得到预期结果了。
场景2:既要保留前缀匹配的性能,又要偶尔支持中间子串查询
如果你的大部分查询都是前缀匹配(比如查"pow"、"dell"),只有少数场景需要查中间子串,可以给catch_all新增一个字段,单独使用普通ngram分析器:
{ "settings": { "analysis": { "filter": { "myEdgeNGramFilter": { "type": "edgeNGram", "min_gram": 1, "max_gram": 40 }, "myFullNGramFilter": { "type": "ngram", "min_gram": 1, "max_gram": 40 } }, "analyzer": { "myEdgeNGramAnalyzer": { "type": "custom", "tokenizer": "standard", "filter": ["lowercase", "myEdgeNGramFilter"] }, "myFullNGramAnalyzer": { "type": "custom", "tokenizer": "standard", "filter": ["lowercase", "myFullNGramFilter"] } } } }, "mappings": { "test": { "properties": { "catch_all": { "type": "text", "fields": { "keyword": { "type": "keyword", "store": true, "ignore_above": 256 }, "prefix_grams": { "type": "text", "store": true, "analyzer": "myEdgeNGramAnalyzer" // 保留前缀分词用于常规查询 }, "full_grams": { "type": "text", "store": true, "analyzer": "myFullNGramAnalyzer" // 新增全量分词用于中间子串查询 } } }, "hostname": { "type": "text", "copy_to": "catch_all" } } } } }
这样平时用catch_all.prefix_grams做前缀查询(性能更好),需要查中间子串时用catch_all.full_grams查询,兼顾性能和需求。
内容的提问来源于stack exchange,提问作者Tech_Lover
相关产品推荐
相关产品推荐

