ElasticSearch query_string查询r@hot未获预期结果的问题
问题:ElasticSearch email字段模糊查询异常解决
已索引的企业数据
[ { "_index": "test_company", "_type": "_doc", "_id": "9303000d-b167-4d7c-b233-43a43c4a7e60", "_score": 2.4849067, "_source": { "id": "9303000d-b167-4d7c-b233-43a43c4a7e60", "name": "My Property Company", "phone": "11484473106", "email": "johnie.schinner@hotmail.com", "website": "https://www.walmart.com", "ein": "731087415", "address": "Apt. 837 5371 Carroll Estates, Zboncakbury, LA 53957-3670", "zip": "99950", "city": "Ketchikan", "state": "Alaska", "country": "US", "fileId": "", "status": "Active" } }, { "_index": "test_company", "_type": "_doc", "_id": "f302ef6a-f259-4980-ad1e-48de33e34799", "_score": 1.8173966, "_source": { "byPhone": "byPhone", "website": "https://www.walmart.com", "zip": "99950", "status": "Active", "ein": "427297769", "createdAt": "2022-11-11T04:39:50.717Z", "isDeleted": false, "address": "056 Robin Island, Arliefurt, MA 28632-8802", "byName": "byName", "email": "nathanael.marks@hotmail.com", "country": "US", "name": "Walmart", "state": "Alaska", "city": "Ketchikan", "byCreatedAt": "byCreatedAt", "fileId": "9b705ead-df91-424c-bad9-ccf1db477f3c", "updatedAt": "2022-11-11T05:49:02.759Z", "byEmail": "byEmail", "id": "f302ef6a-f259-4980-ad1e-48de33e34799", "phone": "14844731064" } }, { "_index": "test_company", "_type": "_doc", "_id": "270c1a72-0f54-4004-8efc-70fd3adc0b3d", "_score": 1.8173966, "_source": { "id": "270c1a72-0f54-4004-8efc-70fd3adc0b3d", "name": "Walmart", "phone": "14844731064", "email": "nick.hyatt@hotmail.com", "website": "https://www.walmart.com", "ein": "058107938", "address": "0440 Neville Camp, Schinnerbury, AK 30194-5833", "zip": "99950", "city": "Ketchikan", "state": "Alaska", "country": "US", "fileId": "", "status": "Active" } }, { "_index": "test_company", "_type": "_doc", "_id": "b695acb2-980a-459d-88d8-e16fc47eead8", "_score": 1.5686159, "_source": { "id": "b695acb2-980a-459d-88d8-e16fc47eead8", "name": "My Property Company", "phone": "14844731064", "email": "kristofer.larkin@hotmail.com", "website": "https://www.walmart.com", "ein": "040723577", "address": "20361 Veum Overpass, Erniechester, ID 19244", "zip": "99950", "city": "Ketchikan", "state": "Alaska", "country": "US", "fileId": "", "status": "Active" } } ]
查询需求
需要在email字段中搜索包含字符串r@hot的记录,期望仅返回第一条数据(邮箱为johnie.schinner@hotmail.com的条目)。
已尝试的查询及结果
尝试1
{ "query": { "bool": { "must": [ {"query_string": { "query": "r@hot*", "fields": ["email"], "analyze_wildcard": true }} ] } } }
结果:返回全部4条数据
尝试2
{ "query": { "bool": { "must": [ {"query_string": { "query": "*r@hot*", "fields": ["email"], "analyze_wildcard": true }} ] } } }
结果:无任何数据返回
问题原因
默认情况下,email字段如果是text类型,会使用标准分词器处理,它会把邮箱拆分成多个独立词汇(比如johnie、schinner、hotmail、com),同时会忽略@这类特殊符号。
- 尝试1的查询
r@hot*被分词后,实际变成搜索包含r或者hot*的词汇,而所有邮箱都包含hotmail,因此全部命中。 - 尝试2的查询
*r@hot*,因为索引中不存在包含r@hot的完整词汇,所以无法匹配到任何结果。
解决方案
方案1:使用字段的keyword子字段查询(无需修改映射)
如果你的email字段在映射中配置了keyword子字段(ElasticSearch默认会给text字段自动生成),可以直接针对email.keyword做模糊查询,这个子字段会存储邮箱的完整字符串:
用wildcard查询
{ "query": { "wildcard": { "email.keyword": "*r@hot*" } } }
用query_string查询
{ "query": { "query_string": { "query": "*r@hot*", "fields": ["email.keyword"], "analyze_wildcard": true } } }
方案2:使用regexp查询(适用于无keyword子字段的情况)
如果没有keyword子字段,可以用正则表达式查询,直接匹配原始文本中的字符串模式:
{ "query": { "regexp": { "email": ".*r@hot.*" } } }
注意:这种方式性能略低,因为需要扫描更多索引条目,数据量大时不推荐。
方案3:修改字段映射(长期最优方案)
如果经常需要对邮箱做精确模糊查询,建议修改email字段的映射,同时保留text和keyword类型,兼顾全文搜索和精确匹配需求:
{ "mappings": { "properties": { "email": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } } } } }
修改映射后需要重新索引数据,之后就可以用email.keyword高效做各种模糊匹配查询。
内容的提问来源于stack exchange,提问作者BivorAdrito
相关产品推荐
相关产品推荐

