如何构建支持模糊匹配与通配符的多字段Elasticsearch查询
实现支持模糊匹配与通配符的多字段Elasticsearch查询
你需要同时支持模糊匹配和子串(通配符)匹配的多字段查询,可以通过以下几种方式实现:
方式一:Bool查询组合Match与Wildcard
为每个目标字段同时添加模糊匹配(match)和通配符匹配(wildcard),通过bool的should逻辑让两种匹配规则并行生效:
GET /document/_search { "query": { "bool": { "should": [ // addressRange字段:模糊匹配(允许1次编辑距离) { "match": { "addressRange": { "_name": "addressRange_fuzzy", "operator": "or", "query": "ogsroa", "fuzziness": 1 } } }, // addressRange字段:通配符子串匹配 { "wildcard": { "addressRange": { "_name": "addressRange_wildcard", "value": "*ogsroa*" } } }, // documentNumber字段:模糊匹配(不允许编辑距离) { "match": { "documentNumber": { "_name": "documentNumber_fuzzy", "operator": "or", "query": "ogsroa", "fuzziness": 0 } } }, // documentNumber字段:通配符子串匹配 { "wildcard": { "documentNumber": { "_name": "documentNumber_wildcard", "value": "*ogsroa*" } } } ], "minimum_should_match": 1 } } }
说明
minimum_should_match:1确保至少有一个匹配规则命中就返回文档(默认值也是1,显式声明更清晰)- 通配符
*ogsroa*会匹配任意包含该子串的内容,但如果通配符以*开头,会触发全索引扫描,数据量大时性能较差
方式二:使用Query String简化写法
Query String支持在查询语句中直接整合通配符和模糊匹配语法,同时指定多字段查询,写法更简洁:
统一模糊规则的版本
GET /document/_search { "query": { "query_string": { "fields": ["addressRange", "documentNumber"], "query": "*ogsroa*~1", "_name": "multi_field_fuzzy_wildcard", "default_operator": "or" } } }
区分字段模糊规则的版本
如果documentNumber不需要模糊匹配,可拆分查询逻辑:
GET /document/_search { "query": { "query_string": { "query": "(addressRange:*ogsroa*~1) OR (documentNumber:*ogsroa*)", "_name": "multi_field_custom_fuzzy_wildcard", "default_operator": "or" } } }
说明
*ogsroa*表示匹配包含该子串的内容~1表示允许1次编辑距离的模糊匹配,documentNumber部分去掉~则禁用模糊- 同样要注意前缀
*带来的性能问题
方式三:使用NGram分词优化性能(推荐)
如果业务允许提前调整索引结构,使用NGram分词器可以从根本上解决子串匹配的性能问题,同时兼容模糊匹配:
1. 创建带NGram分词的索引
PUT /document { "settings": { "analysis": { "analyzer": { "ngram_analyzer": { "tokenizer": "ngram_tokenizer" } }, "tokenizer": { "ngram_tokenizer": { "type": "ngram", "min_gram": 3, "max_gram": 10 } } } }, "mappings": { "properties": { "addressRange": { "type": "text", "analyzer": "ngram_analyzer", "search_analyzer": "standard" }, "documentNumber": { "type": "text", "analyzer": "ngram_analyzer", "search_analyzer": "standard" } } } }
2. 执行Match查询(同时支持子串和模糊)
GET /document/_search { "query": { "bool": { "should": [ { "match": { "addressRange": { "_name": "addressRange", "operator": "or", "query": "ogsroa", "fuzziness": 1 } } }, { "match": { "documentNumber": { "_name": "documentNumber", "operator": "or", "query": "ogsroa", "fuzziness": 0 } } } ] } } }
说明
- NGram分词会将字段内容拆分为多个长度3-10的子串,比如"Frogsroad"会被拆分为"Fro"、"rog"、"ogs"等
- 搜索"ogsroa"时,Match查询会直接匹配分词后的子串,无需通配符,性能远高于Wildcard查询
- 同时保留
fuzziness参数,依然支持模糊匹配
内容的提问来源于stack exchange,提问作者Teije
相关产品推荐
相关产品推荐

