LLM之RAG实战(五十一)| 使用python和Cypher解析PDF数据,并加载到Neo4j数据库
一、必备条件:
- python语言
- Neo4j数据库
- python库:neo4j、llmsherpa、glob、dotenv
二、代码:
from llmsherpa.readers import LayoutPDFReader
from neo4j import GraphDatabase
import uuid
import hashlib
import os
import glob
from datetime import datetime
import time
from dotenv import load_dotenv
# Load environment variables
path = "/home/QA/Neo4j_Stage1/.env"
load_dotenv(path)
# Neo4j configuration
NEO4J_URL = os.environ["NEO4J_URI"]
NEO4J_USER = "neo4j"
NEO4J_PASSWORD = os.environ["NEO4J_PASSWORD"]
NEO4J_DATABASE = "neo4j"
# File location for PDFs
file_location = '/home/QA/Neo4j_Stage1/PDFs'
# Initialize Neo4j
def initialiseNeo4j():
cypher_schema = [
"CREATE CONSTRAINT sectionKey IF NOT EXISTS FOR (c:Section) REQUIRE (c.key) IS UNIQUE;",
"CREATE CONSTRAINT chunkKey IF NOT EXISTS FOR (c:Chunk) REQUIRE (c.key) IS UNIQUE;",
"CREATE CONSTRAINT documentKey IF NOT EXISTS FOR (c:Document) REQUIRE (c.url_hash) IS UNIQUE;",
"CREATE CONSTRAINT tableKey IF NOT EXISTS FOR (c:Table) REQUIRE (c.key) IS UNIQUE;",
"CALL db.index.vector.createNodeIndex('chunkVectorIndex', 'Embedding', 'value', 1536, 'COSINE');"
]
driver = GraphDatabase.driver(NEO4J_URL, database=NEO4J_DATABASE, auth=(NEO4J_USER, NEO4J_PASSWORD))
with driver.session() as session:
for cypher in cypher_schema:
session.run(cypher)
driver.close()
# Ingest document into Neo4j
def ingestDocumentNeo4j(doc, doc_location):
cypher_pool = [
"MERGE (d:Document {name: $doc_name_val}) ON CREATE SET d.url = $doc_url_val RETURN d;",
"MERGE (p:Section {key: $doc_name_val+'|'+$block_idx_val+'|'+$title_hash_val}) ON CREATE SET p.page_idx = $page_idx_val, p.title_hash = $title_hash_val, p.block_idx = $block_idx_val, p.title = $title_val, p.tag = $tag_val, p.level = $level_val RETURN p;",
"MATCH (d:Document {name: $doc_name_val}) MATCH (s:Section {key: $doc_name_val+'|'+$block_idx_val+'|'+$title_hash_val}) MERGE (d)<-[:HAS_DOCUMENT]-(s);",
"MATCH (s1:Section {key: $doc_name_val+'|'+$parent_block_idx_val+'|'+$parent_title_hash_val}) MATCH (s2:Section {key: $doc_name_val+'|'+$block_idx_val+'|'+$title_hash_val}) MERGE (s1)<-[:UNDER_SECTION]-(s2);",
"MERGE (c:Chunk {key: $doc_name_val+'|'+$block_idx_val+'|'+$sentences_hash_val}) ON CREATE SET c.sentences = $sentences_val, c.sentences_hash = $sentences_hash_val, c.block_idx = $block_idx_val, c.page_idx = $page_idx_val, c.tag = $tag_val, c.level = $level_val RETURN c;",
"MATCH (c:Chunk {key: $doc_name_val+'|'+$block_idx_val+'|'+$sentences_hash_val}) MATCH (s:Section {key:$doc_name_val+'|'+$parent_block_idx_val+'|'+$parent_hash_val}) MERGE (s)<-[:HAS_PARENT]-(c);",
"MERGE (t:Table {key: $doc_name_val+'|'+$block_idx_val+'|'+$name_val}) ON CREATE SET t.name = $name_val, t.doc_name = $doc_name_val, t.block_idx = $block_idx_val, t.page_idx = $page_idx_val, t.html = $html_val, t.rows = $rows_val RETURN t;",
"MATCH (t:Table {key: $doc_name_val+'|'+$block_idx_val+'|'+$name_val}) MATCH (s:Section {key: $doc_name_val+'|'+$parent_block_idx_val+'|'+$parent_hash_val}) MERGE (s)<-[:HAS_PARENT]-(t);",
"MATCH (t:Table {key: $doc_name_val+'|'+$block_idx_val+'|'+$name_val}) MATCH (s:Document {name: $doc_name_val}) MERGE (s)<-[:HAS_PARENT]-(t);"
]
driver = GraphDatabase.driver(NEO4J_URL, database=NEO4J_DATABASE, auth=(NEO4J_USER, NEO4J_PASSWORD))
with driver.session() as session:
doc_name_val = os.path.basename(doc_location)
doc_url_val = doc_location
cypher = cypher_pool[0]
session.run(cypher, doc_name_val=doc_name_val, doc_url_val=doc_url_val)
for sec in doc.sections():
sec_title_val = sec.title
sec_title_hash_val = hashlib.md5(sec_title_val.encode("utf-8")).hexdigest()
sec_tag_val = sec.tag
sec_level_val = sec.level
sec_page_idx_val = sec.page_idx
sec_block_idx_val = sec.block_idx
if sec_tag_val != 'table':
cypher = cypher_pool[1]
session.run(cypher, page_idx_val=sec_page_idx_val, title_hash_val=sec_title_hash_val, title_val=sec_title_val, tag_val=sec_tag_val, level_val=sec_level_val, block_idx_val=sec_block_idx_val, doc_name_val=doc_name_val)
sec_parent_val = str(sec.parent.to_text())
if sec_parent_val == "None":
cypher = cypher_pool[2]
session.run(cypher, page_idx_val=sec_page_idx_val, title_hash_val=sec_title_hash_val, doc_name_val=doc_name_val, block_idx_val=sec_block_idx_val)
else:
sec_parent_title_hash_val = hashlib.md5(sec_parent_val.encode("utf-8")).hexdigest()
sec_parent_page_idx_val = sec.parent.page_idx
sec_parent_block_idx_val = sec.parent.block_idx
cypher = cypher_pool[3]
session.run(cypher, page_idx_val=sec_page_idx_val, title_hash_val=sec_title_hash_val, block_idx_val=sec_block_idx_val, parent_page_idx_val=sec_parent_page_idx_val, parent_title_hash_val=sec_parent_title_hash_val, parent_block_idx_val=sec_parent_block_idx_val, doc_name_val=doc_name_val)
for chk in doc.chunks():
chunk_block_idx_val = chk.block_idx
chunk_page_idx_val = chk.page_idx
chunk_tag_val = chk.tag
chunk_level_val = chk.level
chunk_sentences = "\n".join(chk.sentences)
if chunk_tag_val != 'table':
chunk_sentences_hash_val = hashlib.md5(chunk_sentences.encode("utf-8")).hexdigest()
cypher = cypher_pool[4]
session.run(cypher, sentences_hash_val=chunk_sentences_hash_val, sentences_val=chunk_sentences, block_idx_val=chunk_block_idx_val, page_idx_val=chunk_page_idx_val, tag_val=chunk_tag_val, level_val=chunk_level_val, doc_name_val=doc_name_val)
chk_parent_val = str(chk.parent.to_text())
if chk_parent_val != "None":
chk_parent_hash_val = hashlib.md5(chk_parent_val.encode("utf-8")).hexdigest()
chk_parent_page_idx_val = chk.parent.page_idx
chk_parent_block_idx_val = chk.parent.block_idx
cypher = cypher_pool[5]
session.run(cypher, sentences_hash_val=chunk_sentences_hash_val, block_idx_val=chunk_block_idx_val, parent_hash_val=chk_parent_hash_val, parent_block_idx_val=chk_parent_block_idx_val, doc_name_val=doc_name_val)
for tb in doc.tables():
page_idx_val = tb.page_idx
block_idx_val = tb.block_idx
name_val = 'block#' + str(block_idx_val) + '_' + tb.name
html_val = tb.to_html()
rows_val = len(tb.rows)
cypher = cypher_pool[6]
session.run(cypher, block_idx_val=block_idx_val, page_idx_val=page_idx_val, name_val=name_val, html_val=html_val, rows_val=rows_val, doc_name_val=doc_name_val)
table_parent_val = str(tb.parent.to_text())
if table_parent_val != "None":
table_parent_hash_val = hashlib.md5(table_parent_val.encode("utf-8")).hexdigest()
table_parent_page_idx_val = tb.parent.page_idx
table_parent_block_idx_val = tb.parent.block_idx
cypher = cypher_pool[7]
session.run(cypher, name_val=name_val, block_idx_val=block_idx_val, parent_page_idx_val=table_parent_page_idx_val, parent_hash_val=table_parent_hash_val, parent_block_idx_val=table_parent_block_idx_val, doc_name_val=doc_name_val)
else:
cypher = cypher_pool[8]
session.run(cypher, name_val=name_val, block_idx_val=block_idx_val, doc_name_val=doc_name_val)
print(f'\'{doc_name_val}\' Done! Summary: ')
print('#Sections: ' + str(len(doc.sections())))
print('#Chunks: ' + str(len(doc.chunks())))
print('#Tables: ' + str(len(doc.tables())))
driver.close()
# Parse PDFs and ingest into Neo4j
def parseAndIngestPDFs():
pdf_files = glob.glob(file_location + '/*.pdf')
print(f'#PDF files found: {len(pdf_files)}!')
pdf_reader = LayoutPDFReader("https://readers.llmsherpa.com/api/document/developer/parseDocument?renderFormat=all")
startTime = datetime.now()
for pdf_file in pdf_files:
doc = pdf_reader.read_pdf(pdf_file)
ingestDocumentNeo4j(doc, pdf_file)
print(f'Total time: {datetime.now() - startTime}')
# Initialize Neo4j
initialiseNeo4j()
# Parse PDFs and ingest into Neo4j
parseAndIngestPDFs()
三、代码解释
3.1 设置
- 导入Neo4j环境变量
- 设置Neo4j唯一key
3.2 初始化Neo4j
- 建立与 Neo4j 的连接并创建必要的约束以确保数据完整性。
3.3 提取文档内容
- 抽取PDFsection、块和表格数据
- 使用 Cypher 查询在 Neo4j 图形中创建和链接节点
3.4 解析PDF内容
-
查找指定目录中的所有 PDF 文件;
-
使用 LayoutPDFReader 解析每个 PDF;
-
将解析后的数据加入到Neo4j数据库中;
相关文章:

LLM之RAG实战(五十一)| 使用python和Cypher解析PDF数据,并加载到Neo4j数据库
一、必备条件: python语言Neo4j数据库python库:neo4j、llmsherpa、glob、dotenv 二、代码: from llmsherpa.readers import LayoutPDFReaderfrom neo4j import GraphDatabaseimport uuidimport hashlibimport osimport globfrom datetime …...
力扣-数组-01两数之和
解析 遍历i和第i1,两个for循环查就可以,时间复杂度是 代码 class Solution { public:vector<int> twoSum(vector<int>& nums, int target) {vector<int> ansewer;bool flag false;for(int i 0;i < nums.size(); i){for(in…...

Flutter中的网络请求图片存储为缓存,与定制删除本地缓存
Flutter中的网络请求图片存储为缓存,与定制删除本地缓存 1:封装请求图片函数 2:访问的图片都会转为本地缓存,当相同的请求url,会在本地调用图片 3:本地缓存管理【windows与andriod已经测试】【有页面】【有…...

保障移动应用安全:多层次安全策略应对新兴威胁
在数字化时代,移动应用的安全问题变得越来越重要。随着网络威胁的不断升级,确保移动应用的安全性不仅是保护敏感数据的关键,也是维护用户信任的基础。为了应对复杂的安全挑战,企业必须采取先进的技术和多层次的安全策略࿰…...

【Linux】函数
一、函数 1、创建函数 如果定义了同名函数,则新定义的函数就会覆盖原先的定义的函数,而且在运行时不会报错。 创建函数的语法: 方法1:使用关键字function function name { commands } shell脚本中的函数名不能重复 方法2&#x…...
Maven中管理SNAPSHOT版本含义及作用
在开发过程中突然产生了一个疑问:IDEA中 maven deploy的依赖包的版本号,比如 1.0.0-SNAPSHOT是在哪配置的?在远程仓库中的版本和这个有关系吗 ? 在 Maven 中,-SNAPSHOT 后缀是用于标识项目版本为快照(Snapshot…...

win10 VS2019上libtorch库配置过程
win10 VS2019上libtorch库配置过程 0 引言1 获取libtorch2 在VS上配置使用libtorch库3 结语 0 引言 💻💻AI一下💻💻 libtorch库是一个用于深度学习的C库,是PyTorch的官方C前端。它提供了用于构建和训练深度学习模…...

【计算机网络】课程 实验二 交换机基本配置和VLAN 间路由实现
实验二 交换机基本配置和VLAN 间路由实现 一、实验目的 1.了解交换机的管理方式。 2.掌握通过Console接口对交换机进行配置的方法。 3.掌握交换机命令行各种模式的区别,能够使用各种帮助信息以及命令进行基本的配置。 4&…...
Oracle Dataguard(主库为单节点)配置详解(4):将主库复制到备库并启动同步
Oracle Dataguard(主库为单节点)配置详解(4):将主库复制到备库并启动同步 目录 Oracle Dataguard(主库为单节点)配置详解(4):将主库复制到备库并启动同步一、…...

OpenCL(贰):浅析CL内核程序接口函数
目录 1.前言 2.获取平台信息 1.cl_int类型 2.cl_platform_id类型 3.clGetPlatformIDs():查询系统OpenCL平台数量或获取具体的平台信息 4.clGetPlatformInfo():查询指定OpenCL平台的信息,例如平台名称、供应商、版本等 3.设置OpenCL上下文…...
Leetcode 3407. Substring Matching Pattern
Leetcode 3407. Substring Matching Pattern 1. 解题思路2. 代码实现 题目链接:3407. Substring Matching Pattern 1. 解题思路 这一题是一道leetcode easy的题目,照说应该没啥的,不过实际我做的时候在这里卡了一下,所以还是拿…...

学英语学压测:02jmeter组件-测试计划和线程组ramp-up参数的作用
📢📢📢:先看关键单词,再看英文,最后看中文总结,再回头看一遍英文原文,效果更佳!! 关键词 Functional Testing功能测试[ˈfʌŋkʃənəl ˈtɛstɪŋ]Sample样…...

Vue笔记-001-声明式渲染
https://cn.vuejs.org/tutorial/#step-2https://cn.vuejs.org/tutorial/#step-2 Vue 单文件组件 (Single-File Component,缩写为 SFC) 单文件组件是一种可复用的代码组织形式,它将从属于同一个组件的 HTML、CSS 和 JavaScript 封装在使用 .vue 后缀的文件…...
26考研资料分享 百度网盘
26考研资料分享考研资料合集 百度网盘(仅供参考学习) 基础班: 通过网盘分享的文件:2026【考研英语】等3个文件 链接: https://pan.baidu.com/s/1Q6rvKop3sWiL9zBHs87kAQ?pwd5qnn 提取码: 5qnn --来自百度网盘超级会员v3的分享…...
.NET 8 + Ocelot + Consul 实现代理网关、服务发现
.NET 8 Ocelot Consul 实现代理网关、服务发现 本文环境:.NET 8 Ocelot 23.4.2 Consul 1.7.14.6 1 实现网关 分别创建3个WebApi工程:OcelotGw、TestGwAService、TestGwBService;在OcelotGw工程中安装Ocelot包:Install-Packag…...
使用 Nginx 轻松处理跨域请求(CORS)
使用 Nginx 轻松处理跨域请求(CORS) 在现代 Web 开发中,跨域资源共享(CORS)是一种重要的机制,用于解决浏览器的同源策略限制。CORS 允许服务器声明哪些来源可以访问其资源,从而确保安全性与可用…...

【LeetCode Hot100 二分查找】搜索插入位置、搜索二维矩阵、搜索旋转排序数组、寻找两个正序数组的中位数
二分查找 搜索插入位置搜索二维矩阵在排序数组中查找元素的第一个和最后一个位置寻找旋转排序数组中的最小值搜索旋转排序数组寻找两个正序数组的中位数(hard) 搜索插入位置 给定一个排序数组和一个目标值,在数组中找到目标值,并…...
使用MediaPipe Face Mesh 面部动作检测
一、技术选型 OpenCV(Open Source Computer Vision Library) 用于视频流捕捉、图像预处理和基本图像处理操作。 MediaPipe 提供高效的人脸检测与关键点提取功能(Face Mesh)。 Python 作为后端开发语言,整合上述库进行…...
【Vue】<script setup>和 <script>区别是什么?在使用时的写法区别?
<script setup> 是 Vue 3 引入的一种新的脚本语法,它提供了一种更简洁和声明式的方式来编写组件逻辑。它是为了解决传统 <script> 标签在 Vue 单文件组件(SFC)中的一些局限性而设计的。 <script setup> 与 <script>…...

微服务框架,Http异步编程中,如何保证数据的最终一致性
一、背景 在微服务框架下,跨服务之间的调用,当遇到操作耗时或者量大的情况,我们一般会采用异步编程实现。 本文出现的问题是:异步回调过来时,却未查询到数据库中的任务,导致未能正常处理回调。 下面是当…...

GC1808:高性能24位立体声音频ADC芯片解析
1. 芯片简介 GC1808 是一款24位立体声音频模数转换器(ADC),支持96kHz采样率,集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器,适用于家庭影院、蓝牙音箱等场景。 核心特性 高精度:24位分辨率,…...

YOLOv8n行人检测实战:从数据集准备到模型训练
YOLOv8n行人检测实战:从数据集准备到模型训练 一、为什么选择YOLOv8?二、环境准备2.1 环境配置解析 三、安装Ultralytics框架四、数据集准备与理解4.1 数据集下载4.2 数据集结构4.3 YOLO标签格式解析 五、数据集可视化:理解标注数据5.1 可视化…...
使用Python和Flask构建简单的机器学习API
在机器学习项目中,将模型部署为一个Web API是一种常见的需求。这样可以方便地将模型集成到其他应用程序中,例如移动应用、Web应用或其他后端服务。Flask是一个轻量级的Python Web框架,非常适合用于构建简单的API。本文将通过一个具体的例子&a…...
【拓扑剪枝+深搜剪枝/计数】2024睿抗-章鱼图的判断
题目描述 对于无向图 G ( V , E ) G(V,E) G(V,E),我们将有且只有一个环的、大于 2 2 2 个顶点的无向连通图称之为章鱼图,因为其形状像是一个环(身体)带着若干个树(触手),故得名。 给定一个…...
两轮自平衡机器人建模、LQR控制与仿真分析
以下是一个针对两轮自平衡机器人(平衡车) 的完整建模、控制设计与仿真分析报告,包含详细的理论推导、控制算法实现及Python仿真代码。 两轮自平衡机器人建模、LQR控制与仿真分析 1. 引言 两轮自平衡机器人是一种典型的欠驱动、非线性、不稳定系统,其动力学特性与倒立摆高度…...
【Prompt实战】国际翻译小组
本文原创作者:姚瑞南 AI-agent 大模型运营专家/音乐人/野生穿搭model,先后任职于美团、猎聘等中大厂AI训练专家和智能运营专家岗;多年人工智能行业智能产品运营及大模型落地经验,拥有AI外呼方向国家专利与PMP项目管理证书。&#…...
Vue.js 组件:深入理解与实践
Vue.js 组件:深入理解与实践 引言 随着前端技术的不断发展,Vue.js 作为一种流行的前端框架,因其简洁、易学、高效的特点受到越来越多开发者的青睐。在Vue.js中,组件是构建用户界面的基石。本文将深入探讨Vue.js组件的概念、特性、创建方式以及在实际开发中的应用,帮助读…...
Claude vs ChatGPT vs Gemini:功能对比、使用体验、适合人群
随着AI应用全面进入生产力场景,市面上的主流AI对话工具也进入“三国杀”时代: Claude(Anthropic):新锐崛起,语言逻辑惊艳,Opus 模型被称为 GPT-4 杀手ChatGPT(OpenAI)&a…...
C#对象扩展方法:提升对象操作的灵活性与效率
C#对象扩展方法:提升对象操作的灵活性与效率 在C#编程中,我们经常需要对对象进行各种操作,如获取对象属性信息、转换对象格式、复制对象等。通过扩展方法,我们可以为现有类型添加新的功能,而无需修改原始类型的代码。…...

IM即时通讯软件,构建企业局域网内安全协作
安全与权限:协同办公的企业级保障 在协同办公场景中,BeeWorks 将安全机制贯穿全流程。文件在局域网内传输与存储时均采用加密处理,企业网盘支持水印预览、离线文档权限回收等功能,防止敏感资料外泄;多人在线编辑文档时…...