Parent-Child 建模

Parent-Child 建模 #

Parent-Child 用来表达"两个文档属于不同类型/生命周期,但又需要建立关联"的场景。相比 nested,它更适合父文档频繁变化 / 子文档数量较多 / 生命周期不同步的情况。

什么时候考虑 Parent-Child? #

典型场景:

  • 主资源 + 活动记录:例如用户(父)+ 多条行为日志/评论(子)
  • 订单 + 物流/状态变更记录:订单比较稳定,状态记录会持续追加
  • 文档 + 标签/评分:标签或评分变化频率远高于主体文档

这类关系有几个共同特点:

  • 父/子文档生命周期不同步(子可以频繁新增/删除,父相对稳定)
  • 子文档数量可能很多,如果全部嵌入父文档会让父文档变得非常庞大
  • 查询时既可能只查子文档,也可能需要"从父找子"或"从子找父"

Parent-Child 与 Nested 的对比 #

可以用下面的方式做一个快速选择:

  • 更适合 Nested 的情况:

    • 子元素数量有限,整体更新成本可接受
    • 查询几乎总是"连带父文档一起看"
    • 不需要单独对"子"做大规模搜索或独立生命周期管理
  • 更适合 Parent-Child 的情况:

    • 子元素数量较多,且经常新增/删除
    • 子文档需要独立参与搜索与统计
    • 父/子有不同的更新/存储策略

Nested 更像"文档内部的结构", Parent-Child 更像"两个文档集合之间的引用关系"。

建模要点(概念级) #

底层上,父文档与子文档都存储在同一个索引中,通过一个"连接字段"来描述父/子的关系:

  • 父文档:在连接字段中声明自己是某个"父类型"
  • 子文档:在连接字段中声明自己是某个"子类型",并携带父文档 ID
  • 父/子关系只在这个索引内部生效,不能跨索引

实务上需要注意:

  • 父/子文档通常需要落在同一个分片上,以保证查询效率与一致性
    → 路由策略(routing)必须以父文档为基准,写子文档时复用父文档的 routing。
  • 一旦索引创建好,父/子结构(连接字段定义)很难修改,通常需要通过"新索引 + 重建数据"来演进。

具体的 mapping 与连接字段配置、查询语法,请以参考手册中的"关联查询"与字段类型文档为准,这里聚焦建模思路与取舍。

查询与聚合上的典型用法(进阶视角) #

有了父子关系之后,你可以表达例如:

  • “找到包含满足某条件子文档的所有父文档”
  • “找到拥有指定父文档的子文档子集”

在查询层面,通常会用到几类"关联查询":

  • has_child:从父的角度出发,筛选"拥有满足子查询条件的父文档"
  • has_parent:从子的角度出发,筛选"其父文档满足某条件的子文档"
  • parent_id:根据父 ID 定位子文档

配合聚合,可以:

  • 按父文档分组统计子文档属性(例如每个用户的评论数、最近一条评论时间)
  • 在子文档条件过滤后,对父文档层面的属性做分析(例如"最近 7 天内有投诉记录的用户,按地区分布")

这些需求如果用纯扁平索引或 nested 来表达,要么需要在应用层做二次 join,要么需要索引大量冗余数据。

性能与复杂度权衡 #

优势:

  • 相比把所有信息塞进一个大文档,父/子分开可以:
    • 降低单个文档的更新成本
    • 对子文档的增删改更轻量
  • 更适合大量子文档的场景(日志/评论/记录类)

成本与限制:

  • 建模和查询语义更复杂,开发/调试成本更高
  • 需要更谨慎地规划索引与路由策略,否则可能出现父/子落在不同分片的问题
  • 某些查询与聚合在父/子混合场景下会显著更重,属于"昂贵查询"范畴
    • 在部分配置下,如果禁止昂贵查询,对应的关联查询(如 has_child/has_parent)会被直接拒绝

经验建议:

  • 如果 nested 能满足需求,优先尝试 nested(语义简单、查询更直观)
  • 只有在 nested 明显不适合(子文档太多 / 生命周期差异很大)时,才考虑 Parent-Child
  • 对使用了父子关系的索引:
    • 控制索引规模与分片数,避免在"超大索引上跑海量父子关联查询"
    • 为关键父子查询单独设计 API 与限流、超时策略,而不是开放为任意 DSL

小结 #

  • Parent-Child 用来表达"两个文档属于不同类型/生命周期,但又需要建立关联"的场景
  • 相比 nested,它更适合父文档频繁变化、子文档数量较多、生命周期不同步的情况
  • 父/子文档通常需要落在同一个分片上,以保证查询效率与一致性
  • 建模和查询语义更复杂,需要更谨慎地规划索引与路由策略

下一步可以继续阅读:

参考手册(API 与参数) #