Skip to content

局部检索、社区摘要与更新成本:练习答案 ​

参考实现 ​

独立运行,以依赖图表示原文及派生产物:

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不构成新证据。结构投影仍只有三个端点连接,报告则有五个来源,两个计数回答不同问题。

用心记录每一步成长