【Elasticsearch】映射:Nested 类型

映射:Nested 类型

  • [1.为什么需要 Nested 类型](#1.为什么需要 Nested 类型)
  • [2.如何定义 Nested 类型](#2.如何定义 Nested 类型)
  • 3.相关操作
    • [3.1 索引包含 Nested 数据的文档](#3.1 索引包含 Nested 数据的文档)
    • [3.2 查询 Nested 数据](#3.2 查询 Nested 数据)
    • [3.3 聚合 Nested 数据](#3.3 聚合 Nested 数据)
    • [3.4 排序 Nested 数据](#3.4 排序 Nested 数据)
    • [3.5 更新 Nested 文档中的特定元素](#3.5 更新 Nested 文档中的特定元素)
  • [4.Nested 类型的高级操作](#4.Nested 类型的高级操作)
    • [4.1 内嵌 inner hits](#4.1 内嵌 inner hits)
    • [4.2 多级嵌套](#4.2 多级嵌套)
  • 5.注意事项

Nested(嵌套)类型是 Elasticsearch 中一种特殊的数据类型,用于处理 对象数组object arrays)中对象的独立性。在默认情况下,Elasticsearch 会将对象数组 扁平化flattened),这会导致 数组内对象之间的关联丢失。Nested 类型解决了这个问题,它使数组中的每个对象被独立索引和查询。

1.为什么需要 Nested 类型

考虑以下文档结构:

json 复制代码
{
  "user": "John",
  "comments": [
    {
      "text": "Great product!",
      "votes": 5
    },
    {
      "text": "Terrible experience",
      "votes": 1
    }
  ]
}

默认情况下(使用 object 类型)查询 text 包含 Great,且 votes 等于 1 会错误地匹配这个文档,因为 Elasticsearch 将数组扁平化为:

复制代码
comments.text: ["Great product!", "Terrible experience"]
comments.votes: [5, 1]

使用 nested 类型可以保持数组内对象的独立性。

2.如何定义 Nested 类型

在映射中明确声明字段为 nested 类型:

json 复制代码
PUT /my_index
{
  "mappings": {
    "properties": {
      "comments": {
        "type": "nested", 
        "properties": {
          "text": { "type": "text" },
          "votes": { "type": "integer" }
        }
      }
    }
  }
}

3.相关操作

3.1 索引包含 Nested 数据的文档

json 复制代码
PUT /my_index/_doc/1
{
  "user": "John",
  "comments": [
    {
      "text": "Great product!",
      "votes": 5
    },
    {
      "text": "Terrible experience",
      "votes": 1
    }
  ]
}

3.2 查询 Nested 数据

使用 nested 查询来查询嵌套对象:

json 复制代码
GET /my_index/_search
{
  "query": {
    "nested": {
      "path": "comments",
      "query": {
        "bool": {
          "must": [
            { "match": { "comments.text": "Great" } },
            { "range": { "comments.votes": { "gte": 5 } } }
          ]
        }
      }
    }
  }
}

3.3 聚合 Nested 数据

使用 nested 聚合分析嵌套字段:

json 复制代码
GET /my_index/_search
{
  "aggs": {
    "comments_agg": {
      "nested": {
        "path": "comments"
      },
      "aggs": {
        "avg_votes": {
          "avg": { "field": "comments.votes" }
        }
      }
    }
  }
}

3.4 排序 Nested 数据

使用 nested 排序:

json 复制代码
GET /my_index/_search
{
  "sort": [
    {
      "comments.votes": {
        "order": "desc",
        "nested": {
          "path": "comments"
        }
      }
    }
  ]
}

3.5 更新 Nested 文档中的特定元素

需要使用脚本更新:

json 复制代码
POST /my_index/_update/1
{
  "script": {
    "source": """
      if (ctx._source.comments != null) {
        for (int i = 0; i < ctx._source.comments.size(); i++) {
          if (ctx._source.comments[i].text == 'Great product!') {
            ctx._source.comments[i].votes++;
          }
        }
      }
    """
  }
}

返回结果说明如下:

核心字段

字段 含义
_index 文档所属的索引名称(这里是 "my_index")。
_type 文档类型(Elasticsearch 7.x 后默认为 "_doc",表示单类型索引)。
_id 被更新文档的唯一 ID(这里是 "1")。
_version 文档的当前版本号(从 1 变为 2,表示这是第二次修改)。
result 操作结果("updated" 表示文档已成功更新)。

分片信息(_shards

字段 含义
total 需要更新的分片总数(主分片 + 副本分片,这里是 2)。
successful 成功更新的分片数(这里是 2,表示主分片和副本分片均更新成功)。
failed 更新失败的分片数(这里是 0,表示无失败)。
  • 如果集群有副本分片,total 可能大于 1(例如主分片 + 1个副本 = 2)。
  • failed > 0,需检查集群健康状态或分片分配问题。
    并发控制字段
字段 含义
_seq_no 序列号(Sequence Number),用于乐观并发控制(每次修改递增)。
_primary_term 主分片任期(Primary Term),用于区分主分片是否发生过切换(如节点重启)。
  • 这两个字段可用于实现 乐观锁(Optimistic Concurrency Control)。

  • 例如,下次更新时可通过指定 if_seq_noif_primary_term 避免并发冲突。
    业务含义总结

  • 文档更新成功

    • 版本号 _version1 变为 2,说明这是对文档的第二次修改。
    • result: "updated" 确认了更新操作已生效(如果是首次创建,会返回 "created")。
  • 集群状态健康

    • 所有分片(total: 2)均成功更新(successful: 2),无失败(failed: 0)。
  • 后续操作依据

    • _seq_no_primary_term 可用于后续的并发更新控制。
      常见问题
  • 如果 resultnoop:表示脚本执行后未实际修改文档(例如条件不满足或值未变化)。

  • 如果 failed > 0:需检查副本分片是否不可用(如节点宕机或网络问题)。

如果需要进一步验证更新内容,可以通过 GET /my_index/_doc/1 查询文档最新状态。

4.Nested 类型的高级操作

4.1 内嵌 inner hits

🚀 inner_hits 是 Elasticsearch 中的一个功能,它允许你在查询嵌套对象或父子文档时,获取匹配的内部嵌套结果或子文档的详细信息。

获取匹配的嵌套对象详情:

json 复制代码
GET /my_index/_search
{
  "query": {
    "nested": {
      "path": "comments",
      "query": {
        "match": { "comments.text": "product" }
      },
      "inner_hits": {}
    }
  }
}

4.2 多级嵌套

Elasticsearch 支持多级嵌套,但要注意性能影响:

json 复制代码
PUT /my_index
{
  "mappings": {
    "properties": {
      "users": {
        "type": "nested",
        "properties": {
          "name": { "type": "text" },
          "comments": {
            "type": "nested",
            "properties": {
              "text": { "type": "text" },
              "votes": { "type": "integer" }
            }
          }
        }
      }
    }
  }
}

5.注意事项

  • 性能考虑
    • Nested 文档会作为独立文档索引,增加索引大小
    • 查询 nested 字段比普通字段更耗资源
    • 避免过度嵌套(通常不超过 2 2 2 级)
  • 限制
    • 一个索引默认最多包含 50 50 50 个 nested 字段(index.mapping.nested_fields.limit
    • 一个文档中所有 nested 对象数默认不超过 10000 10000 10000 个(index.mapping.nested_objects.limit
  • 与父子文档对比
    • Nested 适合小规模、紧密关联的数据
    • 父子文档(join 类型)适合大规模、松散关联的数据
  • 更新开销
    • 更新父文档会替换整个 nested 数组
    • 频繁更新 nested 字段会影响性能
  • 查询特殊性
    • 必须使用 nested 查询来查询 nested 字段
    • 普通查询无法正确匹配 nested 对象间的关系

通过合理使用 nested 类型,可以准确建模和查询复杂的一对多关系数据,但要注意其对性能的影响。

相关推荐
TDengine (老段)7 小时前
TDengine 数学函数 DEGRESS 用户手册
大数据·数据库·sql·物联网·时序数据库·iot·tdengine
TDengine (老段)7 小时前
TDengine 数学函数 GREATEST 用户手册
大数据·数据库·物联网·时序数据库·iot·tdengine·涛思数据
失散137 小时前
分布式专题——47 ElasticSearch搜索相关性详解
java·分布式·elasticsearch·架构
字节数据平台8 小时前
火山引擎Data Agent再拓新场景,重磅推出用户研究Agent
大数据·人工智能·火山引擎
铭毅天下10 小时前
Elasticsearch 到 Easysearch 数据迁移 5 种方案选型实战总结
大数据·elasticsearch·搜索引擎·全文检索
跨境小新10 小时前
Facebook广告投放:地域定向流量不精准?x个优化指南
大数据·facebook
ZKNOW甄知科技11 小时前
客户案例 | 派克新材x甄知科技,构建全场景智能IT运维体系
大数据·运维·人工智能·科技·低代码·微服务·制造
币须赢12 小时前
688758赛分科技 阴上阴形态 洗盘上涨?
大数据
学掌门12 小时前
大数据知识合集之预处理方法
大数据
Elastic 中国社区官方博客14 小时前
Elasticsearch 推理 API 增加了开放的可定制服务
大数据·数据库·人工智能·elasticsearch·搜索引擎·ai·全文检索