用Neo4j构建数据库语义图谱,优化Text2SQL效果
用Neo4j构建数据库语义图谱,优化Text2SQL效果
作者:威辰新创
在大模型驱动的智能数据时代,Text2SQL的准确性严重依赖对表结构和表间关系的理解。传统方法依赖Prompt工程或Schema描述,效果不稳定。
今天,我将带你用Neo4j构建"数据库语义图谱",让大模型"看得懂关系",显著提升SQL生成准确率!
核心概念
数据库语义图谱:将MySQL的表结构、字段信息和表间关系,以图数据库的形式进行存储和表示。每个表是一个节点,表之间的关系是连接线,让大模型能够直观地理解数据库的语义关系。
准备工作
在开始之前,请确保准备好以下环境和工具:
必需软件
- Docker(用于运行Neo4j)
- Python 3.7+
- MySQL数据库
Python依赖
pip install pymysql py2neo
数据库配置
# MySQL配置
MYSQL_CONFIG = {
"host": "localhost",
"port": 13006,
"user": "root",
"password": "your_password", # 替换为你的密码
"database": "text2sql_db",
"charset": "utf8mb4",
}
# Neo4j配置
NEO4J_URI = "bolt://localhost:7687"
NEO4J_USER = "neo4j"
NEO4J_PASSWORD = "your_password" # 替换为你的密码
步骤详解
步骤一:启动Neo4j服务
首先,我们需要启动Neo4j图数据库服务:
docker run -d \
--name neo4j-apoc \
-p 7474:7474 \
-p 7687:7687 \
-v ./volume/neo4j/data:/data \
-v ./volume/neo4j/plugins:/plugins \
-e apoc.export.file.enabled=true \
-e apoc.import.file.enabled=true \
-e apoc.import.file.use_neo4j_config=true \
-e NEO4J_AUTH=neo4j/neo4j123 \
neo4j:5.26.11-ubi9
避坑指南:
- 确保7474和7687端口未被占用
- 首次启动后,可通过http://localhost:7474访问Neo4j浏览器
步骤二:建立数据库连接
创建数据库连接函数,这是后续所有操作的基础:
from py2neo import Graph
import pymysql
def connect_mysql():
return pymysql.connect(**MYSQL_CONFIG)
def connect_neo4j():
return Graph(NEO4J_URI, auth=(NEO4J_USER, NEO4J_PASSWORD))
重要提示:在实际使用前,请务必修改配置中的密码信息。
步骤三:自动提取MySQL表结构
这个函数会自动扫描数据库,提取所有表的结构信息:
def get_tables_from_database(connection):
"""自动扫描数据库,提取表名、字段、主键/外键标记"""
tables = {}
with connection.cursor() as cursor:
cursor.execute("SHOW TABLES")
table_names = [row[0] for row in cursor.fetchall()]
for table_name in table_names:
cursor.execute(f"SHOW COLUMNS FROM {table_name}")
columns = cursor.fetchall()
fields = []
for col in columns:
field_name = col[0]
key_type = col[3] # PRI=主键, MUL=外键候选
if key_type == "PRI":
fields.append(f"{field_name} [主键]")
elif key_type == "MUL":
fields.append(f"{field_name} [外键]")
else:
fields.append(field_name)
tables[table_name] = {"name": table_name, "fields": fields}
return tables
优势:无需手动维护字段列表,自动感知数据库变更!
步骤四:定义表间业务关系
自动提取无法识别业务逻辑关系,需要人工补充:
RELATIONSHIPS = [
{
"from_table": "t_customers",
"to_table": "t_sales_orders",
"description": "客户创建销售订单",
"field_relation": "customer_id → order.customer_id",
},
{
"from_table": "t_sales_orders",
"to_table": "t_order_details",
"description": "订单包含多个明细项",
"field_relation": "order_id → detail.order_id",
},
{
"from_table": "t_products",
"to_table": "t_order_details",
"description": "产品属于订单明细",
"field_relation": "product_id → detail.product_id",
},
]
技巧:description用自然语言描述,方便大模型理解!
步骤五:构建Neo4j图谱
现在,我们将表结构和关系写入Neo4j:
首先创建约束,防止重复节点:
def create_constraints(graph):
graph.run("CREATE CONSTRAINT IF NOT EXISTS FOR (t:Table) REQUIRE t.name IS UNIQUE")
print("✅ 节点唯一约束已创建")
然后创建表节点:
def create_table_nodes(graph, tables):
for table_name, info in tables.items():
graph.run(
"""
MERGE (t:Table {name: $name})
SET t.label = $label, t.fields = $fields
""",
name=info["name"],
label=table_name,
fields=info["fields"]
)
print("✅ 表节点创建完成!共创建 %d 个表节点" % len(tables))
最后创建表关系:
def create_table_relationships(graph):
for rel in RELATIONSHIPS:
graph.run(
"""
MATCH (from:Table {name: $from_table})
MATCH (to:Table {name: $to_table})
MERGE (from)-[r:REFERENCES {
description: $description,
field_relation: $field_relation
}]->(to)
""",
from_table=rel["from_table"],
to_table=rel["to_table"],
description=rel["description"],
field_relation=rel["field_relation"]
)
print("✅ 表关系创建完成!共创建 %d 条关系" % len(RELATIONSHIPS))
步骤六:一键运行主函数
将所有功能整合到主函数中,实现一键构建:
def main():
print("🚀 开始构建Text2SQL语义图谱...")
mysql_conn = connect_mysql()
neo4j_graph = connect_neo4j()
try:
# 步骤1:获取表结构
tables = get_tables_from_database(mysql_conn)
print(f"📊 检测到 {len(tables)} 张数据表")
# 步骤2:清空旧数据(谨慎操作!)
print("🗑️ 清空Neo4j中的旧数据...")
neo4j_graph.delete_all()
# 步骤3:创建约束
create_constraints(neo4j_graph)
# 步骤4:创建表节点
create_table_nodes(neo4j_graph, tables)
# 步骤5:创建表关系
create_table_relationships(neo4j_graph)
print("🎉 图谱构建完成!现在可用Cypher查询或供大模型调用")
except Exception as e:
print(f"❌ 构建失败: {str(e)}")
raise
finally:
mysql_conn.close()
print("🔌 数据库连接已关闭")
if __name__ == "__main__":
main()
成果验证
构建完成后,我们可以查询图谱来验证结果:
def test_get_table_relationships():
"""从Neo4j图数据库中查询预定义表之间的REFERENCES关系"""
graph = connect_neo4j()
table_names = ["t_customers", "t_sales_orders", "t_products", "t_order_details"]
query = """
MATCH (t1:Table)-[r:REFERENCES]-(t2:Table)
WHERE t1.name IN $table_names
AND t2.name IN $table_names
AND t1.name < t2.name
RETURN
t1.name AS from_table,
r.field_relation AS relationship,
t2.name AS to_table
"""
result = graph.run(query, table_names=table_names).data()
print("查询结果:", result)
return result
如果一切正常,你应该能看到类似这样的输出:
查询结果: [
{'from_table': 't_customers', 'relationship': 'customer_id → order.customer_id', 'to_table': 't_sales_orders'},
{'from_table': 't_order_details', 'relationship': 'order_id → detail.order_id', 'to_table': 't_sales_orders'},
{'from_table': 't_order_details', 'relationship': 'product_id → detail.product_id', 'to_table': 't_products'}
]
下一步学习建议
恭喜你成功构建了数据库语义图谱!接下来可以:
- 集成到大模型应用:将Neo4j图谱作为知识库,增强Text2SQL的准确性
- 学习Cypher查询语言:更深入地查询和操作图数据
- 探索高级功能:如图算法、路径查找等
动手实践
现在轮到你啦!按照上面的步骤动手试试看,相信你会收获满满。如果在实践中遇到任何问题,或者有成功的经验想要分享,欢迎在评论区留言交流!
记住:最好的学习方式就是动手实践。开始你的图数据库之旅吧!