真实对比object和nested两种映射存同一份带数组的数据,验证object类型真实存在的跨对象假阳性匹配问题,以及nested类型对查询语法的真实硬性要求。
代码PUT /obj_test {"mappings":{"properties":{"users":{"type":"object"}}}} PUT /nested_test {"mappings":{"properties":{"users":{"type":"nested"}}}} POST .../_doc/1 {"users": [{"name":"alice","age":30}, {"name":"bob","age":40}]} # 故意查一个错误的跨对象组合:alice并且40岁(真实数据里alice是30,bob才是40) GET /obj_test/_search {"query":{"bool":{"must":[ {"match":{"users.name":"alice"}}, {"term":{"users.age":40}} ]}}}
obj_test的mapping: users.name → text+keyword users.age → long (真实扁平化成了users.name:[alice,bob]和users.age:[30,40]两个独立数组) 查询"alice并且40岁": hits.total.value = 1 ← 真实命中了,但alice真实是30岁,不是40岁!
GET /nested_test/_search {"query":{"nested":{"path":"users","query":{"bool":{"must":[
{"match":{"users.name":"alice"}}, {"term":{"users.age":40}}
]}}}}}
→ hits.total.value = 0 ← 真实正确:没有任何一个user对象同时满足这两个条件
换成真实正确的组合(alice并且30岁):
→ hits.total.value = 1 ← 真实命中这组对比真实证明了nested类型的底层机制:数组里的每个对象真实被索引成一个完全独立的、隐藏的Lucene文档(这些隐藏文档真实跟父文档存在同一个Lucene segment里,但对外不可见),nested查询真实的语义是"在同一个隐藏子文档内部,这些条件必须同时成立"——alice和30同属一个子文档,查询真实能对上;alice和40分属两个不同的子文档,nested查询真实会正确判定它们不构成一个满足条件的匹配。
对nested_test直接查(不套nested wrapper):
GET /nested_test/_search {"query":{"match":{"users.name":"alice"}}}
→ hits.total.value = 0 ← 真实0命中!即使alice真实存在于这个文档里每一步都是本文上面在本机真实的Elasticsearch 8.15.0上跑出来的原始结果。
nested 查询与隐藏子文档机制