局部检索、社区摘要与更新成本:练习答案
参考实现
独立运行,以依赖图表示原文及派生产物:
python
deps = {'r1':{'d1','d2'}, 'r2':{'d3'}, 'r4':{'r1'}}
dirty = {'d2'}
while True:
next_dirty = dirty | {name for name,inputs in deps.items() if inputs & dirty}
if next_dirty == dirty:
break
dirty = next_dirty
assert dirty == {'d2','r1','r4'}每轮只增加有限节点,因此会收敛;循环依赖也不会无限增加,但真实生产应禁止或明确处理循环构建,失效能收敛不意味着重建有合法顺序。
返回题目。
链路变体
在插入数据库前执行 texts['s1']='A:amy mentors A:bo from 2024 to 2026.',删除原有2026社区等于 s1/s3/s5 的断言,改成:
python
assert local('A',2026,'A:amy',2) == []
assert any(node=='A:delta' for node,path in local('A',2026,'A:bo',1))
try:
extract('bad','Amy probably knows Bo')
except ValueError:
pass
else:
raise AssertionError('unsupported grammar accepted')失效的是边,不是所有同名节点。实际入库任务把 ValueError 文档记录到待审队列,不把无边当作“文档没有知识”。
并行关系与重复摄取
在原始graph_lab.py的末尾追加运行,保留原s1有效至2028。
python
texts['s6']='A:amy works_for A:bo from 2024 to 2028.'
texts['s7']=texts['s1']
for source in ['s6','s7','s7']:
conn.execute('INSERT OR IGNORE INTO edge VALUES(?,?,?,?,?,?,?)',extract(source,texts[source]))
parallel=graph('A',2026)
assert parallel.number_of_edges('A:amy','A:bo')==3
assert {d['relation'] for d in parallel['A:amy']['A:bo'].values()}=={'mentors','works_for'}
assert {d['source'] for d in parallel['A:amy']['A:bo'].values()}=={'s1','s6','s7'}
path=dict(local('A',2026,'A:amy',2))['A:bo']
assert path[0][2]==['s1','s6','s7']
projection=nx.Graph(parallel)
assert projection.number_of_edges()==3
parts=list(nx.community.greedy_modularity_communities(projection))
evidence={d['source'] for part in parts for a,b,d in parallel.edges(data=True) if a in part and b in part}
assert evidence=={'s1','s3','s5','s6','s7'}
print('parallel claims and idempotent ingestion passed')s6是不同关系,s7是同一关系的独立来源,都必须保留;第二次摄取s7不构成新证据。结构投影仍只有三个端点连接,报告则有五个来源,两个计数回答不同问题。