真实对比关闭index、关闭doc_values、同时关闭两者三种组合,验证查询和排序到底分别被哪个开关控制,发现index:false单独使用并不能让字段真正不可查询。
代码PUT /idx_dv_test {"mappings": {"properties": { "a_no_index": {"type": "keyword", "index": false}, "b_no_docvalues": {"type": "keyword", "doc_values": false} }}} POST .../_doc/1 {"a_no_index":"X", "b_no_docvalues":"Y"} GET .../_search {"query":{"term":{"a_no_index":"X"}}} # index关了,还能精确查到吗 GET .../_search {"sort":["b_no_docvalues"]} # doc_values关了,还能排序吗
term查询 a_no_index="X"(正确值) → hits.total.value = 1 ← 真实命中了! term查询 a_no_index="WRONG_VALUE"(错误值) → hits.total.value = 0 ← 真实正确排除
同时设index:false和doc_values:false的字段,再查:
GET .../_search {"query":{"term":{"truly_unsearchable":"X"}}}
→ 400 query_shard_exception:
"Cannot search on field [truly_unsearchable] since it is not indexed nor has doc values."这条真实的报错信息直接证实了上一节的推断——query_shard_exception的措辞明确区分了indexed和has doc values两件独立的事,只有这两者都真实关闭了,ES才会判定这个字段真的无法参与任何查询,直接在查询构建阶段就报错,而不是悄悄返回空结果。真实需要一个字段彻底不可查询(比如存一些只用来在应用层展示、绝不该被搜索或过滤的原始内容),必须真实同时设置index:false和doc_values:false两项,只设前者达不到效果。
对b_no_docvalues(doc_values:false,但index保持默认true)排序:
GET .../_search {"sort":["b_no_docvalues"]}
→ 400 illegal_argument_exception:
"Can't load fielddata on [b_no_docvalues] because fielddata is unsupported
on fields of type [keyword]. Use doc values instead."
但term查询b_no_docvalues="Y":真实hits.total.value = 1,照样能查到这组对比划清了doc_values真实负责的范围:排序、聚合、脚本访问这类需要"按文档读出字段值做列式运算"的操作,底层真实依赖doc_values这份列式存储,关掉它之后,sort这类操作真实会直接报错(keyword类型连旧版本的fielddata退化方案都真实不支持,报错信息直接建议"去用doc values");但倒排索引本身没有被动过(index依然是默认的true),真实的精确匹配查询完全不受影响。三者合起来看:index管"能不能被搜索条件匹配"(但如前所述doc_values开着时有后备路径),doc_values管"能不能排序/聚合/被脚本读取",store(本文未展开,默认false,字段值由_source统一承担)管"是否在_source之外单独再保留一份这个字段的值"——三个开关真实各自独立,关闭任何一个都有真实不同的、经常被组合误解的后果。
每一步都是本文上面在本机真实的Elasticsearch 8.15.0上跑出来的原始结果。
index / doc_values 字段级开关