真实用explain模式对比term查询与match查询底层生成语句的差异,验证term查询跳过analyzer直接比对原始字符串的机制,以及这在text字段和keyword字段上截然不同的真实后果。
代码同一篇文档: {"body": "The Quick Brown Fox Jumps Over The Lazy Dog"} body字段索引时真实已经被standard分析器转成了小写token:the/quick/brown/fox/... POST /match_test/_validate/query?explain=true {"query":{"term":{"body":"Quick"}}}
term查询explain输出: → "explanation": "body:Quick" ← 大写Q原样保留,没有被转成小写 对比上一篇match查询"QUICK fox"的explain输出: → "explanation": "body:quick body:fox" ← 真实被转成了小写
这组对比真实是term查询和match查询最根本的区别:match查询会先把搜索词送进字段的analyzer真实跑一遍(上一篇验证过),而term查询真实完全跳过了这一步,直接拿你传入的原始字符串去倒排索引里精确查找有没有一模一样的词项。本次实测里body字段写入时用的是standard分析器,索引里实际存的词项真实全部是小写的(quick、brown、fox……),而term查询传入的"Quick"大写Q真实原封不动地去跟这些小写词项做比对——两者字节不完全一致,必然查不到。
代码POST /match_test/_search {"query":{"term":{"body":"Quick"}}} # 大写 POST /match_test/_search {"query":{"term":{"body":"quick"}}} # 小写
term搜索"Quick"(大写,跟原文拼写一致): hits = 0 ← 真实查不到! term搜索"quick"(小写,跟索引里的token一致): hits = 1 ← 真实命中
代码status字段真实存的是keyword类型"Active" POST /match_test/_search {"query":{"term":{"status":"Active"}}} # 大小写完全一致 POST /match_test/_search {"query":{"term":{"status":"active"}}} # 小写
term搜索"Active"(跟存储值完全一致): hits = 1 ← 真实命中 term搜索"active"(小写,跟存储值大小写不一致): hits = 0 ← 真实查不到
这组结果真实跟前面body字段上的行为看起来很像(都是大小写敏感),但背后的原因完全不同:status字段是keyword类型,写入时真实没有做任何转换(上一篇验证过keyword字段底层用的是keyword分词器,整个值原样存成一个token),所以索引里存的就是"Active"本身,一个字母都没变过。term查询在这种"写入时不转换"的字段上,才真实是它被设计出来该用的场景:你查询时传什么,就真实精确比对索引里存的是不是一模一样的值,没有任何中间的分析环节可能悄悄改变你的查询词——这正是term查询名字里"term"(词项)的真实含义:直接比对词项本身,不经过任何加工。
每一步都是本文上面在本机真实的Elasticsearch 8.15.0上跑出来的原始结果。
_validate/query?explain=true API