kgrag/kgrag_migration/05_verify_migration.py
2026-06-30 13:35:52 +08:00

172 lines
6.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""
步骤 5验证迁移结果
在【迁移目标机】上执行本脚本
配置项请修改 migration_config.py
"""
import os
import json
import sys
sys.path.insert(0, os.path.dirname(__file__))
from migration_config import (
OLD_IP, DST_CODE_DIR, DST_FILES_DIR, NEW_BASE_URL,
NEO4J_URI, NEO4J_USER, NEO4J_PASSWORD
)
from neo4j import GraphDatabase
URL_CHECK_SAMPLE = 5
PASS = "\033[92m[PASS]\033[0m"
FAIL = "\033[91m[FAIL]\033[0m"
WARN = "\033[93m[WARN]\033[0m"
def check_files():
print("\n--- 1. 关键文件检查 ---")
checks = [
(DST_FILES_DIR, "原始文档目录"),
(f"{DST_FILES_DIR}/uploads_v1", "高亮 PDF 目录"),
(f"{DST_CODE_DIR}/kg_output", "抽取结果 JSON 目录"),
(f"{DST_CODE_DIR}/kg_snapshot.json", "全量快照 kg_snapshot.json"),
(f"{DST_CODE_DIR}/entity_registry.json", "实体注册表"),
(f"{DST_CODE_DIR}/app.py", "主程序 app.py"),
(f"{DST_CODE_DIR}/config.py", "配置文件 config.py"),
]
all_ok = True
for path, desc in checks:
if os.path.exists(path):
if os.path.isdir(path):
count = len(os.listdir(path))
print(f" {PASS} {desc}: {path} ({count} 个文件)")
else:
size = os.path.getsize(path) / 1024 / 1024
print(f" {PASS} {desc}: {path} ({size:.1f} MB)")
else:
print(f" {FAIL} 缺失: {desc}: {path}")
all_ok = False
return all_ok
def check_neo4j():
print("\n--- 2. Neo4j 图谱检查 ---")
try:
driver = GraphDatabase.driver(NEO4J_URI, auth=(NEO4J_USER, NEO4J_PASSWORD))
with driver.session() as session:
node_count = session.run("MATCH (n) RETURN count(n) AS c").single()["c"]
rel_count = session.run("MATCH ()-[r]->() RETURN count(r) AS c").single()["c"]
ks_count = session.run(
"MATCH (n) WHERE n.knowledge_source IS NOT NULL RETURN count(n) AS c"
).single()["c"]
driver.close()
print(f" {PASS} Neo4j 连接正常")
print(f" {PASS} 节点数: {node_count} 关系数: {rel_count} 含溯源节点: {ks_count}")
return True, ks_count
except Exception as e:
print(f" {FAIL} Neo4j 连接失败: {e}")
return False, 0
def check_old_ip(neo4j_ok, ks_count):
print(f"\n--- 3. 旧 IP 残留检查({OLD_IP}---")
config_files = ["config.py", "batch_kg_build.py", "app.py"]
residual_found = False
for fname in config_files:
fpath = os.path.join(DST_CODE_DIR, fname)
if not os.path.exists(fpath):
continue
with open(fpath, "r", encoding="utf-8", errors="ignore") as f:
content = f.read()
lines = [i+1 for i, l in enumerate(content.splitlines()) if OLD_IP in l]
if lines:
print(f" {WARN} {fname}{lines} 行仍含旧 IP")
residual_found = True
if neo4j_ok and ks_count > 0:
try:
driver = GraphDatabase.driver(NEO4J_URI, auth=(NEO4J_USER, NEO4J_PASSWORD))
with driver.session() as session:
result = session.run(
f"MATCH (n) WHERE n.knowledge_source CONTAINS '{OLD_IP}' "
"RETURN count(n) AS c"
)
old_url_count = result.single()["c"]
driver.close()
if old_url_count > 0:
print(f" {WARN} Neo4j 中仍有 {old_url_count} 个节点含旧 URL请重新执行步骤 3")
residual_found = True
else:
print(f" {PASS} Neo4j 中无旧 IP 残留")
except Exception as e:
print(f" {WARN} 无法检查 Neo4j 中的旧 URL: {e}")
if not residual_found:
print(f" {PASS} 配置文件中无旧 IP 残留")
def check_urls(ks_count):
print(f"\n--- 4. 溯源 URL 可访问性抽查(抽查 {URL_CHECK_SAMPLE} 个)---")
if ks_count == 0:
print(f" {WARN} Neo4j 不可用,跳过 URL 检查")
return
try:
driver = GraphDatabase.driver(NEO4J_URI, auth=(NEO4J_USER, NEO4J_PASSWORD))
with driver.session() as session:
result = session.run(
"MATCH (n) WHERE n.knowledge_source IS NOT NULL "
f"RETURN n.名称 AS name, n.knowledge_source AS ks LIMIT {URL_CHECK_SAMPLE}"
)
records = list(result)
driver.close()
except Exception as e:
print(f" {WARN} 无法读取 Neo4j 节点: {e}")
return
for record in records:
name = record["name"]
ks_raw = record["ks"]
try:
ks_list = json.loads(ks_raw) if isinstance(ks_raw, str) else ks_raw
url = ks_list[0].get("url", "") if ks_list else ""
if not url:
print(f" {WARN} 节点 {name}: knowledge_source 无 url 字段")
continue
filename = url.split("/upload/")[-1].split("#")[0]
local_path = os.path.join(DST_FILES_DIR, "uploads_v1", filename)
if os.path.exists(local_path):
print(f" {PASS} {name}: 高亮 PDF 存在 → {filename}")
else:
print(f" {FAIL} {name}: 高亮 PDF 缺失 → {local_path}")
except Exception as e:
print(f" {WARN} 节点 {name} 检查失败: {e}")
def main():
print("==========================================")
print(" kgrag 迁移验证脚本 - 步骤 5")
print(f" 代码目录: {DST_CODE_DIR}")
print(f" 文件目录: {DST_FILES_DIR}")
print(f" 新服务地址: {NEW_BASE_URL}")
print("==========================================")
files_ok = check_files()
neo4j_ok, ks_cnt = check_neo4j()
check_old_ip(neo4j_ok, ks_cnt)
check_urls(ks_cnt)
print("\n==========================================")
if files_ok and neo4j_ok:
print(" 总体结果:迁移基本完成,请检查上方 WARN/FAIL 项")
else:
print(" 总体结果:存在关键问题,请修复 FAIL 项后重新验证")
print("==========================================")
if __name__ == "__main__":
main()