ElasticSearch 2.3.5多搜索查询无结果问题求助
嘿,我来帮你捋捋这个问题~ 你遇到的情况核心原因大概率是分词器的行为和查询参数的组合导致的,咱们一步步拆解:
为什么带"b"就查不到?
首先,Elasticsearch 2.3.5默认的standard分词器会把118b拆成两个独立的token:118和b。而你的查询用了operator: "and",意味着cross_fields模式下,所有拆分出来的token都需要在指定的字段集合中找到匹配。
当你去掉"b"只查118时,分词后只有118这一个token,它能匹配目标文档中*hasStreetNumber字段里的118(因为该字段的118b也会被拆出118),所以能命中。但加上"b"后,b这个token在其他字段(比如姓名、街道名、邮编这些)里大概率不存在,导致整个查询的and条件不满足,自然就没结果了。
具体解决方案
1. 检查并调整*hasStreetNumber字段的分词设置
如果*hasStreetNumber字段是用来存储精确的门牌号(比如118b这种格式),那它应该被设置为不分词(在ES2.3.5里是"index": "not_analyzed"),这样存储的118b会作为一个完整的token保留,查询时也能精确匹配。
你可以通过以下命令查看字段的映射:
GET /your_index/_mapping/your_type
如果发现该字段是analyzed(默认),可以修改映射(注意需要重建索引,因为ES不能直接修改已有字段的映射):
PUT /your_new_index { "mappings": { "your_type": { "properties": { "hasStreetNumber": { "type": "string", "index": "not_analyzed" } // 其他字段的映射... } } } }
然后把旧索引的数据迁移到新索引即可。
2. 调整查询语句,单独处理门牌号字段
如果暂时不想改映射,可以把查询拆成bool组合,让门牌号字段用精确匹配逻辑,其他字段保留原来的cross_fields查询:
{ "query": { "bool": { "must": [ { "multi_match": { "type": "cross_fields", "query": "John Schmidt Sankt Boulevard 2554 Island", "minimum_should_match": "50%", "operator": "and", "fields": ["*Name", "*Street.*hasStringValue", "*hasPostCode", "*PostalLocality.*hasStringValue"] } }, { "match": { "*hasStreetNumber": { "query": "118b", "operator": "and", "analyzer": "keyword" // 强制用keyword分词器,不分词 } } } ] } } }
如果字段已经是not_analyzed类型,还可以直接用term查询:
{ "query": { "bool": { "must": [ // 原cross_fields查询部分 { "term": { "*hasStreetNumber": "118b" } } ] } } }
3. 测试分词结果验证问题
你可以用ES的_analyze API查看分词情况,确认是不是分词导致的问题:
GET /your_index/_analyze?analyzer=standard&text=118b
返回的结果会显示拆分后的token,这样就能直观看到118b被拆成了118和b,这就是问题的根源。
内容的提问来源于stack exchange,提问作者JohnJackson

