Elasticsearch如何实现大小写敏感的term查询?
问题原因分析
你遇到的这个问题其实是Elasticsearch默认的字段处理逻辑导致的——你的unit字段大概率被映射成了text类型,而ES默认的standard分词器会自动把所有字母转成小写,同时做分词处理。所以当你存入"kWh"的时候,实际被索引的内容是"kwh",这就导致你用term查询"kWh"时找不到结果,查"kwh"却能匹配到。
虽然term查询本身是大小写敏感的,但它匹配的是倒排索引里已经处理过的分词结果,而不是你存入的原始文本,这就是关键矛盾点。
解决方案
因为你需要精确匹配且不想用match,这里给你几个可行的方案:
方案1:将unit字段设置为keyword类型
keyword类型的字段不会被分词,会完整存储原始文本,天生支持精确匹配。如果你的索引还没创建,或者可以重新创建索引的话,先定义映射:
curl -X PUT "localhost:9200/my_index" -H 'Content-Type: application/json' -d'{ "mappings": { "my_type": { "properties": { "point_name": {"type": "text"}, "unit": {"type": "keyword"} } } } }'
然后重新存入文档,之后用term查询"kWh"就能精准匹配到了。
方案2:给text类型的unit字段添加keyword子字段
如果不想重建索引(ES6.2.4支持动态添加子字段),可以给已有的unit字段添加一个keyword子字段:
curl -X PUT "localhost:9200/my_index/_mapping/my_type" -H 'Content-Type: application/json' -d'{ "properties": { "unit": { "type": "text", "fields": { "raw": {"type": "keyword"} } } } }'
添加后需要重新索引数据(可以用_reindex API),之后查询的时候指定子字段:
curl -X GET "localhost:9200/my_index/my_type/_search" -H 'Content-Type: application/json' -d'{ "query": { "bool": { "must": [{"term": {"unit.raw": "kWh"}}] } } }'
方案3:修改unit字段的分词器为大小写敏感的
如果一定要用text类型且保留分词,但需要大小写敏感,可以自定义一个不转小写的分词器,比如:
curl -X PUT "localhost:9200/my_index" -H 'Content-Type: application/json' -d'{ "settings": { "analysis": { "analyzer": { "case_sensitive_analyzer": { "tokenizer": "standard", "filter": [] // 移除默认的lowercase过滤器,保留原始大小写 } } } }, "mappings": { "my_type": { "properties": { "unit": {"type": "text", "analyzer": "case_sensitive_analyzer"} } } } }'
不过这种方案适合需要分词但又要保留大小写的场景,对于unit这种短文本的精确匹配需求,前两种方案更合适。
总结
核心问题就是默认text字段的分词处理改变了原始文本的大小写,导致term查询的目标值和索引里的内容不匹配。选择keyword类型或其子字段是最直接满足精确匹配需求的方式,也能和你其他字段的查询逻辑兼容。
内容的提问来源于stack exchange,提问作者Stoecki
相关产品推荐
相关产品推荐

