nested类型是专门为支持数组对象索引的数据类型服务的,在某种程度上可以相互独立查询。
tip:当接收大量的键值对或者key的类型比较分散,你可以考虑为每个key-value建立自己的nested类型的document。相反,也可以考虑使用flattened数据类型,这种数据类型可以将整个对象映射为单个字段,并且可以在其content上进行一些简单的搜索。
对象数组是如何打平的
Elasticsearch并没有内部对象的概念。因此,它将对象的层次打平为一个简单的name-value的列表。例如,如下的文档:
PUT my-index-000001/_doc/1{"group" : "fans","user" : [ ①{"first" : "John","last" : "Smith"},{"first" : "Alice","last" : "White"}]}
①:user是字段作为object字段类型动态添加的。
在系统内部以前的文档会转换为类似下面的数据结构:
{"group" : "fans","user.first" : [ "alice", "john" ],"user.last" : [ "smith", "white" ]}
user.first和user.last字段会被打平为数组字段,并且会丢失alice和white之间的关系。这个文档就会错误的匹配到alice 和 smith的查询:
GET my-index-000001/_search{"query": {"bool": {"must": [{ "match": { "user.first": "Alice" }},{ "match": { "user.last": "Smith" }}]}}}
对数组类型的对象使用nested类型
如果你需要索引对象数组并且保持数组中每个对象独立,使用nested来代替object数据类型。
在内部,nested对象会将数组中的每个对象作为单独的隐藏的文档来索引,意味着每个nested对象可以使用nested独立查询:
PUT my-index-000001{"mappings": {"properties": {"user": {"type": "nested" ①}}}}PUT my-index-000001/_doc/1{"group" : "fans","user" : [{"first" : "John","last" : "Smith"},{"first" : "Alice","last" : "White"}]}GET my-index-000001/_search{"query": {"nested": {"path": "user","query": {"bool": {"must": [{ "match": { "user.first": "Alice" }},{ "match": { "user.last": "Smith" }} ②]}}}}}GET my-index-000001/_search{"query": {"nested": {"path": "user","query": {"bool": {"must": [{ "match": { "user.first": "Alice" }},{ "match": { "user.last": "White" }} ③]}},"inner_hits": { ④"highlight": {"fields": {"user.first": {}}}}}}}
①:user字段映射为nested类型而不是object类型
②:此查询不会匹配任何数据,应为alice和smith没有在同一个nested对象中。
③:此查询会匹配到数据,因为alice和white在同一个nested对象中。
④:inner_hits允许我们高亮匹配的nested文档。
与nested文档交互
nested文档可以:
- 使用nested查询。
- 使用nested分析和reverse_nested聚合。
- nested sorting排序。
- 检索和高亮。
重要:因为nested是被分开索引的,因此他们只能被nsted query、ested/reverse_nested aggregations, or nested inner hits查询到。
例如,nested文档内的字符串字段,index_options设为offsets,使得在高亮时允许use of the postings。这些offsets在主要的高亮阶段将不可用。反而,高亮需要通过nested inner hits来执行。同样的考虑也使用当在搜索中通过docvalue_fields 或者 stored_fields加载字段时。
