Elasticsearch 7.8.1多条件组合模糊搜索无法命中匹配文档问题
查询失效原因
你的DSL返回不了预期结果,是几个写法错误叠加导致的:
- 用错了查询类型:
term查询是精确匹配倒排词条用的,完全不支持*通配符语法,你写的"p101*"会被当成完整字符串去匹配,根本不会触发模糊逻辑。 - 通配符逻辑不对:你写的
p101*只匹配以p101开头的内容,等价于SQL的like 'p101%',和你要的任意位置包含的%p101%逻辑不符。 - 字段匹配逻辑问题:Spring Data Elasticsearch默认对字符串类型做双字段映射:
text类型分词做全文检索,.keyword子字段不分词做精确匹配。你直接对text类型字段做精确类查询,会因为分词、大小写转换问题匹配失败。 - 样例数据本身不匹配:你贴的两条样例文档里,
dtcCode是D101(首字母大写D),其余subSystem、description、maintenanceActivity字段里也完全没有p101子串,搜p101本身就不会命中这两条数据,搜101才能匹配第二条记录。
另外你最开始写的SQL本身有逻辑优先级bug:and运算优先级高于or,不加括号的话实际逻辑是(vinNumber = "xyz" and organizationId = 1 and dtcCode like %p101%) or subSystem like %p101% or description like %p101%,会返回不匹配vin和组织的数据,写DSL的时候要注意规避。
正确写法
根据你的数据量规模选对应方案即可:
方案1:小数据量场景(百万级以下),无需改索引
直接用wildcard通配符查询,关键词前后都加*实现任意位置匹配,开启大小写不敏感参数,用.keyword子字段匹配避免分词干扰:
GET /maintenance_logs/_search { "query": { "bool": { "must": [ {"term": {"vinNumber.keyword": "DH34ASD7SDFF84742"}}, {"term": {"organizationId": 1}} ], "should": [ {"wildcard": {"dtcCode.keyword": {"value": "*p101*", "case_insensitive": true}}}, {"wildcard": {"subSystem.keyword": {"value": "*p101*", "case_insensitive": true}}}, {"wildcard": {"maintenanceActivity.keyword": {"value": "*p101*", "case_insensitive": true}}}, {"wildcard": {"description.keyword": {"value": "*p101*", "case_insensitive": true}}} ], "minimum_should_match": 1 } } }
注意:前置*的通配符查询需要遍历全量倒排词条,数据量过大会有明显性能问题,不适合生产大数据量场景。
方案2:生产大数据量场景,改索引配置优化性能
如果数据量在百万级以上,不要用前置通配符查询,提前给需要模糊匹配的字段配置N-Gram分词器,在写入时就把文本拆成固定长度的短子串,查询时直接用普通match即可,性能和精确查询一致:
- 新建索引配置分词和映射
PUT /maintenance_logs_v2 { "settings": { "analysis": { "tokenizer": { "ngram_tokenizer": { "type": "ngram", "min_gram": 3, "max_gram": 10, "token_chars": ["letter", "digit"] } }, "analyzer": { "ngram_analyzer": { "tokenizer": "ngram_tokenizer", "filter": ["lowercase"] } } } }, "mappings": { "properties": { "vinNumber": {"type": "keyword"}, "organizationId": {"type": "integer"}, "dtcCode": {"type": "text", "analyzer": "ngram_analyzer"}, "subSystem": {"type": "text", "analyzer": "ngram_analyzer"}, "maintenanceActivity": {"type": "text", "analyzer": "ngram_analyzer"}, "description": {"type": "text", "analyzer": "ngram_analyzer"}, "odometer": {"type": "integer"}, "statsDate": {"type": "date"} } } }
- 用reindex接口把旧索引数据迁移到新索引后,用如下DSL查询即可,自动支持任意位置子串匹配、大小写不敏感:
GET /maintenance_logs_v2/_search { "query": { "bool": { "must": [ {"term": {"vinNumber": "DH34ASD7SDFF84742"}}, {"term": {"organizationId": 1}} ], "should": [ {"match": {"dtcCode": "p101"}}, {"match": {"subSystem": "p101"}}, {"match": {"maintenanceActivity": "p101"}}, {"match": {"description": "p101"}} ], "minimum_should_match": 1 } } }
内容的提问来源于stack exchange,提问作者Tuhin Subhra Mandal
相关产品推荐
相关产品推荐

