Neo4j 图数据库操作与数据导入实战

Neo4j 图数据库操作与数据导入实战

一份涵盖 Cypher 查询、CSV 批量导入、Python 动态建边、索引优化与 Docker 部署的 Neo4j 实践笔记。


前言

在知识图谱、股权穿透、关系推理等场景中,Neo4j 是常用的图数据库。本文基于实际项目经验,梳理了从数据建模、节点/关系导入、查询、删除,到索引创建和 Docker 全量同步的关键操作。无论你是初次接触图数据库,还是希望提升导入效率,都能在这里找到可直接复用的参考。

数据模型示例(以公司-股东为例):

  • 节点标签Company(公司)、Shareholders / People(股东/自然人)
  • 关系类型法人股东自然人股东,并携带属性 percent(持股比例)、open_flag(是否公开)

一、基础查询:匹配公司及其股东

MATCH (c:Company {name: '北京万合漫旅信息技术有限公司'})-[r:法人股东|自然人股东]-(p)
RETURN c, COLLECT(DISTINCT p) AS shareholders
  • 通过 | 匹配多种关系类型,一次找出所有股东。
  • COLLECT(DISTINCT p) 去重后返回股东列表,避免重复。
  • 该查询可用于股权穿透的基础信息获取。

二、数据导入

2.1 使用 LOAD CSV 导入节点

LOAD CSV WITH HEADERS FROM 'file:///data/vc_nodes.csv' AS row
CREATE (:Company {id: row.`:ID(VC-ID)`, name: row.name})
  • 文件需放在 Neo4j 的 import 目录下。
  • id: row.:ID(VC-ID)`` 将 CSV 中的 ID 列直接作为节点的 id 属性,便于后续关系匹配。

2.2 LOAD CSV 导入关系(固定关系类型)

LOAD CSV WITH HEADERS FROM 'file:///data/gd_rels.csv' AS row
MATCH (start:Shareholders {id: row.`:START_ID(Shareholders-ID)`})
MATCH (end:Company {id: row.`:END_ID(Shareholders-ID)`})
CREATE (start)-[:自然人股东 {percent: toFloat(row.`percent:float`), open_flag: toInteger(row.`open_flag:int`)}]->(end)
  • 这里的关系类型被硬编码自然人股东,无法根据 CSV 内容动态变化。
  • 若 CSV 中包含多种关系类型(如法人股东、自然人股东),上述写法只能导入其中一种。

2.3 Python 动态导入多种关系

为了解决 LOAD CSV 的动态关系限制,使用 Python 驱动循环读取 CSV 并创建关系:

from neo4j import GraphDatabase
import csv

g = GraphDatabase.driver(GRAPH_DB['uri'], auth=(GRAPH_DB['user'], GRAPH_DB['password']))

def create_relationship(start_node, end_node, start_id, end_id, rel_type, percent, open_flag):
    query = (
        "MATCH (p:%s),(q:%s) "
        "WHERE p.id='%s' AND q.id='%s' "
        "CREATE (p)-[rel:%s{percent:'%s', open_flag:'%s'}]->(q)"
    ) % (start_node, end_node, start_id, end_id, rel_type, percent, open_flag)
    with g.session(database='neo4j') as session:
        session.run(query)

with open('/Users/yqy/neo4j/data/gd_rels.csv', encoding='utf-8') as f:
    reader = csv.DictReader(f)
    for row in reader:
        start_id = int(row[':START_ID(Shareholders-ID)'])
        end_id = int(row[':END_ID(Shareholders-ID)'])
        percent = float(row['percent:float'])
        open_flag = int(row['open_flag:int'])
        relation_type = row[':TYPE']   # 动态读取关系类型
        create_relationship('People', 'Company', start_id, end_id,
                            relation_type, percent, open_flag)
  • 此方法可以根据 CSV 的 :TYPE 字段动态创建 法人股东自然人股东 等不同关系
  • 务必保证节点 ID 唯一,且事先导入所有节点,否则创建关系时会一直执行但无实际效果(见下文注意点)。

三、删除操作

// 删除特定关系
MATCH (:Shareholders)-[r:`股东`]->(:Company)
DELETE r

// 分批删除节点(防内存溢出)
MATCH (n:Shareholders)
WITH n LIMIT 1000000
DELETE n
RETURN count(*)
  • 大批量删除节点时建议分批 + LIMIT,避免一次性加载过多节点导致 OOM。
  • 删除关系必须在删除节点前执行,否则会因外键约束报错。

四、关键注意点

4.1 ID 匹配问题

  • 执行 LOAD CSV 或 Python 建关系时,如果 START_ID 或 END_ID 对应的节点不存在,Cypher 会返回 no changes, no records,而 Python 脚本并不会报错,只会静默跳过。
  • 务必检查节点 ID 完全对应,否则会在无声中丢失大量关系。

4.2 关系设计建议

统一关系方向与语义:A 与 B 的具体关系由关系的属性来区分,而非创建大量不同的关系类型。
例如,不要创建 大股东小股东 等多种类型,而是统一用 股东 关系,内部用 typeshare_percent 属性标记类别。
(但若业务上需要快速检索某一类关系,保留少量关系类型也是合理选择。)


五、索引优化

CREATE INDEX ON :Shareholders(name)
  • 对高频查询字段(如 nameid)建立索引,能显著加速 MATCHWHERE
  • 企业版 Neo4j 支持更多索引类型(如全文索引、复合索引),可按需查阅文档。

六、Docker 全量离线导入(高性能)

对于大规模数据,可使用 neo4j-admin import 工具直接生成数据库文件,导入速度远超逐条 INSERT。

docker run -d --name neo4ji \
  -p 7474:7474 -p 7687:7687 \
  -v /tidb/neo4j/data:/data \
  -v /tidb/neo4j/logs:/logs \
  -v /tidb/neo4j/import:/var/lib/neo4j/import \
  --env-file ./env.list \
  neo4j:enterprise \
  bin/neo4j-admin import \
    --nodes=import/gd_nodes_v1.csv \
    --relationships=import/gd_rels.csv \
    --multiline-fields=True \
    --skip-bad-relationships=True \
    --database=register

参数解读:

  • --nodes:指定节点 CSV,可多次出现。
  • --relationships:指定关系 CSV,格式必须为 :START_ID,:END_ID,:TYPE 及属性列。
  • --multiline-fields=True:允许 CSV 字段中包含换行符。
  • --skip-bad-relationships=True:跳过引用不存在节点的关系,并记录日志。
  • --database=qmpregister:生成名为 qmpregister 的数据库,而非默认 neo4j

注意事项:


结语

本文总结了 Neo4j 从查询到大规模导入的常见操作,尤其突出了 动态关系导入的 Python 方案Docker 离线导入的高效实践。图数据库的精髓在于关系,正确处理好 ID 匹配和关系建模,能让后续查询又快又准。建议将上述命令封装为脚本,结合 CI/CD 定期更新,以维持图谱数据的鲜活。

如果你在操作中遇到特殊问题,欢迎在评论区交流,希望这份速查手册能帮你少走弯路。

posted @ 2026-05-19 16:31  BeginnerY  阅读(27)  评论(0)    收藏  举报