OpenMetadata 如何对整个服务执行递归硬删除并验证无残留关系 OpenMetadata 如何对整个服务执行递归硬删除并验证无残留关系【免费下载链接】OpenMetadataThe Open Context Layer for Data and AI , OpenMetadata is the open platform for building trusted data context and business semantics for humans, AI assistants, and agents.项目地址: https://gitcode.com/GitHub_Trending/op/OpenMetadata当 OpenMetadata 中某个数据库服务下积累了大量表和字段需要把整个服务从目录中彻底移除而不是软删除留档时普通的删除端点会逐个实体清理大规模子树下既慢又可能留下指向已删实体的孤立entity_relationship行。OpenMetadata 提供了recursivehardDelete两个查询参数让DELETE /v1/services/databaseServices/{id}支持整个子树递归硬删除并提供了异步变体避免 HTTP 请求超时。本文给出从拿到服务 ID、发起删除、跟踪异步任务到验证数据库与搜索索引无残留的完整操作路径。删除端点与参数递归硬删除使用的是标准的 service 删除端点见 API 参考DELETE /v1/services/databaseServices/{id}?recursivetruehardDeletetrue两个查询参数在端点定义DatabaseServiceResource.java中有明确语义recursive递归删除该实体及其所有子实体默认false。hardDelete硬删除实体直接删行而非标记删除默认false。端点的响应约定200表示成功404表示{id}对应的 database service 不存在。删除操作受 RBAC 鉴权约束MetadataOperation.DELETE调用需携带有效 JWT。硬删除是不可恢复操作。硬删除的子树不进入 DELETED 状态无法通过PUT /v1/services/databaseServices/restore恢复——该 restore 端点只对软删除的 service 生效。执行前确认目标服务确实要彻底删除。大规模子树用异步端点避免超时子树越大例如 计划文档 中描述的 100k–1M 张表的服务删除耗时越长。同步端点会占住整个请求连接此时改用异步端点DELETE /v1/services/databaseServices/async/{id}?recursivetruehardDeletetrue异步路径EntityResource.java的行为是立即返回202 Accepted响应体为DeleteEntityResponse其中jobId是本次删除任务的 UUIDhardDelete与recursive字段回显本次请求的取值。删除在后台异步执行任务完成或失败后通过 WebSocket 推送sendDeleteOperationCompleteNotification/sendDeleteOperationFailedNotification携带同一个jobId。失败时服务端会记录Async delete failed for ... (jobId ...)错误日志。注释中明确说明了这一点WebSocket 通知是异步失败路径唯一的对外报告渠道没有活跃 socket 监听时失败只能从日志中看到。操作前检查确认无孤儿数据残留发起删除前记录一下当前的entity_relationship行数作为删除后对比的基线SELECT COUNT(*) FROM entity_relationship;计划文档中给出过一组本地 Docker 基准测试1 GB heapMySQL Elasticsearch的删除前基线100k 张表的 service 删除前entity_relationship共 100088 行。执行递归硬删除假设服务 ID 为{SERVICE_ID}从GET /v1/services/databaseServices列表响应中获取curl -X DELETE http://localhost:8585/api/v1/services/databaseServices/{SERVICE_ID}?recursivetruehardDeletetrue{SERVICE_ID}需要替换为目标服务的 UUID。服务端口以conf/openmetadata.yaml中的port: ${SERVER_PORT:-8585}为准本地默认 8585。子树很大时改用异步端点并从响应体中记下jobIdcurl -X DELETE http://localhost:8585/api/v1/services/databaseServices/async/{SERVICE_ID}?recursivetruehardDeletetrue返回202且包含jobId表示任务已入队此时删除仍在后台进行不能立即开始验证。判断完成的依据有两个监听 WebSocket 收到该jobId的完成通知或在服务端日志中确认没有Async delete failed记录且任务结束。验证无残留关系删除完成后的验证分三步。1. 目录中实体已消失curl http://localhost:8585/api/v1/services/databaseServices/{SERVICE_ID}预期返回 404service 本体及子树实体都已不存在。2. 数据库中无指向已删实体的孤立关系行再次执行删除前记录的计数查询SELECT COUNT(*) FROM entity_relationship;在计划文档的 100k 表基准场景中删除后该表从 100088 行降至 86 行即该子树的全部 100,002 条边被移除且无孤儿行。你自己的环境中没有固定的预期值判断标准是行数相对删除前基线减少的量应等于该子树贡献的关系边数且不存在 fromId/toId 指向已删实体 ID 的行。3. 搜索索引已清空计划文档的验证项还包括 Elasticsearch 侧该 service 下的 table 文档数应为 0搜索已清理干净。可通过搜索 API 或 ES 的 count 查询按service.id过滤确认。已知限制与边界以下边界直接来自设计文档docs/plans/2026-06-22-bulk-deletion-redesign.md并发写入的竞态尚未在main上关闭。LockManagerInitializer.initialize()没有调用方checkModificationAllowed实际是 no-oploadLockedFqnPrefixes()仍是返回空集合的 stub也没有 stale-lock reaper。因此在删除期间ingestion 仍可能重新创建子树下已被清扫过的实体这些新实体会以孤儿形式存活。删除窗口内应暂停对该服务的 ingestion。按 chunk 的事务原子性是后续工作。当前 chunk 的清理仍是每次 DAO 调用各自 autocommit把每个 chunk 包进一个flushInOneTransaction来自 PR #28675是文档中标注的 follow-up。性能数据是文档示例不是固定预期。计划文档给出的测量值——100k 表子树从基线的 1643 秒约 27 分钟优化到 59 秒约 1700 表/秒、峰值堆内存 493 MB1 GB heap 下无 OOM——是本地 Docker1 GB heapMySQL Elasticsearch环境下的单次基准结果。不同数据规模、引擎和负载下的耗时会有差异只应将其量级作为参考。软删除语义不受影响。本文只覆盖hardDeletetrue路径软删除保留现有树遍历必须为恢复保留关系不适用上述按 ID 集合批量删除的设计。端点的 Javadoc 描述中保留了If databases (and tables) belong the service, it cant be deleted的旧措辞recursivetrue时子树会一并删除实际行为以参数语义和删除后的验证结果为准。相关源码位置递归/硬删除参数入口DatabaseServiceResource.java#L669-L729同步删除与异步删除实现EntityResource.java#L762-L852删除子系统设计与无孤儿验证标准docs/plans/2026-06-22-bulk-deletion-redesign.md端点全集索引docs/generated/api-reference.md【免费下载链接】OpenMetadataThe Open Context Layer for Data and AI , OpenMetadata is the open platform for building trusted data context and business semantics for humans, AI assistants, and agents.项目地址: https://gitcode.com/GitHub_Trending/op/OpenMetadata创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考