Elasticsearch之Nested Object

本文深入探讨了在Elasticsearch中使用Nested对象的原理与实践,阐述了其在存储相关实体和提高搜索性能方面的重要性,并详细解释了如何通过Nested对象解决跨对象匹配问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

                                 (这是一个小系列:请戳:ElasticsearchNested(嵌套)系列,查看其他nested相关文章)

   Given the fact that creating, deleting, and updating a single document in Elasticsearch is atomic, 

it makes sense to store closely related entities within the same document.

考虑到在ES里面建立,删除和更新一个单一文本是原子性的,那么将相关实体保存在同一个文本里面是有意义的。

PUT /my_index/blogpost/1
{
  "title":"Nest eggs",
  "body":  "Making your money work...",
  "tags":  [ "cash", "shares" ],
  "comments":[
     {
	  "name":    "John Smith",
      "comment": "Great article",
      "age":     28,
      "stars":   4,
      "date":    "2014-09-01"
	 },
	 {
      "name":    "Alice White",
      "comment": "More like this please",
      "age":     31,
      "stars":   5,
      "date":    "2014-10-22"
     }
  ]
}

Because all of the content is in the same document, there is no need to join blog posts and comments at query time, so searches perform well. 

因为所有的内容都在同一文本里面,在查询的时候就没有必要拼接blog posts,因此检索性能会更好。

The problem is that the preceding document would match a query like this: 

问题是,上面的文档会匹配这样的一个查询:

curl -XPGET 'localhost:9200/_search' -d '
{
  "query":{
     "bool":{
   "must":[
     {"match":{"name":"Alice"}},
     {"match":{"age":28}}
   ]
 }
  }
}'
但是Alice is 31,不是28啊!

The reason for this cross-object matching, as discussed in Arrays of Inner Objects, is that our beautifully structured JSON document is flattened into a simple key-value format in the index that looks like this:

造成这种交叉对象匹配是因为结构性的JSON文档会平整成索引内的一个简单键值格式,就像这样:

{
  "title":              [ eggs, nest ],
  "body":             [ making, money, work, your ],
  "tags":              [ cash, shares ],
  "comments.name":    [ alice, john, smith, white ],
  "comments.comment":  [ article, great, like, more, please, this ],
  "comments.age":      [ 28, 31 ],
  "comments.stars":     [ 4, 5 ],
  "comments.date":      [ 2014-09-01, 2014-10-22 ]
}

The correlation between Alice and 31, or between John and 2014-09-01, has been irretrievably lost. 

显然,像这种‘Alice/31’,‘john/’2014-09-01’间的关联性就不可避免的丢失了。

While fields of type object (see Multilevel Objects) are useful for storing a single object, they are useless, from a search point of view, 

for storing an array of objects.

虽然object类型的字段对于保存一个单一的object很有用,但是从检索的角度来说,这对于保存一个object数组却是无用的。

This is the problem that nested objects are designed to solve。

nested object就是为了解决上述问题而设计出来的。

By mapping the commments field as type nested instead of type object, each nested object is indexed as a hidden separate document, something like this:

通过将comments字段映射为nested类型,而不是object类型,每一个nested object 将会作为一个隐藏的单独文本建立索引。如下:

{ ①
  "comments.name":    [ john, smith ],
  "comments.comment": [ article, great ],
  "comments.age":     [ 28 ],
  "comments.stars":   [ 4 ],
  "comments.date":    [ 2014-09-01 ]
}
{ 
  "comments.name":    [ alice, white ],
  "comments.comment": [ like, more, please, this ],
  "comments.age":     [ 31 ],
  "comments.stars":   [ 5 ],
  "comments.date":    [ 2014-10-22 ]
}
{ 
  "title":            [ eggs, nest ],
  "body":             [ making, money, work, your ],
  "tags":             [ cash, shares ]
}
①nested object

By indexing each nested object separately, the fields within the object maintain their relationships. We can run queries that will match only 

if the match occurs within the same nested object.

通过分开给每个nested object建索引,object内部的字段间的关系就能保持。当执行查询时,只会匹配’match’同时出现在相同的nested object的结果.

Not only that, because of the way that nested objects are indexed, joining the nested documents to the root document at query time is fastalmost as fast as if they were a single document.

不仅如此,由于nested objects 建索引的方式,在查询的时候将根文本和nested文档拼接是很快的,就跟把他们当成一个单独的文本一样的快。

These extra nested documents are hidden; we cant access them directly. To update, add, or remove a nested object, we have to reindex 

the whole document. Its important to note that, the result returned by a search request is not the nested object alone; it is the whole document.

这些额外的nested文本是隐藏的;我们不能直接接触。为了更新,增加或者移除一个nested对象,必须重新插入整个文本。要记住一点:查询请求返回的结果不仅仅包括nested对象,而是整个文本。

You may want to index inner objects both as nested fields and as flattened object fields, eg for highlighting. This can be achieved

 by setting include_in_parent to true:

你可能想要检索内部object同时当作nested 字段和当作整平的object字段,比如为了强调。这可以通过将include_in_parent设置为true实现:

curl -XPUT 'localhost:9200/my_index' -d '
{
  "mappings":{
     "blogpost":{
	     "properties":{
		     "comments":{
			    "type":"nested",
				"include_in_parent":true,
				"properties":{
				   "name":    {"type":"string"    },
				   "comment": { "type": "string"  },
                   "age":     { "type": "short"   },
                   "stars":   { "type": "short"   },
                   "date":    { "type": "date"    }
				}
			 }
		 }
	 }
  }
}

The result of indexing our example document would be something like this:

查询结果类似这样:

{ 
    "user.first" : "alice",
    "user.last" :  "white"
}
{ 
    "user.first" : "john",
    "user.last" :  "smith"
}
{ 
    "group" :        "fans",
    "user.first" : [ "alice", "john" ],
    "user.last" :  [ "smith", "white" ]
}

Nested fields may contain other nested fields. The include_in_parent object refers to the direct parent of the field, while the include_in_root 

parameter refers only to the topmost “root” object or document.

nested 字段可能会包含其他的nested 字段。include_in_parent object关联字段的直接上层,而include_in_root仅仅关联“根”obejct或文本



参考:

1.http://www.elastic.co/guide/en/elasticsearch/guide/master/nested-objects.html

2.http://www.elastic.co/guide/en/elasticsearch/reference/1.4/mapping-nested-type.html



<think>嗯,用户问的是Elasticsearchobjectnested类型的优势。首先,我需要回忆一下这两种数据类型的基本概念和区别。Object类型是Elasticsearch默认的嵌套结构,适用于简单的键值对嵌套,而Nested类型则用于处理更复杂的嵌套对象,特别是当子对象需要独立查询的时候。 我应该先解释为什么需要这两种类型。传统上,在Elasticsearch中,如果一个字段是对象类型,数组中的多个对象会被扁平化为多个字段,导致数据之间的关联丢失。例如,一个用户有多个订单,每个订单有商品和数量,如果用object类型存储,查询时可能会出现错误匹配,因为各个订单的数据会被合并。这时候就需要nested类型来保持每个对象的独立性,确保查询准确。 接下来,需要分别说明objectnested的优势。对于object类型,优势可能在于简单易用,不需要额外配置,存储和查询效率高,适合不需要维护数组元素独立性的场景。而nested类型则通过内部维护隐藏的文档,使得每个嵌套对象可以独立索引和查询,适合需要精准匹配多个字段的情况,比如电商中的订单或博客的评论。 然后要比较两者的区别,比如内部结构、查询方式、性能差异。Object类型数组中的对象会被扁平化,导致跨对象的字段查询不准确;而nested类型每个对象都是独立的,可以精确查询。查询时,object使用普通的查询方式,而nested需要使用专门的nested查询。性能方面,nested因为要维护更多文档,可能在写入和查询时开销更大。 应用场景方面,object适用于简单的嵌套结构,比如用户的地址,而nested适合需要维护独立性的数组对象,如订单、评论等。最后给出选择建议,根据是否需要独立查询来决定使用哪种类型。 需要确保回答结构清晰,分点说明优势、区别和应用场景,同时用例子帮助理解。还要注意使用正确的LaTeX格式,虽然这里可能用不到数学公式,但如果有的话要按照规则处理。另外,语言要口语化,避免技术术语过于密集,让用户容易理解。</think>Elasticsearch 中 `object` 和 `nested` 是两种处理嵌套数据的核心类型,它们的优势和适用场景如下: --- ### **一、Object 类型的优势** 1. **简单嵌套场景** - 适用场景:单层键值对嵌套(如 `用户信息` → `地址`)。 - 示例:存储 `{"user": {"name": "张三", "age": 30}}`,通过 `user.name` 直接查询。 2. **存储和查询效率高** - Object 字段的子属性会被扁平化为普通字段(如 `user.name`),索引和查询性能接近原生字段。 3. **自动映射** - Elasticsearch 自动识别嵌套对象为 `object` 类型,无需显式声明。 --- ### **二、Nested 类型的优势** 1. **保持数组元素的独立性** - **问题背景**:当对象数组(如多个订单)使用 `object` 类型时,Elasticsearch 会将其扁平化,导致跨元素的字段错误关联。 **示例**: 数据:`{"orders": [{"product": "A", "quantity": 2}, {"product": "B", "quantity": 3}]}` `object` 类型查询 `product:A AND quantity:3` 会错误匹配(因为字段被合并为 `["A", "B"]` 和 `[2, 3]`)。 **nested 解决方案**:每个数组元素独立存储和索引,确保查询精确性。 2. **支持复杂查询** - 使用 `nested` 查询和聚合,可精准匹配同一子对象的多个字段。 **查询示例**: ```json { "query": { "nested": { "path": "orders", "query": { "bool": { "must": [ { "term": { "orders.product": "A" } }, { "term": { "orders.quantity": 2 } } ] } } } } } ``` 3. **独立评分机制** - 每个 `nested` 对象独立计算相关性得分(如 `nested` 子查询的 `score_mode` 参数)。 --- ### **三、核心区别对比** | **特性** | **Object 类型** | **Nested 类型** | |------------------------|----------------------------------|----------------------------------| | 内部结构 | 子字段扁平化存储 | 每个数组元素存储为独立隐藏文档 | | 数组元素独立性 | ❌ 元素间字段混合 | ✅ 元素间完全独立 | | 查询方式 | 普通查询(如 `term`) | 必须使用 `nested` 查询 | | 性能 | 高(无额外开销) | 较低(维护更多文档) | | 适用场景 | 简单嵌套(无跨元素查询需求) | 复杂嵌套(需精准匹配子对象字段) | --- ### **四、如何选择?** 1. **使用 `object` 的场景** - 无需维护数组元素的独立性(如用户的多个电话号码)。 - 查询逻辑简单,无跨元素字段匹配需求。 2. **使用 `nested` 的场景** - 需要精确匹配数组元素的多个字段(如订单中的商品和数量组合)。 - 需要聚合或排序嵌套对象内的字段(如统计每个商品的销量)。 --- ### **五、总结** - **`object`**:简单高效,适合轻量级嵌套。 - **`nested`**:解决数组元素独立性丢失问题,适合复杂查询场景。 实际选择需权衡查询需求与性能成本。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值