101 lines
3.6 KiB
Python

"""实体归并:参考作品内部专名、别名与歧义的确定性归并;可疑同名不覆盖已有实体。"""
from __future__ import annotations
import hashlib
from typing import Any
from muse.资料研究.模型 import 资料错误
def 收集实体(窗口结果: list[dict[str, Any]]) -> list[dict[str, Any]]:
"""把逐窗分析的实体展开为带窗口归属与证据的候选记录。"""
候选: list[dict[str, Any]] = []
for 结果 in 窗口结果:
for 项 in 结果.get("entities") or []:
名 = (项.get("name") or "").strip()
if not 名:
raise 资料错误("实体缺少名称")
候选.append(
{
"name": 名,
"type": (项.get("type") or "unknown").strip() or "unknown",
"aliases": [别名 for 别名 in (项.get("aliases") or []) if 别名],
"evidence": list(项.get("evidence") or ()),
"window_id": 结果.get("window_id"),
}
)
return 候选
def 归并(候选: list[dict[str, Any]]) -> dict[str, Any]:
"""同类型且名称(规范形)一致的候选合并为一组并保留证据;同名异型一律歧义。
规则完全确定性:候选按 (规范化名, 类型) 分组,别名只扩入组的别名集,不另立组;
同一规范名出现在多个类型下时整体登记歧义,不猜测、不投票、不越作品合并。
"""
def 规范(名: str) -> str:
return 名.strip().lower()
组: dict[tuple[str, str], list[dict[str, Any]]] = {}
for 项 in 候选:
组.setdefault((规范(项["name"]), 项["type"]), []).append(项)
按名: dict[str, set[str]] = {}
for 键名, 类型 in 组:
按名.setdefault(键名, set()).add(类型)
合并组: list[dict[str, Any]] = []
歧义: list[dict[str, Any]] = []
for (键名, 类型), 成员 in sorted(组.items()):
if len(按名[键名]) > 1:
出现窗 = sorted(
{
项["window_id"]
for 类型2 in 按名[键名]
for 项 in 组.get((键名, 类型2), [])
if 项["window_id"]
}
)
歧义.append(
{
"名": 键名,
"类型冲突": sorted(按名[键名]),
"出现窗": 出现窗,
"处理": "歧义保留;待核对实体歧义任务澄清",
}
)
continue
合并组.append(
{
"canonical": 成员[0]["name"],
"type": 类型,
"aliases": sorted(
{项["name"] for 项 in 成员}
| {别名 for 项 in 成员 for 别名 in 项["aliases"]} - {成员[0]["name"]}
),
"windows": sorted({项["window_id"] for 项 in 成员 if 项["window_id"]}),
"evidence": [证据 for 项 in 成员 for 证据 in 项["evidence"]],
}
)
return {
"合并组": sorted(合并组, key=lambda g: g["canonical"]),
"歧义": sorted(歧义, key=lambda g: g["名"]),
}
def 归并哈希(归并结果: dict[str, Any]) -> str:
return hashlib.sha256(
hashlib.sha256(
str(sorted((g["canonical"], g["type"]) for g in 归并结果["合并组"])).encode()
+ str(sorted(g["名"] for g in 归并结果["歧义"])).encode()
)
.hexdigest()[:16]
.encode()
).hexdigest()
__all__ = ["收集实体", "归并", "归并哈希", "资料错误"]