1. 领域驱动设计概述
1.1 DDD 核心概念
领域驱动设计(Domain-Driven Design,DDD)是一种以业务领域为核心的软件建模与架构方法论。它强调技术实现必须紧密围绕业务逻辑,而非数据表或技术框架。DDD 的核心在于通过统一的语言和边界划分,将复杂的业务知识转化为可维护、可演进的软件模型。
| 核心概念 | 定义 | 在搜索系统中的映射 |
|---|---|---|
| 通用语言 | 团队(业务+技术)共享的术语集,消除沟通歧义 | 搜索字段名、聚合维度名、查询参数名必须与业务术语一致 |
| 限界上下文 | 模型应用的显式边界,内部有统一语义 | 商品搜索、订单搜索、用户搜索各自为独立上下文 |
| 实体 | 具有唯一标识且生命周期可追踪的对象 | 商品ID、订单ID、用户ID 作为索引主键 |
| 值对象 | 由属性值定义、无唯一标识的不可变对象 | 价格区间、地理位置坐标、标签集合 |
| 聚合 | 一组相关对象的组合,通过聚合根保证一致性 | 商品聚合(商品+库存+价格+属性)作为索引文档 |
| 领域事件 | 领域中发生的、业务方关心的状态变化 | 商品上架事件触发索引更新、库存变更事件触发聚合查询 |
关键原则:搜索索引的字段设计不应直接照搬数据库表结构,而应基于聚合根和值对象重新组织,使索引文档成为业务语义的"快照"。
1.2 战略设计与战术设计
DDD 将设计过程分为两个层次:战略设计关注宏观的领域划分与上下文关系;战术设计关注微观的模型实现模式。两者在搜索系统中各有侧重。
- 战略设计——决定搜索系统的"边界":
- 识别核心域(商品搜索)、支撑域(用户搜索)、通用域(日志搜索)
- 定义限界上下文之间的映射关系(如商品上下文→搜索上下文的事件同步)
- 划分索引集群的物理边界与逻辑边界
- 战术设计——决定搜索模型的"结构":
- 使用聚合根设计索引文档的顶层结构
- 使用值对象设计嵌套字段(如地址、价格范围)
- 使用领域事件驱动索引增量更新
- 使用仓储模式封装搜索引擎的读写操作
实践建议:在搜索系统启动阶段,先花 30% 的时间做战略设计(上下文映射、事件流梳理),再进入战术设计(索引结构、查询接口),可减少后期 60% 以上的重构成本。
1.3 领域建模在搜索系统中的作用
传统搜索系统往往直接从数据库表结构映射索引字段,导致索引文档与业务语义脱节。领域建模为搜索系统带来三个核心价值:
- 语义对齐:索引字段名、聚合维度名、过滤条件名全部来自通用语言,业务方可以直接理解搜索参数的含义。
- 边界清晰:每个限界上下文对应独立的索引或索引分区,避免字段冲突和语义污染。
- 聚合查询可配置:基于聚合根和值对象,可以精确控制哪些字段参与聚合、聚合的层级深度、以及聚合结果的返回格式。
下图展示了领域建模如何将业务领域知识转化为搜索索引的聚合查询边界:
1.4 搜索系统中的领域建模实践框架
在搜索系统中应用领域建模,通常遵循以下步骤:
| 阶段 | 活动 | 产出物 | 搜索系统对应 |
|---|---|---|---|
| 1. 领域探索 | 事件风暴、业务用例分析 | 领域事件清单、聚合草图 | 搜索需求清单、查询场景列表 |
| 2. 上下文映射 | 识别限界上下文、定义关系 | 上下文映射图 | 索引分区策略、跨上下文查询方案 |
| 3. 聚合设计 | 确定聚合根、实体、值对象 | 聚合模型 | 索引文档结构、嵌套字段映射 |
| 4. 查询边界定义 | 提取聚合维度、过滤条件、排序规则 | 查询参数配置表 | 聚合查询 DSL 模板、边界参数校验规则 |
| 5. 事件驱动同步 | 定义领域事件到索引更新的映射 | 事件处理流程图 | 增量索引管道、数据一致性保障 |
常见误区:不要试图用一个"大索引"覆盖所有业务上下文。每个限界上下文应有独立的索引或索引别名,避免字段膨胀和查询性能退化。当需要跨上下文查询时,优先使用应用层聚合而非索引层 JOIN。