Neo4j 关系类型细分+权重标注迁移方案

迁移策略总览
Neo4j 的好消息是:不需要真正「迁移」,可以在原图上直接演进。核心动作有三:

1. 关系类型重命名/细分 → APOC 批量操作
2. 新增权重属性 → SET 属性更新
3. 建立标注工作流 → LLM + Cypher 半自动化

第一步:先摸清现有结构

// 查看所有现有关系类型及数量
CALL db.relationshipTypes() YIELD relationshipType
RETURN relationshipType;

// 更详细:每种关系类型的数量
MATCH ()-[r]->()
RETURN type(r) AS relType, count(r) AS count
ORDER BY count DESC;

// 查看某类关系的样本
MATCH (a)-[r:你的关系类型]->(b)
RETURN a.name, type(r), b.name
LIMIT 20;

把结果贴给我,我可以帮你做具体的映射方案。

第二步:安装 APOC(关键工具)
Neo4j 原生不能直接重命名关系类型,必须用 APOC:

# 确认 APOC 已安装
CALL apoc.help(“refactor”)

如果没有,在 neo4j.conf 加入:

dbms.security.procedures.unrestricted=apoc.*

第三步:关系类型细分(核心迁移)
方法:复制新关系 → 删除旧关系

// 示例:把旧的 :RELATED_TO 按条件拆分为细分类型
// 先处理「定义关系」
MATCH (a)-[r:RELATED_TO]->(b)
WHERE r.description CONTAINS ‘定义’ OR r.description CONTAINS ‘defines’
CALL apoc.refactor.setType(r, ‘DEFINES_AS’)
YIELD input, output
RETURN count(*);

// 处理「发展关系」
MATCH (a)-[r:RELATED_TO]->(b)
WHERE r.description CONTAINS ‘发展’ OR r.description CONTAINS ‘演变’
CALL apoc.refactor.setType(r, ‘DEVELOPS_FROM’)
YIELD input, output
RETURN count(*);

如果没有description属性,用节点类型判断

// 例:Scripture节点之间的关系改为 ANCHORED_IN
MATCH (a:Concept)-[r:RELATED_TO]->(b:Scripture)
CALL apoc.refactor.setType(r, ‘ANCHORED_IN_L1’)
YIELD input, output
RETURN count(*);

第四步:批量加权重属性
关系类型确定后,加三维权重属性:

// 第一轮:给所有关系加默认权重(待人工/LLM覆盖)
MATCH ()-[r]->()
WHERE r.certainty IS NULL
SET r.certainty = 0.5,
r.centrality = 0.5,
r.evidence = 0.5,
r.annotated = false,
r.annotator = ‘pending’
RETURN count(r);

// 计算综合分数
MATCH ()-[r]->()
SET r.composite_score =
(r.certainty * 0.4 + r.centrality * 0.3 + r.evidence * 0.3)
RETURN count(r);

第五步:LLM 半自动标注流程
这是最关键的效率杠杆:
Python 脚本框架

from neo4j import GraphDatabase
import anthropic
import json

driver = GraphDatabase.driver(“bolt://localhost:7687″,
auth=(“neo4j”, “password”))
client = anthropic.Anthropic()

def annotate_batch(batch_size=50):
# 1. 取出未标注的关系
with driver.session() as session:
result = session.run(“””
MATCH (a)-[r]->(b)
WHERE r.annotated = false
RETURN id(r) as rid,
a.name as source,
type(r) as rel_type,
b.name as target,
r.description as desc
LIMIT $batch_size
“””, batch_size=batch_size)
edges = [dict(record) for record in result]

# 2. 发给 Claude 标注
for edge in edges:
prompt = f”””
你是倪柝声-李常受神学专家。请分析以下知识图谱关系:

节点A:{edge[‘source’]}
关系类型:{edge[‘rel_type’]}
节点B:{edge[‘target’]}
现有描述:{edge.get(‘desc’, ‘无’)}

请返回JSON(只返回JSON,不要其他文字):
{{
“certainty”: 0.0-1.0,
“centrality”: 0.0-1.0,
“evidence”: 0.0-1.0,
“suggested_type”: “从[DEFINES_AS/PRESUPPOSES/DEVELOPS_FROM/CONTRASTS_WITH/ANCHORED_IN_L1/MANDATES_PRACTICE]中选”,
“reason”: “一句话说明”
}}
“””
response = client.messages.create(
model=”claude-sonnet-4-20250514″,
max_tokens=300,
messages=[{“role”: “user”, “content”: prompt}]
)

annotation = json.loads(response.content[0].text)

# 3. 写回 Neo4j
with driver.session() as session:
session.run(“””
MATCH ()-[r]->()
WHERE id(r) = $rid
SET r.certainty = $certainty,
r.centrality = $centrality,
r.evidence = $evidence,
r.composite_score = ($certainty*0.4 + $centrality*0.3 + $evidence*0.3),
r.llm_suggested_type = $suggested_type,
r.annotator = ‘llm-claude’,
r.annotated = true
“””, rid=edge[‘rid’], **annotation)

annotate_batch(50)

第六步:人工审核界面(可选)
高价值节点需要人工复核,建议用简单查询筛出来:

// 找出需要人工审核的关系(低确定性 或 核心节点)
MATCH (a)-[r]->(b)
WHERE r.certainty < 0.4
OR a.name IN [‘经纶’, ‘三一神’, ‘召会’, ‘灵’, ‘生命’]
RETURN a.name, type(r), b.name,
r.certainty, r.llm_suggested_type, r.reason
ORDER BY r.certainty ASC
LIMIT 100;

// 人工确认后标记
MATCH ()-[r]->()
WHERE id(r) = 12345
SET r.annotator = ‘human-verified’,
r.certainty = 0.95

迁移时间估算

|阶段 |工作 |时间 |
|——–|———–|——–|
|结构普查 |运行统计查询 |半天 |
|类型映射设计 |制定旧→新类型对照表 |1-2天 |
|APOC批量迁移|执行关系重命名 |1天 |
|默认权重注入 |全库SET操作 |数小时 |
|LLM批量标注 |4万条 × 约0.5秒|约6小时机器时间|
|人工核心审核 |前200高度数节点 |1-2周 |

最关键的第一个动作
先跑这个查询,把结果给我看:

MATCH ()-[r]->()
RETURN type(r) AS relType, count(r) AS count
ORDER BY count DESC
LIMIT 30;

知道你们现有的关系类型名称,才能制定精确的映射方案,避免误操作四万条关系。​​​​​​​​​​​​​​​​