当前位置: 首页 > news >正文

ES_多表关联


一、 核心设计原则:反规范化(Denormalization)

这是 ES 中最重要、最常用、也是性能最高的关联设计方法。

1. 是什么?
将业务关联的多个实体(表)的数据,在写入 ES 之前,合并到一个文档中。换句话说,用空间换时间,用数据冗余避免昂贵的查询时关联。

2. 何时使用?

  • 一对多关系(例如:一篇博客文章和它的所有评论)。
  • 多对一关系(例如:多个订单都属于同一个用户)。
  • 关联数据不频繁变更,或者变更后对实时性要求不高。

3. 案例:电商订单模型(Order - Product)
在关系数据库中,我们有 orders 表和 products 表,通过 product_id 关联。
在 ES 中,我们将其反规范化为一个 orders 索引。

// RDBMS 结构
orders: [id, user_id, total_amount, created_at]
order_items: [id, order_id, product_id, quantity, price]
products: [id, name, category, description]// ES Denormalized 映射设计
PUT /orders
{"mappings": {"properties": {"order_id": { "type": "keyword" },"user_id": { "type": "keyword" },"total_amount": { "type": "float" },"created_at": { "type": "date" },"items": { // 将订单项和商品信息直接内嵌"type": "nested", // 使用nested类型保证数组对象的独立性"properties": {"item_id": { "type": "keyword" },"quantity": { "type": "integer" },"price": { "type": "float" },// 以下是反规范化的产品信息"product_id": { "type": "keyword" },"product_name": { "type": "text", "fields": { "raw": { "type": "keyword" } } },"product_category": { "type": "keyword" }}}}}
}

4. 优缺点:

  • 优点:查询性能极致。一次查询即可获取所有所需数据,无需额外关联。
  • 缺点
    • 数据冗余:商品信息(如 product_name)会在每个包含它的订单中重复存储。
    • 更新困难:如果商品名称变更,需要更新所有包含该商品的订单文档。通常通过后续的异步作业(如 Spark、Logstash)来执行这种大规模更新。

二、 应用端关联(Application-side Joins)

1. 是什么?
由应用程序而非 ES 来执行关联逻辑。通常分为两步:
1. 第一个查询从 ES 中获取一组结果(例如 IDs)。
2. 根据第一步的结果,发起第二个查询到 ES 或数据库,获取关联数据。

2. 何时使用?

  • 关联的实体完全独立,更新非常频繁。
  • 关联数据不需要在每次查询时都返回(例如,只在详情页才需要展示用户信息)。
  • 你可以接受较高的查询延迟(两次网络往返)。

3. 案例:用户评论系统(Comment - User)

  • comments 索引存储评论内容,包含一个 user_id
  • users 索引存储用户详情(姓名、头像等)。
// 第一步:查询评论
GET /comments/_search
{"query": { "match": { "post_id": "123" } },"_source": ["content", "created_at", "user_id"] // 只取评论内容和用户ID
}// 应用端:从返回的 hits 中提取所有 user_id (e.g., [101, 202])
// 第二步:根据 user_id 批量获取用户信息
GET /users/_mget
{"ids": ["101", "202"]
}
// 最后,在应用端将用户信息“缝合”到评论数据中并返回给客户端。

4. 优缺点:

  • 优点:数据模型清晰,无冗余,易于更新。
  • 缺点:查询延迟高(N+1 查询问题),对应用程序逻辑有依赖。

三、 父子关联(Parent-Child Join)

(注:已在上一节详细介绍,此处简要回顾)

1. 是什么?
在同一索引内,通过 join 类型字段建立文档间的父子关系。父子文档是独立的,但必须路由到同一分片。

2. 何时使用?

  • 父子数据更新非常频繁且需要独立更新(反规范化不适用)。
  • 子文档数量巨大,反规范化会使父文档变得臃肿。
  • 你能接受其显著的性能开销

3. 案例:问答系统(Question - Answer)
一个问题(父)对应大量回答(子),回答频繁新增。

PUT /faq
{"mappings": {"properties": {"qa_relationship": {"type": "join","relations": { "question": "answer" }},"body": { "type": "text" },"user": { "type": "keyword" }}}
}

4. 优缺点:

  • 优点:父子数据独立,更新灵活。
  • 缺点:性能差,内存消耗大,使用复杂(需处理路由)。

四、 宽表预关联(Pre-joined Wide Tables)

1. 是什么?
在数据写入 ES 之前,通过 ETL(Extract, Transform, Load)过程,在数据源头(如数据仓库、业务数据库)完成所有需要的关联查询,生成一张包含所有所需字段的“宽表”,再整批导入 ES。

2. 何时使用?

  • 数据主要用于只读的分析和搜索(如报表、看板、大屏)。
  • 数据更新有明确的批处理窗口(如每天凌晨更新一次)。
  • 关联逻辑非常复杂,无法用上述方案简单实现。

3. 案例:电商数据分析宽表

PUT /product_analytics_wide
{"mappings": {"properties": {"product_id": { "type": "keyword" },"product_name": { "type": "keyword" },"category_name": { "type": "keyword" },"brand_name": { "type": "keyword" },"total_sales_volume": { "type": "long" },    // 预聚合好的数据"avg_rating": { "type": "float" },           // 预聚合好的数据"first_sale_date": { "type": "date" }// ... 几十个其他维度/指标字段}}
}

这张宽表可能由 products, categories, brands, orders, order_items, reviews 等多张表关联和聚合后生成。

4. 优缺点:

  • 优点:查询性能达到巅峰,非常适合 OLAP 场景。
  • 缺点:数据延迟高,完全失去了实时性,ETL 流程复杂。

五、 架构师决策指南:如何选择?

面对一个关联需求,作为架构师,你可以遵循以下决策流程:

flowchart TD
A[开始关联设计] --> B{关联数据是否频繁变更?}
B -- 否 --> C[首选:反规范化<br>性能最优,最符合ES哲学]
B -- 是 --> D{子数据量是否巨大<br>且需独立更新?}
D -- 是 --> E[谨慎选择:父子关联<br>需接受其性能开销和复杂度]
D -- 否 --> F[选择:应用端关联<br>保持数据独立,由应用层处理]
G[分析型/只读场景] --> H[选择:宽表预关联<br>在ETL阶段完成关联]

总结:Elasticsearch 关联设计哲学

  1. 第一选择永远是反规范化:这是最符合 ES 设计理念的方式,能带来极致的性能体验。不要害怕数据冗余。
  2. 如果反规范化不行,考虑应用端关联:这保持了数据的独立性,将复杂度转移到了应用层,是一种务实的解决方案。
  3. 父子关联是最后的逃生舱口:仅在万不得已时(数据量大、更新频繁且必须独立)使用,并务必进行充分的性能压测。
  4. 为分析场景设计宽表:如果业务是只读的、滞后的分析需求,那么在数据进入 ES 之前就完成所有关联(ETL),向 ES 提供最简单的扁平宽表。
http://www.dtcms.com/a/342630.html

相关文章:

  • Linux 信号 (Signals)
  • 鱼眼相机去畸变的算法原理(一)
  • WEB服务器(静态/动态网站搭建)
  • 循环神经网络实战:用 LSTM 做中文情感分析(二)
  • Mokker AI:一键更换照片背景的AI神器
  • 鸿蒙生态开发全栈指南
  • mac的m3芯片安装mysql
  • 统计全为1的正方形子矩阵-二维dp
  • 机器学习中的两大核心算法:k 均值聚类与集成学习
  • c# 和 c++ 怎样结合
  • 基于springboot的美术馆管理系统
  • 迁移docker容器的mysql数据库到本地
  • CQRS 的优缺点
  • 【图像算法 - 20】慧眼识病:基于深度学习与OpenCV的植物叶子疾病智能识别系统
  • uniapp跨域怎么解决
  • uniapp 获取手机状态栏的高度
  • 2025-08-21 Python进阶1——控制流语句
  • K 均值聚类:从概念到实践的无监督学习之旅
  • 面试后的跟进策略:如何提高录用几率并留下专业印象
  • 暂停更新的高速下载网盘,作者可能不再维护
  • Oracle: cannot decrease column length because some value is too big
  • .NET Core MongoDB 查询数据异常及解决
  • 分布式集群压测+grafana+influxdb+Prometheus详细步骤
  • 详细说明http协议特别是conten-length和chunk编码,并且用linux的命令行演示整个过程
  • Python读取和设置PNG图片的像素值
  • 软件漏洞扫描的测试内容(二)
  • DzzOffice V2.3.7 核心功能升级与关键问题修复,体验全面优化!
  • 计算机网络-1——第一阶段
  • 【苹果软件】Prism Mac 9.4苹果系统免费安装包英文版 Graphpad Prism for Mac 9.4软件免费下载与详细图文教程!!
  • UGUI源码剖析(12):实战演练——从零构建一个健壮的Gradient顶点特效