Skip to content
📖0 阅读·🤍0 点赞

ES常用对象类型故事版

  • object类型:object类型用于表示一个JSON对象,即非基本数据类型之外的默认JSON对象。可以将多个字段组合成一个对象进行存储和检索,方便对复杂数据结构进行管理和查询。
  • flattened类型:flattened类型是一种单映射对象类型,其值为JSON对象。在索引时,flattened类型会将嵌套的JSON对象展平为一级字段,使得数据更加扁平化,便于查询和分析。
  • nested类型:nested类型是一种嵌套类型,用于存储嵌套结构的数据。当需要在一个文档中存储多个相关子文档时,可以使用nested类型。nested类型支持独立的查询和过滤,但在性能上会有一定的开销。
  • join类型:join类型用于表示父子级关系类型的数据结构。通过join类型可以在一个文档中定义父子关系,例如在一个文档中存储多个子文档。这种类型可以用于实现层次化数据结构的存储和查询。

咱们继续数字村的奇幻之旅!这次村里要处理更复杂的“物品组合”和“家庭关系”,于是诞生了四位建筑大师,各自擅长建造不同结构的“数据房屋”:


故事:数字村的建筑大师与他们的神奇房屋

数字村的村民们拥有的东西越来越丰富,不再是单个物品,而是成组的物品(对象)嵌套的小包裹(子文档)、甚至有血缘关系的家族物品(父子文档)。为了妥善存放这些复杂关系,村里请来了四位建筑大师:

  1. 万能杂物间 (object) - 默认的JSON对象类型

    • 建筑师: 万师傅
    • 招牌: “万物皆可装,自由又随性!” (默认存储JSON对象)
    • 建造什么:
      • 万师傅建造的是一种最普通、最灵活的杂物间。村民可以把任何一组相关的物品,随意地打包成一个包裹(JSON对象),然后整个包裹原封不动地塞进这个杂物间里。
    • 怎么用:
      • 比如村民“张三”的信息:
        json
        "user": { // 这是一个object类型的杂物间
          "name": "张三",
          "age": 30,
          "address": { // 里面甚至可以再套一个杂物间!
            "city": "北京",
            "street": "朝阳路"
          }
        }
    • 特点:
      • 默认选择:如果你不特别说明怎么存,Elasticsearch 默认就用这种方式存你的对象。
      • 灵活嵌套:对象里面可以再套对象,无限嵌套(理论上)。
      • 查询限制:当你查询 address.city: "北京" 时,它能找到张三。但是!如果同一个文档里,user 对象有多个(比如一个用户有多个地址),并且你想找 “同时满足城市是北京且街道是朝阳路” 的地址时,它可能会出错!因为它默认会把所有嵌套字段“扁平化”处理,丢失了内部对象的边界信息。
  2. 扁平大通铺 (flattened) - 单映射对象类型

    • 建筑师: 扁大叔
    • 招牌: “统统摊平,一目了然!” (展平嵌套对象为一级字段)
    • 建造什么:
      • 扁大叔不喜欢嵌套结构。他拿到一个包裹(JSON对象)后,会把里面所有的东西,不管原来在第几层,都拆出来,铺在一个巨大的、单层的地板上(展平)。并且,他会给每样东西贴上带路径的新标签
    • 怎么用:
      • 还是张三的信息,交给扁大叔:
        • 原来的 user.name: "张三"
        • 原来的 user.address.city: "北京" 变成了 user.address.city: "北京"
        • 原来的 user.address.street: "朝阳路" 变成了 user.address.street: "朝阳路"
      • 所有值都被当作 keyword 类型处理(不分词,精确值)。
    • 特点:
      • 避免映射爆炸:如果包裹里的东西千奇百怪(动态字段很多),用万师傅的杂物间可能会导致映射字段爆炸(太多字段)。扁大叔的大通铺能有效避免这个问题。
      • 简化查询:查询展平后的字段(如 user.address.city: "北京") 相对直接。
      • 牺牲内部关系:和万师傅的杂物间一样,展平后也丢失了内部对象的边界信息。多个地址混在一起时,精确查询组合条件同样可能出错。
      • 值当keyword处理:所有展平出来的字段值都按 keyword 处理,不支持分词、文本分析,只适合精确匹配或聚合。
  3. 独立小公寓 (nested) - 嵌套类型

    • 建筑师: 巢阿姨
    • 招牌: “独立空间,互不干扰!” (保持子对象独立性)
    • 建造什么:
      • 巢阿姨专门为那些需要保持独立性的小包裹(子对象) 建造独立的公寓楼。每个小包裹都有自己的独立小公寓(隐藏文档),和主文档住在一起,但物理上是分开存放和管理的
    • 怎么用:
      • 比如一个订单 (order) 有多个商品 (items):
        json
        "order_id": "ORD123",
        "items": [ // 这是一个nested类型的公寓楼
          { // 商品1 的独立小公寓
            "product_id": "P100",
            "name": "T恤",
            "quantity": 2
          },
          { // 商品2 的独立小公寓
            `"product_id": "P200",
            "name": "帽子",
            "quantity": 1
          }
        ]
    • 特点:
      • 保持独立性:每个 items 里的商品对象都是独立的。查询 "items.name": "T恤" AND "items.quantity": 1 时,不会匹配到这个文档!因为巢阿姨知道,T恤和帽子是分开的,没有哪个商品同时满足这两个条件。
      • 精确查询子对象:可以精确查询子对象内部的组合条件。
      • 性能开销:因为每个子对象都相当于一个隐藏的小文档,查询(尤其是聚合)时开销比 objectflattened 大。公寓楼管理费高!
  4. 亲子套房 (join) - 父子级关系类型

    • 建筑师: 关爷爷
    • 招牌: “血脉相连,关系明确!” (定义文档间父子关系)
    • 建造什么:
      • 关爷爷建造的是一种特殊的连体套房。一套房里住着一个父文档和它多个子文档。父文档和子文档是独立的文档,但通过关爷爷的特殊设计(join 字段),它们被明确地链接在一起,住在同一个套房(分片)里。
    • 怎么用:
      • 定义一个 join 字段,比如 my_relation,指定可能的父子关系(如 parent, child)。
      • 父文档(博客文章):
        json
        {
          "id": "blog1",
          "title": "Elasticsearch 入门",
          "my_relation": {
            "name": "parent" // 表明我是父文档
          }
        }
      • 子文档(评论):
        json
        {
          "text": "好文章!",
          "user": "张三",
          "my_relation": {
            "name": "child", // 表明我是子文档
            "parent": "blog1" // 我的父文档ID是 blog1
          }
        }
    • 特点:
      • 定义明确关系:清晰表示一对多多对多(通过额外字段)的文档间关系(如 博客文章->评论,订单->订单项->物流记录)。
      • 独立文档:父和子都是独立文档,可以单独更新、删除。
      • 必须同分片:父文档和它的所有子文档必须存储在同一个分片(套房)里,这是通过路由实现的(通常用父文档ID路由)。
      • 查询特殊:查询父子关系需要使用特定的 has_parenthas_child 查询。
      • 性能开销:维护关系和执行父子查询的开销也比较大。亲子关系管理不易!

故事总结:数字村的“关系”处理专家

  • 简单打包,默认就用 (object):万师傅的万能杂物间最简单常用,适合大多数不需要严格区分内部对象边界的嵌套数据。但要注意它在处理对象数组内部组合条件时的缺陷。
  • 动态字段多,怕爆炸 (flattened):扁大叔的扁平大通铺把嵌套结构强行摊平,能有效防止字段爆炸,适合存储结构不确定或字段非常多的动态对象。代价是内部关系丢失,且所有值都按keyword处理。
  • 子项独立,精准查询 (nested):巢阿姨的独立小公寓是解决对象数组内部独立性问题的标准方案!当你的子对象需要作为一个整体进行精确查询(尤其是组合条件查询)时,必须用它。记住,管理费(性能开销)较高。
  • 文档血缘,父子情深 (join):关爷爷的亲子套房用于建立文档之间的父子关系层级。适用于需要明确表示独立文档间(如博客和评论)一对多/多对多关系,且需要独立更新子文档的场景。同样有显著的管理开销。

选择哪位建筑大师,取决于你的数据关系的复杂程度查询的精确性要求。数字村因为这四位大师,得以井然有序地容纳世间万物及其纷繁关系!