ES常用对象类型故事版
- object类型:object类型用于表示一个JSON对象,即非基本数据类型之外的默认JSON对象。可以将多个字段组合成一个对象进行存储和检索,方便对复杂数据结构进行管理和查询。
- flattened类型:flattened类型是一种单映射对象类型,其值为JSON对象。在索引时,flattened类型会将嵌套的JSON对象展平为一级字段,使得数据更加扁平化,便于查询和分析。
- nested类型:nested类型是一种嵌套类型,用于存储嵌套结构的数据。当需要在一个文档中存储多个相关子文档时,可以使用nested类型。nested类型支持独立的查询和过滤,但在性能上会有一定的开销。
- join类型:join类型用于表示父子级关系类型的数据结构。通过join类型可以在一个文档中定义父子关系,例如在一个文档中存储多个子文档。这种类型可以用于实现层次化数据结构的存储和查询。
咱们继续数字村的奇幻之旅!这次村里要处理更复杂的“物品组合”和“家庭关系”,于是诞生了四位建筑大师,各自擅长建造不同结构的“数据房屋”:
故事:数字村的建筑大师与他们的神奇房屋
数字村的村民们拥有的东西越来越丰富,不再是单个物品,而是成组的物品(对象)、嵌套的小包裹(子文档)、甚至有血缘关系的家族物品(父子文档)。为了妥善存放这些复杂关系,村里请来了四位建筑大师:
万能杂物间 (
object
) - 默认的JSON对象类型- 建筑师: 万师傅
- 招牌: “万物皆可装,自由又随性!” (默认存储JSON对象)
- 建造什么:
- 万师傅建造的是一种最普通、最灵活的杂物间。村民可以把任何一组相关的物品,随意地打包成一个包裹(JSON对象),然后整个包裹原封不动地塞进这个杂物间里。
- 怎么用:
- 比如村民“张三”的信息:json
"user": { // 这是一个object类型的杂物间 "name": "张三", "age": 30, "address": { // 里面甚至可以再套一个杂物间! "city": "北京", "street": "朝阳路" } }
- 比如村民“张三”的信息:
- 特点:
- 默认选择:如果你不特别说明怎么存,Elasticsearch 默认就用这种方式存你的对象。
- 灵活嵌套:对象里面可以再套对象,无限嵌套(理论上)。
- 查询限制:当你查询
address.city: "北京"
时,它能找到张三。但是!如果同一个文档里,user
对象有多个(比如一个用户有多个地址),并且你想找 “同时满足城市是北京且街道是朝阳路” 的地址时,它可能会出错!因为它默认会把所有嵌套字段“扁平化”处理,丢失了内部对象的边界信息。
扁平大通铺 (
flattened
) - 单映射对象类型- 建筑师: 扁大叔
- 招牌: “统统摊平,一目了然!” (展平嵌套对象为一级字段)
- 建造什么:
- 扁大叔不喜欢嵌套结构。他拿到一个包裹(JSON对象)后,会把里面所有的东西,不管原来在第几层,都拆出来,铺在一个巨大的、单层的地板上(展平)。并且,他会给每样东西贴上带路径的新标签。
- 怎么用:
- 还是张三的信息,交给扁大叔:
- 原来的
user.name: "张三"
- 原来的
user.address.city: "北京"
变成了user.address.city: "北京"
- 原来的
user.address.street: "朝阳路"
变成了user.address.street: "朝阳路"
- 原来的
- 所有值都被当作
keyword
类型处理(不分词,精确值)。
- 还是张三的信息,交给扁大叔:
- 特点:
- 避免映射爆炸:如果包裹里的东西千奇百怪(动态字段很多),用万师傅的杂物间可能会导致映射字段爆炸(太多字段)。扁大叔的大通铺能有效避免这个问题。
- 简化查询:查询展平后的字段(如
user.address.city: "北京"
) 相对直接。 - 牺牲内部关系:和万师傅的杂物间一样,展平后也丢失了内部对象的边界信息。多个地址混在一起时,精确查询组合条件同样可能出错。
- 值当keyword处理:所有展平出来的字段值都按
keyword
处理,不支持分词、文本分析,只适合精确匹配或聚合。
独立小公寓 (
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恤和帽子是分开的,没有哪个商品同时满足这两个条件。 - 精确查询子对象:可以精确查询子对象内部的组合条件。
- 性能开销:因为每个子对象都相当于一个隐藏的小文档,查询(尤其是聚合)时开销比
object
或flattened
大。公寓楼管理费高!
- 保持独立性:每个
亲子套房 (
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_parent
或has_child
查询。 - 性能开销:维护关系和执行父子查询的开销也比较大。亲子关系管理不易!
故事总结:数字村的“关系”处理专家
- 简单打包,默认就用 (
object
):万师傅的万能杂物间最简单常用,适合大多数不需要严格区分内部对象边界的嵌套数据。但要注意它在处理对象数组内部组合条件时的缺陷。 - 动态字段多,怕爆炸 (
flattened
):扁大叔的扁平大通铺把嵌套结构强行摊平,能有效防止字段爆炸,适合存储结构不确定或字段非常多的动态对象。代价是内部关系丢失,且所有值都按keyword处理。 - 子项独立,精准查询 (
nested
):巢阿姨的独立小公寓是解决对象数组内部独立性问题的标准方案!当你的子对象需要作为一个整体进行精确查询(尤其是组合条件查询)时,必须用它。记住,管理费(性能开销)较高。 - 文档血缘,父子情深 (
join
):关爷爷的亲子套房用于建立文档之间的父子关系层级。适用于需要明确表示独立文档间(如博客和评论)一对多/多对多关系,且需要独立更新子文档的场景。同样有显著的管理开销。
选择哪位建筑大师,取决于你的数据关系的复杂程度和查询的精确性要求。数字村因为这四位大师,得以井然有序地容纳世间万物及其纷繁关系!