neo4j学习笔记
Neo4j Fundamentals:graphacademy.neo4j.com/courses/neo4j-fundamentals
1.节点、关系、属性、标签
- 节点:图中的基本实体-人。
- 标签:描述节点的内容-一个人,一个公司职员。一个节点可以有很多标签。
- 关系:人际关系,a在公司b工作。有一个类型+一个方向组成。
- 属性:节点和关系的数据。属性以键值对的形式命名;例如firstName(Yunqi)和position(student)。节点和关系可以有任意数量的属性,同一类型的节点和关系不必具有相同的属性;属性具有类型(整数、布尔值、字符串、列表等),并且可以是特定节点标签的唯一标识符(键)。
在两个节点之间创建关系时,数据库会将指向该关系的指针存储在每个节点中。读取数据时,数据库会沿着内存中的指针查找数据,而不是依赖底层索引。
这意味着,无论数据总量如何,查询时间都与扩展的关系规模保持恒定。
2.Cypher 语法
2.1 查询
1. 节点匹配基础 (Node Matching)
用于在图中定位特定类型的实体。
- 语法结构:
MATCH (变量名:标签名) - 关键点:
- 圆括号
():代表一个节点。 - 变量名:用于在后续查询(如
WHERE或RETURN)中引用该节点。 - 标签名:指定节点的类型(如
:Person或:Movie)。
- 圆括号
- 示例:
MATCH (p:Person)—— 查找所有带有Person标签的节点,并将其命名为p。
2. 关系匹配基础 (Relationship Matching)
用于描述节点之间的连接方式。
- 语法结构:
(起始节点)-[:关系类型]->(目标节点) - 关键点:
- 方括号
[]:位于短横线中间,代表关系。 - 箭头
->或<-:代表关系的方向。图数据库中的关系是有方向的。 - 变量引用:关系也可以赋予变量名,如
-[r:ACTED_IN]->,其中r代表关系变量。
- 方括号
- 示例:
MATCH (p:Person)-[:ACTED_IN]->(m:Movie)—— 查找所有“参演”了电影的“人”。
3. 条件过滤 (Filtering)
用于缩小搜索范围,精确匹配特定属性。
- 语法结构:
WHERE 变量名.属性名 = '值' - 关键点:
- 支持逻辑运算符:
AND,OR,NOT。 - 支持比较运算符:
=,<>,<,>,IN等。
- 支持逻辑运算符:
- 示例:
WHERE p.name = 'Tom Hanks'—— 仅筛选出姓名属性为汤姆·汉克斯的节点。
4. 结果返回 (Returning Results)
定义查询最终输出的内容。
- 语法结构:
RETURN 表达式1, 表达式2 - 关键点:
- 返回对象:直接返回变量(如
RETURN p)将输出整个节点实体(包含所有属性和元数据),在 UI 中通常显示为图形。 - 返回属性:返回特定字段(如
RETURN p.name)将仅输出该属性的值,在 UI 中通常显示为表格。
- 返回对象:直接返回变量(如
- 示例:
RETURN p.name, m.title—— 仅输出人的姓名和电影的标题。
2.2模式匹配
1. 模式语法解构 (Pattern Anatomy)
Cypher 的核心是“所见即所得”,通过字符模拟图形结构。
- 节点 (Nodes):使用圆括号
( )表示。- 匿名节点:
(:Person)(仅指定标签)。 - 具名节点:
(p:Person)(指定标签并赋予变量名p)。
- 匿名节点:
- 关系 (Relationships):使用方括号
[ ]和连线表示。- 无向连线:
--。 - 有向连线:
-->或<--。 - 带类型的关系:
-[:ACTED_IN]->。 - 带变量的关系:
-[r:ACTED_IN]->(变量r可用于获取关系属性,如r.role)。
- 无向连线:
2. 多节点路径匹配 (Matching Paths)
可以将多个节点和关系串联,描述复杂的业务逻辑。
- 语法结构:
MATCH (n1)-[r1]->(n2)<-[r2]-(n3) - 应用场景:查找“共同点”。例如,查找与汤姆·汉克斯(Tom Hanks)合作过的所有演员。
- 示例:
MATCH (p:Person)-[:ACTED_IN]->(m:Movie)<-[:ACTED_IN]-(p2:Person)
WHERE p.name = 'Tom Hanks'
RETURN p2.name
逻辑:找到汤姆·汉克斯演过的电影m,再反向找到同样演过电影m的另一个人p2。
3. 结果别名 (Aliasing with AS)
为了提高输出结果(尤其是表格形式)的可读性,可以为返回的列重命名。
- 语法结构:
RETURN 表达式 AS 自定义名称 - 关键点:
AS关键字可以将复杂的属性路径(如p2.name)映射为一个简洁的列标题(如actor)。 - 示例:
RETURN p2.name AS actor, m.title AS movie
4. 关系属性的访问 (Accessing Relationship Properties)
关系不仅连接节点,自身也可以携带属性(如演员在电影中的角色名、用户评分的分值)。
- 前提条件:必须为关系定义变量名。
- 语法结构:
MATCH ()-[r:TYPE]->() RETURN r.propertyName - 示例:
RETURN r.role AS role—— 返回演员在特定电影中扮演的角色名称。
5. 模式匹配的执行逻辑
- 定位起始点:通过
MATCH和WHERE找到图中的锚点节点。 - 路径扩展:从锚点出发,根据定义的箭头方向和关系类型,在内存中遍历相连的指针。
- 提取数据:根据
RETURN子句,从匹配成功的整条“路径”中提取出指定的节点、关系或属性。
2.3.创建图
1. 智能创建与更新 (The MERGE Clause)
MERGE 是 Cypher 中最强大的写入语句,它结合了“查找”和“创建”的功能。
- 核心逻辑:
- 检查存量:先检查图中是否存在匹配该模式的节点或关系。
- 存在则匹配:如果已存在,则像
MATCH一样直接使用它。 - 不存在则创建:如果不存在,则像
CREATE一样新建一个。
- 语法结构:
MERGE (变量:标签 {唯一标识属性: 值}) - 示例:
MERGE (m:Movie {title: "Arthur the King"})
逻辑:如果库里有这部电影,就选中它;如果没有,就新建一个名为 "Arthur the King" 的电影节点。
2. 属性赋值 (The SET Clause)
用于为节点或关系添加、更新属性。
- 语法结构:
SET 变量名.属性名 = 值 - 关键点:常与
MERGE配合使用,确保在创建或匹配后完善数据信息。 - 示例:
MERGE (m:Movie {title: "Arthur the King"})
SET m.released = date('2024-03-22')
3. 关系的安全创建
在创建关系时,推荐先 MERGE 节点,再 MERGE 关系,以防止重复创建节点或产生断开的关系。
- 标准工作流:
MERGE起始节点。MERGE目标节点。MERGE它们之间的关系。
- 示例:
MERGE (m:Movie {title: "Arthur the King"})
MERGE (u:User {name: "Adam"})
MERGE (u)-[r:RATED {rating: 5}]->(m)
4. 结果排序 (The ORDER BY Clause)
用于对返回的表格数据进行逻辑排序。
- 语法结构:
ORDER BY 变量名.属性名 [ASC/DESC] - 关键点:
- ASC:升序(默认)。
- DESC:降序。
- 示例:
ORDER BY m.released DESC—— 按上映时间从新到旧排列。
5. 数量限制 (The LIMIT Clause)
用于控制返回结果的条目数,常用于获取“前 N 名”或分页显示。
- 语法结构:
LIMIT 数字 - 示例:
MATCH (m:Movie)
RETURN m.title
ORDER BY m.released DESC
LIMIT 5
逻辑:返回最新上映的 5 部电影。
3.GraphRAG和RAG的区别
1. 传统 RAG 的局限性:只见树木,不见森林
传统的 RAG(基于向量搜索)主要解决的是“局部”问题。
- 工作原理:将文档切碎成块,通过关键词或语义相似度找到最相关的几个碎片。
- 痛点:如果你问“这篇文章的主题是什么?”或者“这 100 份文档里关于某个实体的总体评价如何?”,传统 RAG 会因为只能检索到局部碎片,而无法拼凑出全局的全貌。
- 直觉比喻:传统 RAG 像是在图书馆里找几本具体的书;而 GraphRAG 则是要理解整个图书馆里所有书之间的逻辑网。
2. 为什么需要 GraphRAG?
微软和 Neo4j 提出的 GraphRAG 引入了一个关键步骤:将非结构化文本转化为结构化的知识图谱。
- 信息压缩:它将分散在不同文档里的实体(Entity)和关系(Relationship)提取出来,合并到同一个图谱中。
- 消除冗余:通过“实体解析(Entity Resolution)”,它能发现文档 A 里的“苹果公司”和文档 B 里的“Apple Inc”是同一个东西,从而把碎片信息连接起来。
3. GraphRAG 的核心创新:从 Local 到 Global
neo4j.com/blog/developer/global-graphrag-neo4j-langchain,这篇博客重点解释了微软 GraphRAG 论文中的一个神来之笔——社区发现(Community Detection):
- 图社区(Graph Communities):算法会自动发现图中哪些节点联系紧密(比如“高血压”和“氨氯地平”属于医疗社区)。
- 社区摘要(Community Summaries):LLM 会为每个社区写一份“总结报告”。
- 全局回答:当你问一个宏观问题时,系统不再去翻原始文档碎片,而是去阅读这些预先写好的社区总结。这让它能够回答跨文档、跨实体的全局性问题。
| 特性 | 传统 RAG (Vector-only) | GraphRAG (Neo4j + LLM) |
|---|---|---|
| 检索单位 | 文本块 (Text Chunks) | 实体、关系、社区摘要 |
| 擅长问题 | 具体事实(“某人的生日?”) | 宏观总结(“这个行业的主要风险?”) |
| 数据关联 | 靠语义相似度(可能断裂) | 靠物理指针直接连接(无索引邻接) |
| 处理成本 | 检索时成本低 | 索引阶段(建图)成本高,但回答质量极高 |
4.Text2Cypher 的工作流
GraphRAG 是"为什么要用图做检索"(理念层)
Text2Cypher 是"怎么把自然语言变成图查询"(机制层)√
GraphCypherQAChain 是"LangChain 里怎么封装这个机制"(实现层)
也就是:"用户说了一句人话,图数据库是怎么听懂的?"———通过Text2Cypher
Text2Cypher 是 GraphRAG 中实现"用户用自然语言查询知识图谱"的关键技术。它的工作流分为四个阶段:

阶段一:读取 Schema
LLM 不是凭空知道数据库结构的。它需要先读取图数据库的 Schema,了解有哪些节点类型、属性、以及节点之间的关系。例如:
Node properties:
Movie {runtime: INTEGER, name: STRING}
Actor {name: STRING}
The relationships:
(:Actor)-[:ACTED_IN]->(:Movie)
阶段二:生成 Cypher
LLM 根据 Schema 和用户问题,生成 Cypher 查询语句。例如用户问 "Who played in Top Gun?",LLM 生成:
MATCH (a:Actor)-[:ACTED_IN]->(m:Movie)
WHERE m.name = 'Top Gun'
RETURN a.name
这一步的本质是:把自然语言的语义意图,翻译成图数据库的结构化查询。
阶段三:数据库执行
Cypher 语句被发送到 Neo4j 执行,返回结构化数据:
[
{"a.name": "Tom Cruise"},
{"a.name": "Val Kilmer"},
{"a.name": "Anthony Edwards"},
{"a.name": "Meg Ryan"}
]
阶段四:结果翻译
LLM 再次介入,把结构化查询结果组织成自然语言:
Tom Cruise, Val Kilmer, Anthony Edwards, and Meg Ryan played in Top Gun.
Text2Cypher 的核心是 LLM 的两次转换——第一次把自然语言转成 Cypher,第二次把数据库结果转成自然语言。Neo4j 在中间负责提供真实数据。这意味着答案不是来自 LLM 的记忆,而是来自数据库的真实查询结果,从根本上减少了幻觉。
5.GraphCypherQAChain 是什么
是 LangChain 中用于 Neo4j 图数据库问答的链。它的作用是让用户可以用自然语言查询图数据库,而不需要手写 Cypher 查询语句。
它的核心流程是:
用户自然语言问题
→ LLM 根据图数据库 schema 生成 Cypher 查询
→ Neo4j 执行 Cypher 查询并返回结果
→ LLM 根据数据库结果生成自然语言回答
为什么需要它:
普通 LLM 只能根据模型自身知识回答,容易产生幻觉,也无法直接访问我的私有数据库。
GraphCypherQAChain 的价值在于:它让 LLM 先查询 Neo4j 中的真实数据,再根据查询结果回答问题。因此它适合用于知识图谱问答、GraphRAG、企业内部数据问答、实体关系查询等场景。
举例:
提问:
Who played in Top Gun?
LLM 根据图数据库 schema 生成 Cypher:
MATCH (a:Actor)-[:ACTED_IN]->(m:Movie)
WHERE m.name = 'Top Gun'
RETURN a.name
Neo4j 执行后返回:
[
{"a.name": "Tom Cruise"},
{"a.name": "Val Kilmer"},
{"a.name": "Anthony Edwards"},
{"a.name": "Meg Ryan"}
]
LLM 再把结果翻译成自然语言:
Tom Cruise, Val Kilmer, Anthony Edwards, and Meg Ryan played in Top Gun.
重点理解的点:
GraphCypherQAChain不是让 LLM 直接回答,而是让 LLM 先生成数据库查询语句。Neo4j 负责提供真实数据,LLM 负责两次转换:第一次把自然语言转换成 Cypher,第二次把数据库结果转换成自然语言答案。
这条链路的可靠性取决于几个因素:图数据库的 schema 是否清晰,LLM 生成的 Cypher 是否正确,Neo4j 返回的数据是否完整,以及最终回答是否严格基于查询结果。
6.rag-demo
git clone https://github.com/neo4j-examples/rag-demo
1.运行起来
1.neo4j
我连接不到云,最后选择neo4j desktop,下载https://neo4j.com/download/,然后在settings设置代理,然后创建instance。
将demo里面的secrets.toml.example复制一份secrets.toml,将url改成bolt://localhost:7687,写入自己的NEO4J_PASSWORD
2.改openai,chat部分用deepseek-chat,embedding部分用硅基流动的BAAI/bge-large-zh-v1.5
直接让trae改就行:“原来的rag-demo用的是openai,我要用deepseek,这导致没有embedding,我想用硅基流动平台的BAAI/bge-large-zh-v1.5,我有硅基流动的api,我想用的这个模型也是免费的。帮我把对话和embbding拆开,对话走deepseek,embedding走硅基流动,同时我还会在配置密钥的地方加入SILICONFLOW_API_KEY。”
2.逐文件解释demo
1. 入口文件:main.py
核心功能 :
- Streamlit 前端界面,处理用户输入
- 显示聊天历史
- 调用 rag_agent.get_results() 获取 AI 回答
关键代码位置 :
- 第 90-92 行 :调用 rag_agent.get_results() ,这是核心入口:
agent_response = rag_agent.get_results(question=user_input, callbacks=[])
入口总结 :用户在 Streamlit 输入 → main.py 接收 → 调用 rag_agent.get_results()
2. 核心逻辑:rag_agent.py(Chain 组装的地方)
核心功能 :
- 初始化 LLM
- 组装三个 Tool(vector_tool、vector_graph_tool、graph_cypher_tool)
- 创建 ReAct Agent(LangChain 的 Agent)
- 暴露 get_results() 函数供 main.py 调用
关键代码位置 :
- 初始化 DeepSeek LLM
- 加载三个 Tools
- 组装 AgentExecutor (LangChain 的 ReAct Agent)
- agent_executor.invoke() 执行 Agent
Chain 组装总结 : llm + [vector_tool, graph_cypher_tool, vector_graph_tool] → AgentExecutor
3. 工具实现:vector_tool.py、vector_graph_tool.py、graph_cypher_tool.py
- vector_tool.py → 调用 vector_chain.get_results()
- vector_graph_tool.py → 调用 vector_graph_chain.get_results()
- graph_cypher_tool.py → 调用 graph_cypher_chain.get_results()
4. Chain 实现:vector_chain.py、vector_graph_chain.py、graph_cypher_chain.py
这三个文件结构几乎一样,都包含:
- Neo4j 连接初始化
- Chain 组装
- get_results() 函数
- vector_chain.py - 纯向量检索链
关键代码 :
- 第 68-70 行 :从 st.secrets 读取 Neo4j 配置
- 第 76-84 行 : Neo4jVector.from_existing_index() → 初始化 Neo4j 向量存储
- 第 112-124 行 : RetrievalQAWithSourcesChain.from_chain_type() → 组装 Chain
流程 :用户问题 → 向量化 → 从 Neo4j 找相似 Chunk → 传给 LLM 回答
- vector_graph_chain.py - 向量 + 图增强
关键代码 :
- 第 60-82 行 : retrieval_query - 这是核心!不仅找相似 Chunk,还通过图遍历找关联的 Company、Manager 等!
- 第 88-97 行 : Neo4jVector.from_existing_index() ,但多传了 retrieval_query
- 第 126-138 行 :同样用 RetrievalQAWithSourcesChain 组装
流程 :用户问题 → 向量化 → 找相似 Chunk → 通过图遍历扩展上下文(Company、Manager 等)→ 传给 LLM 回答
- graph_cypher_chain.py - 纯图查询(Text-to-Cypher)
关键代码 :
- 第 75-81 行 : Neo4jGraph() - 初始化图连接
- 第 84-102 行 : GraphCypherQAChain.from_llm() - 组装 Chain,用两个 LLM:
- cypher_llm :把自然语言翻译成 Cypher
- qa_llm :根据 Cypher 查询结果回答问题
流程 :用户问题 → cypher_llm 翻译成 Cypher → 执行 Cypher 查询 Neo4j → qa_llm 根据结果回答
流程图:
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ 🖥️ 用户浏览器 (Streamlit) │
│ ┌───────────────────────────────────────────────────────────────────────────────┐ │
│ │ 用户输入框:"What companies are in the filings?" │ │
│ └───────────────────────────────────┬───────────────────────────────────────────┘ │
└──────────────────────────────────────┼─────────────────────────────────────────────┘
│
│ 1️⃣ 用户输入
│
▼
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ 📄 rag_demo/main.py │
│ ┌───────────────────────────────────────────────────────────────────────────────┐ │
│ │ Line 90-92: rag_agent.get_results(user_input) │ │
│ └───────────────────────────────────┬───────────────────────────────────────────┘ │
└──────────────────────────────────────┼─────────────────────────────────────────────┘
│
│ 2️⃣ 调用 Agent
│
▼
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ 🤖 rag_demo/rag_agent.py (ReAct Agent) │
│ ┌───────────────────────────────────────────────────────────────────────────────┐ │
│ │ Tools Available: │ │
│ │ [1] vector-tool ← 对应 vector_chain.py │ │
│ │ [2] vector-graph-tool ← 对应 vector_graph_chain.py │ │
│ │ [3] graph-cypher-tool ← 对应 graph_cypher_chain.py │ │
│ │ │ │
│ │ LLM (DeepSeek) 分析问题,决定用哪个 Tool! │ │
│ │ (比如问题涉及计数 → 选 graph-cypher-tool) │ │
│ └───────────────────────────────────┬───────────────────────────────────────────┘ │
└──────────────────────────────────────┼─────────────────────────────────────────────┘
│
│ 3️⃣ 选一个 Tool 调用
│
▼
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ ⛓️ rag_demo/*_chain.py (选其中一个) │
│ │
│ ┌─────────────┐ ┌──────────────────┐ ┌─────────────────────┐ │
│ │vector_chain │ │vector_graph_chain│ │graph_cypher_chain │ │
│ │(纯向量) │ │(向量+图增强) │ │(Text-to-Cypher) │ │
│ └──────┬──────┘ └────────┬─────────┘ └──────────┬──────────┘ │
│ │ │ │ │
│ │ │ │ │
│ 向量化问题→找相似 Chunk│ 向量化问题→找相似 Chunk │ 问题→翻译成 Cypher │
│ │ │ →图遍历扩展上下文(Company,│ →执行 Cypher 查询 Neo4j │
│ │ │ Manager等) │ │
│ │ │ │ │
│ └──────────────────┴───────────────────────┘ │
│ │ │
│ │ 4️⃣ 所有 Chain 都会调用 Neo4j │
│ ▼ │
│ ┌───────────────────────────────────────────────────────────────────────────────┐ │
│ │ Neo4j 连接初始化 (在每个 *_chain.py 文件里) │ │
│ │ - vector_chain.py: Neo4jVector (第76-84行) │ │
│ │ - graph_cypher_chain.py: Neo4jGraph (第75-81行) │ │
│ └───────────────────────────────────┬───────────────────────────────────────────┘ │
└──────────────────────────────────────┼─────────────────────────────────────────────┘
│
│ 5️⃣ 从 Neo4j 取回结果
│
▼
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ 🧠 LLM (DeepSeek) │
│ ┌───────────────────────────────────────────────────────────────────────────────┐ │
│ │ 根据 Neo4j 检索结果,生成最终答案 │ │
│ └───────────────────────────────────┬───────────────────────────────────────────┘ │
└──────────────────────────────────────┼─────────────────────────────────────────────┘
│
│ 6️⃣ 返回答案
│
▼
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ 🖥️ 用户浏览器 (Streamlit) 显示答案! │
└─────────────────────────────────────────────────────────────────────────────────────┘
总结:
1. 入口在哪?
- 前端入口 : main.py 的用户输入框
- 逻辑入口 : rag_agent.py 的 get_results() 函数(被 main.py 第 90 行调用)
2. Neo4j 连接在哪初始化?
每个 Chain 自己初始化 ,不是全局共享的:
- vector_chain.py 第 76-84 行: Neo4jVector.from_existing_index()
- vector_graph_chain.py 第 88-97 行: Neo4jVector.from_existing_index() (有 retrieval_query)
- graph_cypher_chain.py 第 75-81 行: Neo4jGraph()
3. LangChain Chain 怎么组装?
- vector_chain.py 第 112-124 行: RetrievalQAWithSourcesChain.from_chain_type()
- graph_cypher_chain.py 第 84-102 行: GraphCypherQAChain.from_llm()
- rag_agent.py 第 47-57 行:把三个 Tool 包装成 ReAct Agent
4. Tool、Chain、Agent 的关系?
Tool (vector_tool) → 包装 Chain
(vector_chain)
Tool (graph_cypher_tool) → 包装 Chain
(graph_cypher_chain)
Agent (AgentExecutor) → 拥有这三个 Tool,由 LLM 决定用哪个
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)