Schema 变更管理:不停机的 Ontology 演进
噩梦场景:
Coomia发布于 2025年8月13日21 分钟阅读
分享本文Twitter / X
Schema 变更管理:不停机的 Ontology 演进
“系列:S4 本体建模 · 第 9 篇 | 难度:中级 | 阅读时间:18 分钟
#TL;DR
- Ontology Schema 不是一成不变的——业务演进意味着 ObjectType 需要新增属性、修改类型、删除字段,coomia-dip 提供 Schema 版本化和安全迁移机制,确保变更不会打破现有数据和消费者。
- **三阶段迁移协议(Propose → Validate → Apply)**让每次 Schema 变更都经过兼容性检查、影响分析、数据迁移验证,杜绝"改了 Schema 就炸了"的事故。
- 向后兼容性规则自动判定——新增属性(安全)、修改类型(需验证)、删除属性(危险),系统自动分类并给出迁移建议。
#1. 为什么 Schema 变更管理至关重要
#1.1 没有版本控制的 Schema 变更
Code
噩梦场景:
周一:DBA 把 Order.status 从 STRING 改成了 ENUM
周二:报表团队的 ETL 管道全部失败——他们用 status LIKE '%active%'
周三:前端团队发现下拉菜单不显示了——API 返回的枚举值和前端不匹配
周四:数据科学团队的模型训练失败——特征列的数据类型变了
周五:回滚!但回滚也炸了——新写入的 ENUM 值无法转回 STRING
根因分析:
├── 没有变更影响分析
├── 没有通知下游消费者
├── 没有数据迁移计划
├── 没有回滚方案
└── 没有兼容性检查
#1.2 coomia-dip 的 Schema 版本化
Code
coomia-dip 的 Schema 变更流程:
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
│ Propose │ → │Validate │ → │ Preview │ → │ Apply │
│ 提出变更 │ │兼容性检查│ │影响预览 │ │ 执行迁移 │
└─────────┘ └─────────┘ └─────────┘ └─────────┘
│ │
↓ ↓
不兼容?拒绝 自动数据迁移
或要求显式确认 + 版本号递增
每个 ObjectType 有版本历史:
Order v1: {orderId, status: STRING, amount: DOUBLE}
Order v2: {orderId, status: ENUM, amount: DOUBLE, createdAt: TIMESTAMP}
Order v3: {orderId, status: ENUM, totalAmount: DOUBLE, createdAt: TIMESTAMP}
↑ amount 重命名为 totalAmount
#2. Schema 变更的分类
#2.1 变更类型矩阵
Code
变更类型与风险评级:
┌──────────────────┬────────┬──────────────────────────────┐
│ 变更类型 │ 风险 │ 说明 │
├──────────────────┼────────┼──────────────────────────────┤
│ 新增可选属性 │ 🟢 安全 │ 旧数据不受影响,新数据可选填 │
│ 新增必填属性+默认值│ 🟢 安全 │ 旧数据自动填充默认值 │
│ 新增索引 │ 🟢 安全 │ 后台异步构建,不影响读写 │
│ 属性重命名 │ 🟡 中等 │ 需要更新 API 消费者 │
│ 扩大类型范围 │ 🟡 中等 │ INT→LONG, STRING→TEXT 安全 │
│ 新增枚举值 │ 🟡 中等 │ 旧消费者可能不识别新值 │
│ 修改属性类型 │ 🔴 危险 │ 可能导致数据丢失 │
│ 缩小类型范围 │ 🔴 危险 │ LONG→INT 可能溢出 │
│ 删除属性 │ 🔴 危险 │ 依赖该属性的消费者会失败 │
│ 删除枚举值 │ 🔴 危险 │ 现有数据可能包含该值 │
│ 新增必填属性无默认 │ 🔴 危险 │ 旧数据无法满足约束 │
│ 修改主键 │ ⛔ 禁止 │ 破坏所有关系和引用 │
└──────────────────┴────────┴──────────────────────────────┘
#2.2 兼容性规则引擎
Code
兼容性检查引擎:
输入:当前 Schema + 变更请求
输出:兼容性判定 + 迁移建议
规则 1:新增属性
IF 属性 nullable == true OR default != null:
→ COMPATIBLE(安全)
ELSE:
→ BREAKING(危险:旧数据缺少该字段)
→ 建议:添加默认值或设为可选
规则 2:类型变更
兼容类型对(安全扩展):
BOOLEAN → STRING ✓
INT → LONG → DOUBLE ✓
STRING → TEXT ✓
DATE → TIMESTAMP ✓
不兼容类型对(数据丢失风险):
DOUBLE → INT ✗(精度丢失)
STRING → INT ✗(格式不匹配)
TIMESTAMP → DATE ✗(时间丢失)
规则 3:删除属性
扫描所有依赖:
派生属性依赖?→ BREAKING
ActionType 参数依赖?→ BREAKING
RelationType 引用?→ BREAKING
外部 API 消费者?→ WARNING
IF 无任何依赖:
→ COMPATIBLE(但仍建议先标记 @Deprecated)
规则 4:枚举变更
新增值:COMPATIBLE(旧消费者可能需要更新)
删除值:
IF 现有数据包含该值:BREAKING
IF 现有数据不包含该值:COMPATIBLE(但需验证)
修改值名称:BREAKING(本质上是删除旧值+新增新值)
#3. 三阶段迁移协议
#3.1 阶段一:Propose(提出变更)
Code
API: POST /api/v1/ontology/schema/proposals
请求:
{
"objectTypeId": "Order",
"changes": [
{
"type": "ADD_PROPERTY",
"property": {
"name": "priority",
"dataType": "ENUM",
"enumValues": ["LOW", "MEDIUM", "HIGH", "URGENT"],
"nullable": false,
"defaultValue": "MEDIUM"
}
},
{
"type": "MODIFY_PROPERTY",
"propertyName": "amount",
"modifications": {
"rename": "totalAmount",
"dataType": "DECIMAL" // 从 DOUBLE 改为 DECIMAL
}
},
{
"type": "DEPRECATE_PROPERTY",
"propertyName": "legacyCode",
"deprecationMessage": "Use 'orderCode' instead",
"removalVersion": "v5"
}
],
"description": "Add priority field, rename amount to totalAmount with DECIMAL precision",
"author": "alice@company.com"
}
响应:
{
"proposalId": "prop-20250115-001",
"status": "PENDING_VALIDATION",
"version": {
"current": "v3",
"proposed": "v4"
},
"changes": [...],
"createdAt": "2025-01-15T10:00:00Z"
}
#3.2 阶段二:Validate(兼容性检查)
Code
API: POST /api/v1/ontology/schema/proposals/{proposalId}/validate
自动执行的检查项:
┌──────────────────────────────────────────────────────┐
│ Schema Change Validation Report │
│ Proposal: prop-20250115-001 │
│ ObjectType: Order (v3 → v4) │
├──────────────────────────────────────────────────────┤
│ │
│ Change 1: ADD_PROPERTY "priority" │
│ ├── Compatibility: ✅ COMPATIBLE │
│ ├── Reason: Has default value "MEDIUM" │
│ ├── Data migration: None required │
│ └── Impact: None │
│ │
│ Change 2: RENAME "amount" → "totalAmount" │
│ ├── Compatibility: ⚠️ REQUIRES_MIGRATION │
│ ├── Reason: Property name change │
│ ├── Data migration: Column rename (zero-copy) │
│ └── Impact: │
│ ├── 3 Derived Properties reference "amount" │
│ │ → Will auto-update to "totalAmount" │
│ ├── 2 ActionTypes use "amount" as parameter │
│ │ → Require manual update │
│ ├── 1 RelationType filters on "amount" │
│ │ → Will auto-update │
│ └── External APIs: /api/v1/orders response │
│ → Add alias "amount" → "totalAmount" │
│ │
│ Change 3: TYPE_CHANGE "amount" DOUBLE → DECIMAL │
│ ├── Compatibility: ⚠️ REQUIRES_MIGRATION │
│ ├── Reason: Type widening (safe direction) │
│ ├── Data migration: CAST(amount AS DECIMAL(18,4)) │
│ ├── Estimated time: ~30s for 1M rows │
│ └── Impact: None (DECIMAL is superset of DOUBLE) │
│ │
│ Change 4: DEPRECATE "legacyCode" │
│ ├── Compatibility: ✅ COMPATIBLE │
│ ├── Reason: Deprecation only, not removal │
│ └── Impact: Consumers will see @Deprecated warning │
│ │
│ Overall: ⚠️ COMPATIBLE_WITH_MIGRATION │
│ Estimated migration time: ~35 seconds │
│ Requires confirmation: YES (rename + type change) │
└──────────────────────────────────────────────────────┘
#3.3 阶段三:Apply(执行迁移)
Code
API: POST /api/v1/ontology/schema/proposals/{proposalId}/apply
执行过程(分步骤,每步可回滚):
Step 1: 创建新版本 Schema(v4)
├── 在 Schema Registry 中注册 v4
├── v3 和 v4 同时有效(双版本共存期)
└── ⏱️ < 1 秒
Step 2: 数据迁移
├── 新增列 "priority" DEFAULT 'MEDIUM'
├── 重命名列 "amount" → "totalAmount"
├── 类型转换 DOUBLE → DECIMAL
├── 在线 DDL(不锁表)
└── ⏱️ ~35 秒
Step 3: 更新派生属性
├── 扫描所有引用 "amount" 的派生属性表达式
├── 自动替换为 "totalAmount"
├── 重新验证表达式合法性
└── ⏱️ < 5 秒
Step 4: 更新 API 层
├── 添加属性别名:amount → totalAmount
├── API 同时接受旧名和新名(兼容期)
├── 设置兼容期截止日期(默认 30 天)
└── ⏱️ < 1 秒
Step 5: 发布变更通知
├── 通知所有注册的 Schema 变更监听器
├── 发送变更日志到审计系统
├── 更新 SDK 的类型定义
└── ⏱️ < 1 秒
总耗时:~42 秒(其中 35 秒是数据迁移)
全程无停机,读写不受影响
#4. 数据迁移策略
#4.1 在线迁移 vs 离线迁移
Code
在线迁移(Online Migration)—— 默认策略:
适用:
├── 数据量 < 1000 万行
├── 变更类型为安全扩展
└── 可以接受轻微性能下降(<10%)
实现方式:
1. 双写(Double Write)
新数据同时写入旧格式和新格式
2. 后台回填(Backfill)
后台线程逐批迁移历史数据
3. 切换(Cutover)
历史数据迁移完成后,切换到新格式
4. 清理(Cleanup)
删除旧格式数据
时间线:
T0: 开始双写
T0 ~ T1: 后台回填(分钟 ~ 小时)
T1: 回填完成,验证数据一致性
T2: 切换到新格式
T3: 清理旧格式数据
离线迁移(Offline Migration)—— 大数据量:
适用:
├── 数据量 > 1000 万行
├── 变更类型为破坏性变更
└── 需要精确验证
实现方式:
1. 快照(Snapshot)
对当前数据创建快照
2. 转换(Transform)
在快照上执行数据转换
3. 验证(Verify)
对比转换前后的数据
4. 原子切换(Atomic Switch)
一次性切换到新数据
#4.2 类型转换规则
Code
安全类型转换(自动执行):
源类型 → 目标类型 转换规则
BOOLEAN → STRING "true" / "false"
INT → LONG 直接扩展
INT → DOUBLE 直接扩展
LONG → DOUBLE 直接扩展(注意精度)
FLOAT → DOUBLE 直接扩展
STRING → TEXT 直接扩展
DATE → TIMESTAMP 追加 "T00:00:00Z"
ENUM → STRING 使用枚举值的字符串表示
需要验证的类型转换(逐行检查):
源类型 → 目标类型 验证规则
STRING → INT 每行必须是合法整数
STRING → DOUBLE 每行必须是合法数字
STRING → DATE 每行必须匹配日期格式
STRING → ENUM 每行必须在枚举值列表中
DOUBLE → INT 每行的小数部分必须为 0
TIMESTAMP → DATE 丢弃时间部分(需确认)
验证报告示例:
┌────────────────────────────────────────────────┐
│ Type Conversion Validation │
│ STRING → INT for "Order.legacyAmount" │
├────────────────────────────────────────────────┤
│ Total rows: 1,000,000 │
│ Valid rows: 999,847 │
│ Invalid rows: 153 │
│ │
│ Sample invalid values: │
│ Row 12345: "N/A" │
│ Row 67890: "123.45" │
│ Row 99001: "" │
│ Row 99502: "unknown" │
│ │
│ Action required: │
│ ├── Fix invalid data before migration │
│ ├── Or provide a fallback value │
│ └── Or change target type to allow nulls │
└────────────────────────────────────────────────┘
#4.3 迁移脚本自动生成
Code
coomia-dip 自动生成迁移脚本:
示例:Order v3 → v4 的迁移脚本
-- Migration: Order v3 → v4
-- Generated: 2025-01-15T10:05:00Z
-- Author: system (auto-generated)
-- Step 1: Add new column "priority"
ALTER TABLE order_objects
ADD COLUMN priority VARCHAR(20) DEFAULT 'MEDIUM' NOT NULL;
-- Step 2: Rename column "amount" to "totalAmount"
ALTER TABLE order_objects
RENAME COLUMN amount TO total_amount;
-- Step 3: Change type DOUBLE → DECIMAL
ALTER TABLE order_objects
ALTER COLUMN total_amount TYPE DECIMAL(18,4)
USING CAST(total_amount AS DECIMAL(18,4));
-- Step 4: Update indexes
CREATE INDEX CONCURRENTLY idx_order_priority
ON order_objects(priority);
-- Step 5: Add deprecation marker for "legacyCode"
COMMENT ON COLUMN order_objects.legacy_code IS
'@Deprecated: Use orderCode instead. Removal in v5.';
-- Rollback script (auto-generated):
-- ALTER TABLE order_objects DROP COLUMN priority;
-- ALTER TABLE order_objects RENAME COLUMN total_amount TO amount;
-- ALTER TABLE order_objects ALTER COLUMN amount TYPE DOUBLE PRECISION;
-- DROP INDEX idx_order_priority;
每个迁移脚本都有对应的回滚脚本
回滚脚本在 Apply 之前自动验证可执行性
#5. 版本兼容性管理
#5.1 API 兼容层
Code
Schema 变更后,API 需要支持多版本消费者:
场景:Order.amount 重命名为 Order.totalAmount
API 兼容策略:
v3 消费者(旧)请求 /api/v1/orders/123:
{
"orderId": "123",
"amount": 610.13, ← 旧名字仍然可用
"status": "ACTIVE"
}
v4 消费者(新)请求 /api/v1/orders/123:
{
"orderId": "123",
"totalAmount": 610.13, ← 新名字
"priority": "HIGH", ← 新属性
"status": "ACTIVE"
}
不指定版本的消费者 —— 返回最新版本
指定版本的消费者:
GET /api/v1/orders/123?schemaVersion=v3
→ 返回 v3 格式(使用属性别名映射)
兼容期策略:
v3 别名有效期:v4 发布后 30 天
30 天后:使用旧名字会返回 Deprecation Warning Header
60 天后:使用旧名字会返回 400 Bad Request
#5.2 SDK 自动更新
Code
Schema 变更后,SDK 自动生成新的类型定义:
Python SDK 变更:
# v3 (旧版本)
class Order(OntologyObject):
order_id: str
amount: float
status: str
# v4 (新版本 - 自动生成)
class Order(OntologyObject):
order_id: str
total_amount: Decimal # 重命名 + 类型变更
priority: OrderPriority # 新属性
status: str
legacy_code: str | None # 标记为 @deprecated
@deprecated("Use 'total_amount' instead")
@property
def amount(self) -> Decimal:
return self.total_amount
SDK 版本管理:
SDK 1.0.x → Order v3
SDK 1.1.x → Order v4(向后兼容 v3 别名)
SDK 2.0.x → Order v4(移除 v3 别名)
#5.3 消费者通知机制
Code
Schema 变更通知流:
变更提出 → 验证通过 → 发送通知
通知渠道:
├── Webhook —— 推送到注册的消费者端点
├── Event Bus —— 发布到 Kafka topic "schema-changes"
├── Email —— 发送给受影响 ObjectType 的 owner
└── Dashboard —— 在管理控制台显示变更提醒
通知内容:
{
"eventType": "SCHEMA_CHANGE_PROPOSED",
"objectType": "Order",
"version": {"from": "v3", "to": "v4"},
"changes": [
{"type": "ADD_PROPERTY", "property": "priority"},
{"type": "RENAME_PROPERTY", "from": "amount", "to": "totalAmount"},
{"type": "TYPE_CHANGE", "property": "totalAmount",
"from": "DOUBLE", "to": "DECIMAL"}
],
"impact": {
"derivedProperties": 3,
"actionTypes": 2,
"externalConsumers": 5
},
"compatibilityPeriod": "30 days",
"proposedApplyDate": "2025-01-20T00:00:00Z"
}
消费者响应:
├── ACK —— 已知悉,会在兼容期内更新
├── NACK —— 反对变更,需要更多时间
├── REQUEST_EXTENSION —— 请求延长兼容期
└── 超时未响应 —— 系统发送提醒
#6. 版本回滚
#6.1 自动回滚触发条件
Code
以下情况自动触发回滚:
1. 数据迁移步骤失败
→ 已执行的步骤全部回滚
→ 恢复到变更前的 Schema 版本
2. 迁移后验证失败
→ 数据完整性检查不通过
→ 回滚数据和 Schema
3. 手动触发回滚
→ 管理员发现问题
→ API: POST /api/v1/ontology/schema/rollback/{version}
回滚限制:
├── 只能回滚到上一个版本(v4 → v3)
├── 如果新数据使用了新 Schema 特有的值,回滚需要处理
│ 例:v4 新增了 priority 属性,已有 1000 条记录设置了值
│ 回滚时:这 1000 条记录的 priority 值会丢失
│ → 系统会警告并要求显式确认
└── 超过回滚保护期(默认 7 天)后,旧版本数据可能已清理
#6.2 回滚策略
Code
回滚执行步骤:
Step 1: 停止新版本的数据写入
├── API 层切换回旧版本 Schema
└── 新数据按旧 Schema 写入
Step 2: 数据回迁
├── 执行自动生成的回滚脚本
├── 验证回迁数据的完整性
└── 处理新数据中旧 Schema 无法表达的值
Step 3: 恢复依赖项
├── 派生属性表达式恢复
├── ActionType 参数恢复
├── API 别名移除
└── SDK 回退通知
Step 4: 验证
├── 数据完整性检查
├── 派生属性重算
├── API 端到端测试
└── 消费者健康检查
Step 5: 发布回滚通知
├── 通知所有消费者 Schema 已回滚
└── 记录回滚原因到审计日志
#7. Schema 变更的最佳实践
#7.1 渐进式变更
Code
推荐的变更模式——分步骤而非一步到位:
不推荐:直接重命名并改类型
v3 → v4: amount(DOUBLE) → totalAmount(DECIMAL)
风险:一次变更包含两个破坏性操作
推荐:分两次变更
v3 → v4: 添加 totalAmount(DECIMAL),保留 amount
后台同步 amount → totalAmount
v4 → v5: 标记 amount 为 @Deprecated
v5 → v6: 确认无消费者使用 amount 后删除
每次变更只做一件事:
├── 要么新增
├── 要么重命名
├── 要么改类型
├── 要么删除
└── 不要混合多个破坏性操作
#7.2 Schema 变更日志
Code
每次 Schema 变更都记录到审计日志:
SchemaChangeLog:
├── changeId: "sch-20250115-001"
├── objectTypeId: "Order"
├── versionFrom: "v3"
├── versionTo: "v4"
├── changes: [...]
├── author: "alice@company.com"
├── approver: "bob@company.com"
├── proposedAt: "2025-01-15T10:00:00Z"
├── validatedAt: "2025-01-15T10:05:00Z"
├── appliedAt: "2025-01-15T10:10:00Z"
├── migrationDurationMs: 35000
├── affectedRecords: 1000000
├── status: "COMPLETED"
└── rollbackAvailableUntil: "2025-01-22T10:10:00Z"
查询历史:
GET /api/v1/ontology/schema/changelog?objectTypeId=Order
用途:
├── 审计:谁在什么时候改了什么
├── 调试:某个时间点的 Schema 长什么样
├── 合规:变更经过谁的审批
└── 回溯:追踪数据问题到 Schema 变更
#7.3 Schema 设计原则
Code
设计 Schema 时考虑未来变更的原则:
原则 1:宽松设计
├── 字符串字段用 TEXT 而非 VARCHAR(50)
├── 数值字段用 DECIMAL 而非 INT
├── 日期字段用 TIMESTAMP 而非 DATE
└── 预留扩展字段(metadata: JSON)
原则 2:语义命名
├── 使用业务语义命名:totalAmount 而非 amt
├── 使用一致的命名模式:createdAt, updatedAt, deletedAt
└── 避免缩写:使用 description 而非 desc
原则 3:版本感知
├── API 总是标注版本号
├── 消费者声明自己支持的版本范围
├── Schema 变更有充足的兼容期
└── 自动化测试覆盖多版本兼容性
原则 4:可逆性
├── 每次变更都有回滚方案
├── 删除前先 Deprecate
├── 类型变更优先使用安全扩展方向
└── 保留变更前的数据快照
#8. 自动化 Schema 演进
#8.1 Schema 变更检测
Code
coomia-dip 可以从数据变化中推断 Schema 变更需求:
场景:数据写入时发现不匹配
消息队列收到的数据:
{
"orderId": "ORD-2025-001",
"totalAmount": 610.13,
"priority": "HIGH", ← Schema 中没有这个属性!
"customerSegment": "VIP" ← Schema 中没有这个属性!
}
自动推断流程:
1. 检测到未知属性 "priority" 和 "customerSegment"
2. 分析最近 100 条数据,确认这不是偶发的脏数据
priority 出现 98/100 次,值域 = {LOW, MEDIUM, HIGH, URGENT}
customerSegment 出现 95/100 次,值域 = {VIP, REGULAR, NEW}
3. 自动生成 Schema 变更提案:
ADD_PROPERTY priority: ENUM(LOW, MEDIUM, HIGH, URGENT)
ADD_PROPERTY customerSegment: ENUM(VIP, REGULAR, NEW)
4. 发送通知给 ObjectType owner 审批
5. 审批通过后自动应用
注意:自动推断只能建议新增属性
类型变更和删除必须人工发起
#8.2 Schema 差异比较
Code
API: GET /api/v1/ontology/schema/diff?from=v3&to=v4&objectTypeId=Order
响应:
{
"objectTypeId": "Order",
"from": "v3",
"to": "v4",
"diff": {
"added": [
{"name": "priority", "type": "ENUM", "values": ["LOW","MEDIUM","HIGH","URGENT"]}
],
"modified": [
{
"name": "amount → totalAmount",
"changes": {
"name": {"from": "amount", "to": "totalAmount"},
"type": {"from": "DOUBLE", "to": "DECIMAL(18,4)"}
}
}
],
"deprecated": [
{"name": "legacyCode", "message": "Use orderCode instead", "removalVersion": "v5"}
],
"removed": []
},
"compatibility": "BACKWARD_COMPATIBLE_WITH_MIGRATION",
"migrationRequired": true
}
#9. 多环境 Schema 同步
#9.1 环境晋升流程
Code
Schema 变更在多环境间的晋升:
开发环境 (dev) → 测试环境 (staging) → 生产环境 (prod)
流程:
1. dev 环境:自由变更,无需审批
2. staging 环境:从 dev 同步 Schema,运行集成测试
3. prod 环境:从 staging 晋升,需要审批
Schema 同步 API:
POST /api/v1/ontology/schema/promote
{
"objectTypeId": "Order",
"fromEnvironment": "staging",
"toEnvironment": "prod",
"version": "v4"
}
晋升前检查:
├── staging 环境的集成测试是否全部通过
├── 数据迁移是否在 staging 验证过
├── 消费者兼容性测试是否通过
├── 回滚方案是否就绪
└── 审批人是否已批准
#9.2 Schema 锁定
Code
关键 ObjectType 的 Schema 锁定机制:
锁定级别:
UNLOCKED —— 任何人都可以变更
SOFT_LOCK —— 变更需要 owner 审批
HARD_LOCK —— 变更需要多人审批(2/3 审批者同意)
FROZEN —— 禁止任何变更(除非解冻)
设置锁定:
PUT /api/v1/ontology/schema/lock
{
"objectTypeId": "Order",
"lockLevel": "HARD_LOCK",
"approvers": ["alice", "bob", "carol"],
"reason": "Production release freeze"
}
用途:
├── 发布冻结期:FROZEN
├── 核心模型保护:HARD_LOCK
├── 日常管控:SOFT_LOCK
└── 实验性模型:UNLOCKED
#10. Schema 变更与派生属性 DAG 的联动
Code
Schema 变更会影响 DAG:
场景:重命名 Order.amount → Order.totalAmount
DAG 影响分析:
1. 扫描所有引用 "Order.amount" 的 DAG 节点
2. 找到:
Customer.lifetimeValue 的表达式中引用了 Order.amount
Order.profit 的表达式中引用了 amount
3. 自动更新:
Customer.lifetimeValue: "SUM(Order.amount)" → "SUM(Order.totalAmount)"
Order.profit: "amount - cost" → "totalAmount - cost"
4. 重新验证 DAG:
表达式语法检查 ✓
环检测 ✓
类型兼容检查 ✓
场景:删除 Order.legacyField
DAG 影响分析:
1. 扫描所有引用 "Order.legacyField" 的 DAG 节点
2. 找到:Order.legacyScore = legacyField * 0.5
3. 结论:不能删除!legacyField 被派生属性依赖
4. 建议:先删除 Order.legacyScore,再删除 Order.legacyField
操作顺序:
Step 1: 删除派生属性 Order.legacyScore
Step 2: 从 DAG 中移除 legacyScore 节点
Step 3: 删除源属性 Order.legacyField
Step 4: 重新验证 DAG 完整性
#Key Takeaways
- Schema 变更是 Ontology 演进的常态——coomia-dip 通过版本化、兼容性检查、自动迁移将 Schema 变更从"高风险操作"变成了"可控的日常流程",消灭了"改 Schema 就爆炸"的恐惧。
- 三阶段协议是安全阀——Propose(记录意图)→ Validate(自动检查)→ Apply(受控执行),每个阶段都可以中断和回滚,确保不会出现"改到一半系统不可用"的情况。
- 兼容性规则引擎自动分类——安全变更自动通过,危险变更要求确认,禁止的变更直接拒绝,不依赖人的判断来保证安全。
- API 和 SDK 的多版本支持——通过属性别名和版本协商,新旧消费者可以和平共存,给下游充足的迁移时间。
- Schema 变更与 DAG 联动——重命名属性时自动更新派生属性表达式,删除属性时先检查 DAG 依赖,确保 Schema 变更不会静默打破计算链。
#Next Article
下一篇 S4-10 Metrics 作为 Ontology 将讨论如何将监控指标和业务 KPI 统一纳入 Ontology 模型——不再把 metrics 当作独立系统,而是让它成为 ObjectType 的一部分,实现"业务数据"和"运营指标"的统一查询和联动分析。
#ontology #schema-evolution #version-control #migration #backward-compatibility #breaking-change #data-migration #api-versioning