101 lines
3.6 KiB
Python
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__ = ["收集实体", "归并", "归并哈希", "资料错误"]
|