Initial: integrated 2025 LawGraph (graphrag_pipeline) + 2026 kg_project

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-06-17 10:13:39 +08:00
commit 6c1a69af0d
83 changed files with 14295 additions and 0 deletions
+139
View File
@@ -0,0 +1,139 @@
"""
Neo4j数据导入脚本 - 从CSV导入法规知识图谱数据
"""
import pandas as pd
from pathlib import Path
from neo4j import GraphDatabase
import json
import logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
class Neo4jImporter:
"""Neo4j数据导入器"""
def __init__(self, uri: str, username: str, password: str, database: str = 'neo4j'):
self.driver = GraphDatabase.driver(uri, auth=(username, password))
self.database = database
logger.info(f"连接Neo4j: {uri}")
def close(self):
self.driver.close()
def _run_query(self, query, parameters=None):
with self.driver.session(database=self.database) as session:
result = session.run(query, parameters or {})
return [record.data() for record in result]
def create_constraints(self):
"""创建约束和索引"""
schema_file = Path(__file__).parent / 'schema.cypher'
if schema_file.exists():
with open(schema_file, 'r', encoding='utf-8') as f:
content = f.read()
for line in content.split('\n'):
line = line.strip()
if line.startswith('CREATE ') and not line.startswith('//'):
try:
self._run_query(line)
logger.info(f"执行: {line[:60]}...")
except Exception as e:
if 'already exists' not in str(e):
logger.warning(f"约束跳过: {e}")
def import_nodes(self, nodes_csv: str):
"""导入节点"""
nodes_df = pd.read_csv(nodes_csv, encoding='utf-8-sig')
logger.info(f"导入 {len(nodes_df)} 个节点")
# 按类型分批导入
for node_type in nodes_df['type'].unique():
type_df = nodes_df[nodes_df['type'] == node_type]
label = node_type
for _, row in type_df.iterrows():
props = {}
try:
props = json.loads(row.get('properties', '{}'))
except:
pass
props['id'] = row['id']
props['name'] = row['label']
query = f"MERGE (n:{label} {{id: $id}}) SET n += $props"
self._run_query(query, {'id': row['id'], 'props': props})
logger.info(f" {label}: {len(type_df)}")
def import_relationships(self, rels_csv: str):
"""导入关系"""
rels_df = pd.read_csv(rels_csv, encoding='utf-8-sig')
logger.info(f"导入 {len(rels_df)} 个关系")
imported = 0
for _, row in rels_df.iterrows():
rel_type = row['type']
props = {}
try:
props = json.loads(row.get('properties', '{}'))
except:
pass
query = f"""
MATCH (a {{id: $source}})
MATCH (b {{id: $target}})
MERGE (a)-[r:{rel_type}]->(b)
SET r += $props
"""
try:
self._run_query(query, {
'source': row['source'],
'target': row['target'],
'props': props
})
imported += 1
except Exception as e:
logger.warning(f"关系导入失败: {row['source']} -> {row['target']} ({rel_type}): {e}")
logger.info(f"成功导入 {imported}/{len(rels_df)} 个关系")
def import_all(self, nodes_csv: str, rels_csv: str):
"""完整导入流程"""
logger.info("开始导入...")
self.create_constraints()
self.import_nodes(nodes_csv)
self.import_relationships(rels_csv)
logger.info("导入完成!")
def main():
import yaml
config_file = Path(__file__).parent.parent / 'config' / 'legal_config.yaml'
with open(config_file, 'r', encoding='utf-8') as f:
config = yaml.safe_load(f)
neo4j_config = config['neo4j']
importer = Neo4jImporter(
neo4j_config['uri'],
neo4j_config['username'],
neo4j_config['password'],
neo4j_config['database']
)
output_dir = Path(__file__).parent.parent / 'output'
nodes_csv = str(output_dir / 'nodes_merged.csv')
rels_csv = str(output_dir / 'rels_merged.csv')
try:
importer.import_all(nodes_csv, rels_csv)
finally:
importer.close()
if __name__ == '__main__':
main()
+62
View File
@@ -0,0 +1,62 @@
// Neo4j数据模型 - 城市规划法律法规知识图谱
// ============================================================
// 约束和索引
// ============================================================
CREATE CONSTRAINT law_id IF NOT EXISTS FOR (l:Law) REQUIRE l.law_id IS UNIQUE;
CREATE CONSTRAINT reg_id IF NOT EXISTS FOR (r:AdministrativeRegulation) REQUIRE r.reg_id IS UNIQUE;
CREATE CONSTRAINT rule_id IF NOT EXISTS FOR (r:DepartmentalRule) REQUIRE r.rule_id IS UNIQUE;
CREATE CONSTRAINT doc_id IF NOT EXISTS FOR (d:PolicyDocument) REQUIRE d.doc_id IS UNIQUE;
CREATE CONSTRAINT chapter_id IF NOT EXISTS FOR (c:Chapter) REQUIRE c.chapter_id IS UNIQUE;
CREATE CONSTRAINT section_id IF NOT EXISTS FOR (s:Section) REQUIRE s.section_id IS UNIQUE;
CREATE CONSTRAINT article_id IF NOT EXISTS FOR (a:Article) REQUIRE a.article_id IS UNIQUE;
CREATE CONSTRAINT body_id IF NOT EXISTS FOR (g:GovernmentBody) REQUIRE g.body_id IS UNIQUE;
CREATE CONSTRAINT subject_id IF NOT EXISTS FOR (s:LegalSubject) REQUIRE s.subject_id IS UNIQUE;
CREATE CONSTRAINT concept_id IF NOT EXISTS FOR (s:SpatialConcept) REQUIRE s.concept_id IS UNIQUE;
CREATE CONSTRAINT proc_id IF NOT EXISTS FOR (p:AdministrativeProcedure) REQUIRE p.proc_id IS UNIQUE;
// 索引
CREATE INDEX law_name IF NOT EXISTS FOR (l:Law) ON (l.name);
CREATE INDEX law_status IF NOT EXISTS FOR (l:Law) ON (l.status);
CREATE INDEX article_type IF NOT EXISTS FOR (a:Article) ON (a.article_type);
CREATE INDEX body_name IF NOT EXISTS FOR (g:GovernmentBody) ON (g.name);
CREATE INDEX subject_category IF NOT EXISTS FOR (s:LegalSubject) ON (s.category);
// 全文搜索
CREATE FULLTEXT INDEX law_search IF NOT EXISTS FOR (l:Law) ON EACH [l.name, l.full_title];
CREATE FULLTEXT INDEX article_search IF NOT EXISTS FOR (a:Article) ON EACH [a.text];
// ============================================================
// 导入命令示例
// ============================================================
// LOAD CSV WITH HEADERS FROM 'file:///nodes.csv' AS row
// WITH row WHERE row.type = 'Law'
// CREATE (:Law {law_id: row.id, name: row.label, full_title: apoc.text.replace(row.label, '"', '')});
//
// LOAD CSV WITH HEADERS FROM 'file:///rels.csv' AS row
// MATCH (a {id: row.source})
// MATCH (b {id: row.target})
// CALL apoc.create.relationship(a, row.type, {}, b) YIELD rel
// RETURN rel;
// ============================================================
// 常用查询
// ============================================================
// 查询某法律的所有条文
// MATCH (l:Law {name: '城乡规划法'})-[:HAS_CHAPTER]->(ch)-[:CONTAINS_ARTICLE]->(art:Article)
// RETURN ch.title, art.number, art.text;
// 查询引用某法律的法规
// MATCH (d)-[r:CITES]->(l:Law {name: '城乡规划法'})
// RETURN d.name, type(r), r.context;
// 查询涉及某主题的所有条文
// MATCH (art:Article)-[:REGULATES]->(s:LegalSubject {name: '建设用地'})
// RETURN art.text;
// 查询某机关发布的所有文件
// MATCH (d)-[:ISSUED_BY]->(g:GovernmentBody {name: '自然资源部'})
// RETURN d.name, labels(d);