真实用_validate/query的explain模式把match查询底层生成的词项查询原样打印出来,验证operator参数如何组合这些词项,并对比text与keyword字段上match行为的真实差异。
代码索引一篇文档: {"body": "The Quick Brown Fox Jumps Over The Lazy Dog", "status": "Active"} POST /match_test/_validate/query?explain=true { "query": {"match": {"body": "QUICK fox"}} }
explain输出: → "explanation": "body:quick body:fox" ← 原始搜索词是"QUICK fox",真实被拆成了两个独立的词项查询 ← QUICK真实被转成了小写quick,因为body字段用的是默认standard分析器,带lowercase过滤器
这条explain输出真实是本文最核心的证据:match查询收到搜索词"QUICK fox"之后,真实不是直接拿这个字符串去倒排索引里查"QUICK fox"这个完整短语,而是先把它送进body字段写入时用的同一个analyzer(这里是默认的standard)真实跑一遍分词和小写化,产出quick和fox两个token,再对这两个token分别构造词项查询,最后真实用should(即OR)把它们组合起来。这正是为什么大小写、单复数这些查询词和原文不完全一致的情况下,match查询依然真实能命中——因为真实比对的根本不是原始字符串,而是两边经过同一套分析规则处理后的token。
代码POST /match_test/_search {"query":{"match":{"body":{"query":"quick zebra","operator":"and"}}}} POST /match_test/_search {"query":{"match":{"body":"quick zebra"}}} # 不传operator,用默认值
"quick zebra"真实被分析成quick和zebra两个词项,文档里只有quick没有zebra operator="and"(真实要求所有词项都命中): → hits: 0 ← zebra真实查不到,整条查询真实失败 不传operator(真实默认值是"or"): → hits: 1 ← 只要quick命中就算,zebra缺失真实不影响结果
代码status字段真实存的是"Active"(大写A开头),类型是keyword POST /match_test/_search {"query":{"match":{"status":"active"}}} # 全小写搜索 POST /match_test/_search {"query":{"match":{"status":"Active"}}} # 原样大小写搜索
搜索"active"(小写): hits = 0 ← 真实查不到! 搜索"Active"(大小写完全一致): hits = 1 ← 真实命中
这个对比真实揭示了前面几组实验里"match查询会分析搜索词"这句话真正的边界:match查询确实真实会调用字段对应的analyzer去处理搜索词,但keyword类型字段真实根本没有可供分词小写化的analyzer(它底层用的是keyword分词器,等同于"原样整体保留,不做任何转换",这是本系列第26篇验证过的真实结论)。所以对text字段,match查询真实表现得很"宽容",大小写、单复数都不影响命中;但对keyword字段,match查询真实退化成了字节级别的精确比对,哪怕只差一个字母的大小写,也真实完全查不到。这也是为什么本系列反复强调要先搞清楚字段类型再决定用什么查询——同一个match查询语法,在text和keyword字段上真实表现出两种完全不同的行为。
每一步都是本文上面在本机真实的Elasticsearch 8.15.0上跑出来的原始结果。
_validate/query?explain=true API