ElasticSearch深入解析(九):Object、Nested、Flattened类型

Elasticsearch 作为面向文档的搜索引擎,对嵌套数据的处理有多种方式,不同类型适用于不同的业务场景。

一、Object 类型:默认的嵌套对象处理方式

核心原理

Elasticsearch 中,JSON 文档的嵌套对象(如 {"user": {"name": "张三", "age": 25}})会被默认映射为 Object 类型。其底层通过 字段扁平化 实现索引:将嵌套对象的字段展开为 父字段.子字段 的形式(如 user.nameuser.age),存储为独立的字段。

典型场景

适用于 简单嵌套对象,且不需要对嵌套对象内部字段进行 关联查询 的场景。例如:

{
  "article": {
    "title": "ES 数据类型指南",
    "author": { 
      "name": "李四", 
      "email": "lisi@example.com" 
    }
  }
}

此时 author 是一个简单对象,若只需查询 author.nameauthor.email 的独立值(不关心是否属于同一作者),Object 类型足够。

关键限制

当嵌套对象是 数组 时(如一个用户有多个地址),Object 类型会 丢失对象内部字段的关联。例如:

{
  "user": "张三",
  "addresses": [
    {"city": "北京", "zip": "100000"},
    {"city": "上海", "zip": "200000"}
  ]
}

Elasticsearch 会将 addresses.city 存储为 ["北京", "上海"]addresses.zip 存储为 ["100000", "200000"]。若执行查询 city=北京 AND zip=200000,会错误匹配到这条文档(因为字段被扁平化,不关心“北京”和“200000”是否属于同一个地址对象)。

二、Nested 类型:解决嵌套数组的关联查询

核心原理

Nested 类型是 Object 类型的扩展,专门用于处理 嵌套对象数组。它将数组中的每个对象 独立索引为一个“子文档”,保留对象内部字段的关联关系。查询时需使用 nested 查询,确保只匹配同一嵌套对象内的字段。

典型场景

适用于 一对多关联 且需要对嵌套对象内部字段进行 组合查询 的场景。例如:

  • 订单的多个商品(需查询“购买了苹果手机且数量>2的订单”);
  • 用户的多个地址(需查询“城市为北京且邮编为100000的地址”)。
使用示例

映射定义

PUT /my_index
{
  "mappings": {
    "properties": {
      "user": {
        "type": "nested",  // 指定为 nested 类型
        "properties": {
          "name": {"type": "keyword"},
          "address": {
            "type": "nested",  // 支持多层嵌套
            "properties": {
              "city": {"type": "keyword"},
              "zip": {"type": "keyword"}
            }
          }
        }
      }
    }
  }
}

查询示例(匹配同一地址内的城市和邮编):

GET /my_index/_search
{
  "query": {
    "nested": {
      "path": "user.address",  // 指定嵌套路径
      "query": {
        "bool": {
          "must": [
            {"term": {"user.address.city": "北京"}},
            {"term": {"user.address.zip": "100000"}}
          ]
        }
      }
    }
  }
}
注意事项
  • 性能与存储:每个嵌套对象独立索引,会增加索引体积(约为普通 Object 类型的 1.5~3 倍);
  • 嵌套层级:支持多层嵌套(如 user.address.street),但深度建议不超过 5 层(过深会影响查询性能);
  • 更新限制:修改嵌套对象的任意字段需重新索引整个父文档(类似关系型数据库的级联更新)。

三、Join 类型:跨文档的父子关联

核心原理

Join 类型允许在 同一索引 中建立父子文档关系(如父文档是“用户”,子文档是“用户的订单”)。通过 _parent 字段关联父子文档,父文档和子文档需存储在 同一分片 上(通过父文档的 _id 哈希到分片)。

典型场景

适用于 跨文档的一对多关联,且父子文档需要 独立更新 的场景。例如:

  • 论坛的“板块(父)- 帖子(子)”;
  • 企业的“部门(父)- 员工(子)”。
使用示例

映射定义

PUT /my_index
{
  "mappings": {
    "properties": {
      "join_field": { 
        "type": "join",
        "relations": {
          "department": "employee"  // 父类型: "department",子类型: "employee"
        }
      }
    }
  }
}

创建父文档(部门)

PUT /my_index/_doc/1
{
  "name": "技术部",
  "join_field": { "name": "department" }  // 标记为父类型
}

创建子文档(员工)

PUT /my_index/_doc/2?routing=1  // 必须与父文档同分片(routing=父文档ID)
{
  "name": "张三",
  "join_field": { 
    "name": "employee", 
    "parent": "1"  // 关联父文档ID
  }
}

查询示例(查询技术部的所有员工):

GET /my_index/_search
{
  "query": {
    "has_parent": {
      "parent_type": "department",
      "query": { "term": { "name": "技术部" } }
    }
  }
}
注意事项
  • 性能瓶颈:父子查询需要跨文档关联(类似关系型数据库的 JOIN),性能低于 Nested 类型(Nested 是单文档内的关联);
  • 分片限制:父文档和子文档必须同分片,若父文档分布不均可能导致分片数据倾斜;
  • 适用场景:仅当父子文档需要 独立更新(如父文档修改不影响子文档)时使用,否则优先选择 Nested 类型。

四、Flattened 类型:动态嵌套对象的轻量化处理

核心原理

Flattened 类型用于将 复杂的嵌套 JSON 对象(如动态结构的元数据)展平为单个字段。所有嵌套的键会被合并为 点分隔的字符串(如 {"a": {"b": "c"}} 会被展平为 a.b: c),并索引为 keyword 类型(支持精确匹配)。

典型场景

适用于 动态或未知结构的嵌套对象,例如:

  • 日志中的 tags 字段(可能包含任意层级的键值对);
  • 商品的扩展属性(如不同品类的额外信息)。
使用示例

映射定义

PUT /my_index
{
  "mappings": {
    "properties": {
      "metadata": {
        "type": "flattened"  // 指定为 flattened 类型
      }
    }
  }
}

文档示例

PUT /my_index/_doc/1
{
  "metadata": {
    "user": {
      "name": "张三",
      "age": 25
    },
    "device": "iPhone 15"
  }
}

此时 metadata 会被展平为 metadata.user.name: "张三"metadata.user.age: "25"metadata.device: "iPhone 15" 等字段。

查询示例(精确匹配展平后的路径):

GET /my_index/_search
{
  "query": {
    "term": { "metadata.user.name": "张三" }  // 直接使用展平后的字段名
  }
}
注意事项
  • 字段限制:展平后的字段数量默认最多 1000 个(可通过 max_flattened_fields 参数调整);
  • 查询能力:仅支持精确匹配(term)或前缀匹配(prefix),无法进行范围查询(如 age>20);
  • 适用场景:优先用于 不需要复杂查询 的动态嵌套对象(如日志元数据),避免因动态映射导致字段爆炸。

五、类型对比与选择建议

类型核心特点适用场景性能与限制
Object扁平化存储,丢失嵌套对象关联简单嵌套对象,无需关联查询轻量,无法处理嵌套数组的关联查询
Nested独立索引嵌套对象,保留关联一对多嵌套数组,需关联查询索引体积大,更新成本高
Join跨文档父子关联父子需独立更新,跨文档查询查询性能差,分片限制严格
Flattened展平动态嵌套对象,简化索引动态/未知结构的嵌套对象,轻查询仅支持精确匹配,字段数量受限

选择建议

  1. 优先使用 Nested 类型 处理嵌套数组的关联查询(如订单-商品);
  2. 仅当父子需独立更新时使用 Join 类型(如部门-员工);
  3. 动态或未知结构的嵌套对象用 Flattened 类型(如日志元数据);
  4. 简单嵌套对象且无需关联查询时,使用默认的 Object 类型
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TracyCoder123

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值