kgrag/kg_build_0409/_post_process_entities_and_relations.py
2026-06-30 13:35:52 +08:00

210 lines
8.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

def reset_entities_and_relations(entities: list, relations: list, device: str):
"""
实体与关系的后处理中心(规则分支入口)。
在此处集中管理所有不需要大模型参与的规则清洗、类型修正和关系调整。
:param entities: 实体列表 (会被原地修改并过滤)
:param relations: 关系列表 (会被原地修改)
:param device: 设备名称
:return: (filtered_entities, relations) 返回过滤后的实体列表和修改后的关系列表
"""
print(f"\n[后处理] 开始执行规则清洗 (Device: {device})...")
total_changes = 0
# ==========================================
# 配置化规则定义:(旧类型, 新类型, 新关系类型, 名称替换逻辑)
# name_transformer: 接收 (old_name, device),返回 new_name
# ==========================================
standardization_rules = [
{
"old_type": "接口关系",
"new_type": "接口",
"new_rel_type": "配备",
"name_transformer": lambda old, dev: f"{dev}的接口"
},
{
"old_type": "安全警告",
"new_type": "安全警告",
"new_rel_type": "安全警告",
"name_transformer": lambda old, dev: old.replace("安全警告", "注意事项") if "注意事项" in old.replace("安全警告", "注意事项") else f"{dev}的注意事项"
},
{
"old_type": "技术指标",
"new_type": "技术指标参数",
"new_rel_type": "具有",
"name_transformer": lambda old, dev: (
old.replace("技术指标", "技术指标参数") if "技术指标" in old
else f"{old}参数" if old
else f"{dev}的技术指标参数"
)
},
{
"old_type": "安装调试",
"new_type": "调试",
"new_rel_type": "调试", # 注意:这里原代码逻辑是关系类型也变为"调试"
"name_transformer": lambda old, dev: (
old.replace("安装调试", "调试") if "安装调试" in old
else f"{dev}的调试"
)
},
{
"old_type": "系统功能",
"new_type": "功能",
"new_rel_type": "实现",
"name_transformer": lambda old, dev: (
old.replace("系统功能", "功能") if "系统功能" in old
else f"{dev}的功能"
)
},
{
"old_type": "调试细则",
"new_type": "调试",
"new_rel_type": "调试",
"name_transformer": lambda old, dev: (
old.replace("调试细则", "调试") if "调试细则" in old
else f"{dev}的调试"
)
}
]
# ==========================================
# 通用处理引擎:执行标准化规则
# ==========================================
for rule in standardization_rules:
count = 0
old_type = rule["old_type"]
new_type = rule["new_type"]
new_rel_type = rule["new_rel_type"]
transformer = rule["name_transformer"]
old_to_new_map = {}
# 1. 处理实体
for ins in entities:
if ins.get("type") == old_type:
old_name = ins["properties"].get("名称", "")
# 生成新名称
new_name = transformer(old_name, device)
# 兜底检查:如果生成的名字还是空的
if not new_name:
new_name = f"{device}{new_type}"
# 应用修改
ins["type"] = new_type
ins["properties"]["名称"] = new_name
old_to_new_map[old_name] = new_name
count += 1
print(f" - [实体] '{old_name}' ({old_type}) -> '{new_name}' ({new_type})")
# 2. 处理关联关系
if old_to_new_map:
for rel in relations:
to_ent = rel.get("to_entity")
if to_ent in old_to_new_map:
old_rel_type_val = rel.get("type")
rel["type"] = new_rel_type
rel["to_entity"] = old_to_new_map[to_ent]
count += 1
print(f" - [关系] '{rel['from_entity']}' --({old_rel_type_val})--> '{to_ent}' 变更为 --({new_rel_type})--> '{rel['to_entity']}'")
if count > 0:
print(f" [规则应用] {old_type} -> {new_type}: 共修改 {count}")
total_changes += count
# ==========================================
# 特殊逻辑:拆分 "基本情况"
# 策略:先收集新生成的实体/关系,循环结束后再添加,避免遍历中修改列表
# ==========================================
new_items_buffer = []
basic_info_indices = [] # 记录需要被移除的"基本情况"实体的索引(如果需要彻底移除)
for idx, ins in enumerate(entities):
if ins.get("type") == "基本情况":
gonneng = ins["properties"].get("主要功能", "")
gztj = ins["properties"].get("工作条件", "")
source_ks = ins.get("knowledge_source")
# 构建 "功能" 实体
func_name = f"{device}的功能"
entity_func = {
"type": "功能",
"properties": {
"名称": func_name,
"内容": gonneng,
"knowledge_source": source_ks
}
}
rela_func = {
"type": "使用",
"from_entity": device,
"to_entity": func_name,
}
# 构建 "环境条件" 实体
env_name = f"{device}的环境条件"
entity_env = {
"type": "环境条件",
"properties": {
"名称": env_name,
"内容": gztj,
"knowledge_source": source_ks
}
}
rela_env = {
"type": "适用",
"from_entity": device,
"to_entity": env_name,
}
new_items_buffer.extend([entity_func, entity_env, rela_func, rela_env])
# 标记该实体后续需要被过滤掉(根据原代码逻辑,"基本情况"最终不保留在返回的实体列表中)
basic_info_indices.append(idx)
print(f" [拆分完成] 已从 '基本情况' 生成 '功能''环境条件' (来源已继承)。")
# 将新生成的项加入主列表
# 注意new_items_buffer 中包含实体和关系,需要分开加
# 前两个是实体,后两个是关系 (根据上面的 extend 顺序)
# 为了更安全,我们显式区分
entities_to_add = [item for item in new_items_buffer if item.get("properties")] # 简单判断:有 properties 的是实体
relations_to_add = [item for item in new_items_buffer if not item.get("properties")] # 没有 properties 的是关系 (假设关系结构不同)
# 更严谨的区分方式是根据 key 判断,或者上面构建时直接分两个列表
# 这里采用重新构建的方式确保准确,因为 buffer 里混放了
# 实际上,上面的逻辑里 entity 有 properties, relation 没有 (或者结构不同)
# 让我们修正一下添加逻辑,直接复用上面构建的变量逻辑会更清晰,但为了适应 buffer
# 重新整理 buffer (刚才的 extend 混合了,这里简单按类型分离)
# 由于上面构建时 entity 都有 "properties" 键relation 没有 (通常 relation 是 from/to/type)
for item in new_items_buffer:
if "properties" in item:
entities.append(item)
else:
relations.append(item)
# ==========================================
# 最终过滤:移除 "基本情况" 实体
# 原代码逻辑是:遍历 entities如果是 "基本情况" 则跳过,否则加入 final_entity
# ==========================================
final_entities = [ins for ins in entities if ins.get("type") != "基本情况"]
# 如果原列表中有被移除的,计算一下数量用于日志(可选)
removed_count = len(basic_info_indices)
if removed_count > 0:
print(f" [过滤完成] 移除了 {removed_count}'基本情况' 实体。")
# ==========================================
# 总结
# ==========================================
if total_changes == 0 and removed_count == 0 and not new_items_buffer:
print(f"[后处理] 未命中任何清洗或拆分规则。")
else:
print(f"[后处理] 全部完成。标准化修改 {total_changes} 次,拆分生成 {len(new_items_buffer)//2} 组新数据,过滤移除 {removed_count} 个旧实体。\n")
return final_entities, relations