← 返回题目列表

Elasticsearch 中 object 和 nested 类型有什么区别?

高频 中等 第 15 / 30 题 更新于 2026/07/29
ElasticsearchnestedobjectMapping

简化版

object 会把对象数组扁平化,数组内多个对象之间的字段关系可能丢失;nested 会把数组里的每个对象作为隐藏子文档索引,能保证同一个数组元素内的条件匹配。对象数组需要按元素关联查询时用 nested,否则普通 object 更轻。

详细版

例如一篇文档有两个评论:

[
  { "user": "Alice", "score": 5 },
  { "user": "Bob", "score": 1 }
]

如果用普通 object,查询 user=Alice AND score=1 可能错误命中,因为扁平化后用户和分数的对应关系丢了。nested 会保留每个对象边界,必须用 nested query 查询。面试要强调:nested 更准确但更重,写入、查询和聚合成本更高,不要无脑使用。

完整版教学

一、问题来自对象数组的关系丢失

Elasticsearch 没有传统关系型数据库里的行内子表概念。普通 object 字段在索引时会被展开成多个字段。

文档:

{
  "comments": [
    { "user": "Alice", "score": 5 },
    { "user": "Bob", "score": 1 }
  ]
}

如果作为 object 处理,逻辑上容易变成:

comments.user  = ["Alice", "Bob"]
comments.score = [5, 1]

Alice5 的配对关系不再天然保留。

记忆钩子:object 展平字段,nested 保留对象边界。

二、object 的误命中例子

假设我们想查“Alice 给了 1 分”的文档:

{
  "query": {
    "bool": {
      "must": [
        { "term": { "comments.user": "Alice" } },
        { "term": { "comments.score": 1 } }
      ]
    }
  }
}

普通 object 可能命中上面的文档,因为它只知道 comments.user 里有 Alice,也知道 comments.score 里有 1,却不知道这两个值来自不同评论对象。

这个坑在订单明细、商品规格、用户标签属性、问卷答案里非常常见。

三、nested 用隐藏子文档保留边界

nested 会把数组中的每个对象作为独立的隐藏文档建立索引,同时仍然属于父文档。

{
  "mappings": {
    "properties": {
      "comments": {
        "type": "nested",
        "properties": {
          "user": { "type": "keyword" },
          "score": { "type": "integer" }
        }
      }
    }
  }
}

查询时要使用 nested query:

{
  "query": {
    "nested": {
      "path": "comments",
      "query": {
        "bool": {
          "must": [
            { "term": { "comments.user": "Alice" } },
            { "term": { "comments.score": 1 } }
          ]
        }
      }
    }
  }
}

这样两个条件必须在同一个 nested 对象里成立。

四、nested 的成本比 object 高

nested 不是免费精确。一个父文档里有 20 个 nested 对象,底层可能对应 1 个父文档加 20 个隐藏子文档。

1 parent document
+ 20 nested objects
= 21 Lucene documents

这会增加索引体积、写入成本、查询成本和聚合复杂度。父文档更新时,相关 nested 子文档也会受影响。

所以如果只是展示嵌套结构,不需要按数组元素内部多个条件关联查询,普通 object 通常更合适。

五、nested 聚合和 inner_hits 是常见追问

如果要对 nested 字段聚合,需要 nested aggregation。否则聚合可能在父文档语义下理解错误。

{
  "aggs": {
    "comments": {
      "nested": { "path": "comments" },
      "aggs": {
        "avg_score": { "avg": { "field": "comments.score" } }
      }
    }
  }
}

如果想知道到底哪个 nested 对象命中,可以用 inner_hits 返回匹配的内部对象。这对调试很有用。

六、怎么在 object、nested 和拆索引之间选

选择可以按查询需求判断。

建模方式适合场景代价
object只展示嵌套字段,条件不需同元素关联可能误命中
nested对象数组内多条件必须同元素匹配索引和查询更重
拆成独立索引子对象很多、生命周期独立应用侧 join 成本

面试里给出这个取舍,会比只背定义更像真实工程经验。

七、常见误区与追问

  • 误区:object 能天然保证数组对象内字段配对。 object 会扁平化,多条件可能匹配到不同对象。
  • 误区:nested 性能一定更好。 nested 是为准确性付出成本,不是性能优化银弹。
  • 误区:nested 查询可以直接用普通 bool。 nested 字段要用 nested query 指定 path。
  • 追问:inner_hits 有什么用? 返回命中的 nested 子对象,方便解释哪个内部元素满足条件。
  • 追问:nested 对文档数量有什么影响? 每个 nested 对象会成为隐藏 Lucene 文档,数量和成本都会增加。
  • 追问:什么时候拆成独立索引? 子对象数量很大、独立更新频繁、需要单独检索或生命周期独立时考虑。

八、加强记忆

object 和 nested 记成“展平 vs 保边界”。普通 object 会把对象数组字段分别展开,容易出现跨对象误命中;nested 把每个对象作为隐藏子文档,用 nested query 保证条件在同一对象内成立。nested 准确但更重,只有当数组对象内部字段关系真的要被查询时才值得用。