跳到主要内容

实体归一 ​

概述 ​

抽取出“林默”“林公子”和“他”并不等于知道它们是否指向同一个人。实体归一负责把多个文本提及映射到稳定的图节点身份,是知识图谱能否长期维护的关键。

如果实体归一错误,会出现两种相反问题:

  • 拆分错误:同一实体生成多个节点,关系被分散;
  • 合并错误:同名不同实体被合并,产生错误关系传播。

前者降低召回,后者可能污染整个图谱。不能只靠字符串相等解决。

四个不同概念 ​

文本提及 ​

模型响应中的 mentionId 表示当前 Chunk 的一个局部提及,只在单次响应内有效。

候选实体 ​

GraphEntityCandidate 包含名称、类型、别名、属性、证据和候选键。它仍然可能与其他候选指向同一实体。

实体解析结果 ​

GraphEntityResolver 对候选进行聚类或匹配,产生候选键到 nodeId 的映射。

实体注册记录 ​

GraphEntityRegistry 保存跨文档、跨任务可复用的稳定实体身份。它属于长期状态,而不是单次模型输出。

默认名称与别名归一 ​

NameAliasGraphEntityResolver 按“节点类型 + Unicode 规范化名称/别名”合并候选,并通过 SHA-256 生成确定性 nodeId。

text
林默 / 林公子 -> 同一个 Character
林默(Character) / 林默(Organization) -> 不同节点

常见中英文代词即使被模型放进 aliases,也不会作为合并键。属性冲突默认保留首次值,后续候选只补充缺失属性;它不会根据时间、来源可信度或业务优先级自动裁决。

默认实现适合单次文档内的基础去重,但无法可靠处理:

  • “他”“她”“该公司”等指代;
  • 同名不同人;
  • 名称发生变化;
  • 翻译名和音译名;
  • 只有上下文才能区分的角色;
  • 与已有业务主数据匹配。

稳定 ID 的来源 ​

nodeId 应表示业务实体,而不是文本出现位置。可选来源包括:

  • 业务系统主键;
  • 权威主数据 ID;
  • 外部标准编号;
  • 持久化实体注册表分配的 ID;
  • 在有限场景下,由类型和规范名称确定性生成的哈希。

不要使用 mentionId、chunkId、随机数或当前时间生成长期实体 ID。否则文档重试和后续导入会持续创建重复节点。

可以实现 GraphEntityIdGenerator 接入自己的 ID 策略。

为什么默认哈希不足以支持长期图谱 ​

默认哈希取决于本次抽取中确定的规范名称。它能让同一名称重复得到相同 ID,但不能回答:

  • 名称变化前后是否同一实体;
  • 同名的两个实体是否应该分开;
  • 新别名是否属于已有实体;
  • 不同 Space 是否允许共享身份;
  • 实体已经有业务主键时应使用哪个 ID。

所以长期增量入图应使用 GraphEntityRegistry,并在 Pipeline 中装配 RegistryGraphEntityResolver。

使用实体注册表 ​

java
GraphEntityRegistry registry =
    new YourPersistentEntityRegistry();

GraphExtractionPipeline pipeline =
    new GraphExtractionPipeline(
        extractor,
        splitter,
        validator,
        new RegistryGraphEntityResolver(
            "novel_knowledge",
            registry),
        new GraphMutationMapper());

解析器按 Space、节点类型、规范名称和别名查询已有注册记录:

  • 没有命中时生成新 nodeId;
  • 唯一命中时复用已有 nodeId;
  • 命中多个不同 nodeId 时属于歧义,应失败并进入审核,而不是任选一个。

仅把 registry 传给 IncrementalGraphIngestionService 只能在图写成功后保存注册结果,不能改变抽取阶段的解析。跨批次复用历史身份,必须在 Pipeline 的 Resolver 中使用同一个 registry。

注册表的生产约束 ​

生产实现至少需要:

  • 以 Space 隔离不同知识库;
  • 查询时同时限定节点类型;
  • 对名称和别名使用与 Resolver 一致的 NFKC、大小写和空白规范化;
  • 为“Space + 类型 + 规范名称/别名”建立可验证的唯一性规则;
  • 同一个名称已指向另一 nodeId 时拒绝静默覆盖;
  • 幂等保存实体及其新增别名;
  • 保留合并、拆分和人工裁决审计记录;
  • 支持并发创建时的唯一约束或原子冲突处理。

如果多个 Space 共用一个底层表,仍必须把 Space 放入查询和唯一键。否则同名实体会跨知识库污染。

实体注册的提交时机 ​

注册记录应在 Graph Mutation 写入成功后保存,避免失败写入留下指向不存在节点的身份。

但图数据库和注册表通常不在同一个事务中,因此仍可能出现:

text
图写入成功 -> 注册表保存失败

长期入图服务通过持久化操作状态和重试降低这个风险。生产系统还需要对账,发现图节点与注册表不一致。

同名歧义与人工审核 ​

当多个已有实体匹配同一候选时,上层审核界面可以展示:

  • 候选名称、类型和别名;
  • 当前文档上下文与证据;
  • 每个历史实体的属性和关联;
  • 来源文档;
  • 可能的业务主键;
  • 新建实体选项。

审核结果应形成可持久化的别名或身份映射,而不是只修改当前 Mutation。否则下一批文档还会重复产生同样歧义。

指代消解与语义匹配 ​

复杂 Resolver 可以组合:

  • 章节或会话上下文;
  • 已有图谱邻居;
  • 业务主数据;
  • 向量检索;
  • 规则词典;
  • 第二次模型判断;
  • 人工确认。

无论使用什么方法,都应输出可解释的匹配依据和置信信息。高相似度并不等于同一实体,尤其是短名称和常见人名。

实体合并和拆分 ​

发现历史实体重复后,不能只修改注册表指向。图中可能已经存在:

  • 两个节点的不同属性;
  • 指向它们的关系;
  • 不同来源事实;
  • 外部系统引用;
  • 历史文档状态中的 nodeId。

实体合并和拆分应作为独立、可审核的数据治理操作,规划属性合并、关系迁移、别名更新、来源保留和回滚。它不属于默认抽取 Resolver 的自动职责。

常见问题 ​

同名同类型一定是同一实体吗? ​

不一定。默认实现只能做保守的名称归一,生产场景应结合主键、上下文或审核。

可以跨 Space 共用实体 ID 吗? ​

可以由业务决定,但注册查询必须显式带 Space,或者建立清晰的全局身份域。不要因为底层表共享就默认合并知识库。

Registry 会自动保存吗? ​

Pipeline 中的 Resolver 负责查询和映射;增量服务在写图成功后才保存注册结果。单次 Pipeline 抽取不会自动提交业务注册表。

修改规范名称会改变节点 ID 吗? ​

默认哈希策略可能改变。使用持久化注册表或业务主键后,应保持 nodeId 不变,只更新名称和别名。

生产检查清单 ​

  • 是否明确提及、候选、实体和注册记录的区别;
  • nodeId 是否稳定、可复用且与 Chunk 无关;
  • Pipeline 是否真正装配持久化 Registry Resolver;
  • 查询和唯一约束是否包含 Space 与类型;
  • 同名多命中是否进入审核而非随机选择;
  • 属性冲突是否有业务合并策略;
  • 注册是否只在图写成功后提交;
  • 图与注册表不一致是否可恢复和对账;
  • 合并、拆分和别名修改是否有审计;
  • 默认内存注册表是否仅用于测试。

身份确定后,继续阅读增量入图。