bigywater.tech
Elasticsearch · 30

term 查询为什么不分词

真实用explain模式对比term查询与match查询底层生成语句的差异,验证term查询跳过analyzer直接比对原始字符串的机制,以及这在text字段和keyword字段上截然不同的真实后果。

explain对比
真实证明term查询跳过了analyzer分析环节
text字段上term搜大写
真实0命中,索引词项已被转成小写
keyword字段上term
真实是设计初衷,精确比对存储值

做的事:真实用explain模式对比term查询跟上一篇match查询底层生成语句的差异

代码同一篇文档: {"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查询真实把"Quick"原样当成词项去查,大写Q一个字母都没被转换

实测 · 本机 Elasticsearch 8.15.0 执行输出
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真实原封不动地去跟这些小写词项做比对——两者字节不完全一致,必然查不到。

真实验证后果:term搜大写"Quick"查不到,必须搜索引里真实存的小写"quick"

代码POST /match_test/_search {"query":{"term":{"body":"Quick"}}} # 大写 POST /match_test/_search {"query":{"term":{"body":"quick"}}} # 小写

验证:大写"Quick"真实0命中,小写"quick"真实命中1条——跟索引里实际词项完全一致才行

实测 · 本机执行输出
term搜索"Quick"(大写,跟原文拼写一致): hits = 0   ← 真实查不到!
term搜索"quick"(小写,跟索引里的token一致): hits = 1   ← 真实命中
这是新手最容易踩的坑:直觉上"Quick"明明就是原文里出现的词,为什么term查询搜不到?真实原因是term查询比对的对象根本不是"原文里出现过的词",而是"索引里真实存储的词项"——这篇文档写入时真实已经被standard分析器转成小写存进了倒排索引,原文里的大写"Quick"这个字符串本身真实已经不存在于索引里了。这也是为什么官方文档反复强调:term查询只应该用在keyword这类不经过分析、原样存储的字段上;用在text字段上几乎总是真实的误用,因为你永远没法确定analyzer到底把原文转换成了什么样子,除非像本文这样真实用_analyze或explain去验证。

真实验证term查询在keyword字段上才是设计初衷:完全原样比对

代码status字段真实存的是keyword类型"Active" POST /match_test/_search {"query":{"term":{"status":"Active"}}} # 大小写完全一致 POST /match_test/_search {"query":{"term":{"status":"active"}}} # 小写

验证:keyword字段上term查询真实表现稳定,跟原样存的值完全一致才命中

实测 · 本机执行输出
term搜索"Active"(跟存储值完全一致): hits = 1   ← 真实命中
term搜索"active"(小写,跟存储值大小写不一致): hits = 0   ← 真实查不到

这组结果真实跟前面body字段上的行为看起来很像(都是大小写敏感),但背后的原因完全不同:status字段是keyword类型,写入时真实没有做任何转换(上一篇验证过keyword字段底层用的是keyword分词器,整个值原样存成一个token),所以索引里存的就是"Active"本身,一个字母都没变过。term查询在这种"写入时不转换"的字段上,才真实是它被设计出来该用的场景:你查询时传什么,就真实精确比对索引里存的是不是一模一样的值,没有任何中间的分析环节可能悄悄改变你的查询词——这正是term查询名字里"term"(词项)的真实含义:直接比对词项本身,不经过任何加工。

分步演示:term查询从跳过分析的底层机制到正确使用场景的完整验证

每一步都是本文上面在本机真实的Elasticsearch 8.15.0上跑出来的原始结果。

term查询真实跳过分析环节,直接比对原始字符串与索引词项
这一步新验证的查询行为

    本文用到的工具

    • 本机真实部署的 Elasticsearch 8.15.0(单节点,tar包直接启动)
    • 真实的 _validate/query?explain=true API
    京ICP备2026067502号-1京公网安备11010502063487号