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 import datetimeimport timefrom dotenv import load_dotenv# Load environment variablespath = "/home/QA/Neo4j_Stage1/.env"load_dotenv(path)# Neo4j configurationNEO4J_URL = os.environ["NEO4J_URI"]NEO4J_USER = "neo4j"NEO4J_PASSWORD = os.environ["NEO4J_PASSWORD"]NEO4J_DATABASE = "neo4j"# File location for PDFsfile_location = '/home/QA/Neo4j_Stage1/PDFs'# Initialize Neo4jdef 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 Neo4jdef 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_locationcypher = 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.titlesec_title_hash_val = hashlib.md5(sec_title_val.encode("utf-8")).hexdigest()sec_tag_val = sec.tagsec_level_val = sec.levelsec_page_idx_val = sec.page_idxsec_block_idx_val = sec.block_idxif 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_idxsec_parent_block_idx_val = sec.parent.block_idxcypher = 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_idxchunk_page_idx_val = chk.page_idxchunk_tag_val = chk.tagchunk_level_val = chk.levelchunk_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_idxchk_parent_block_idx_val = chk.parent.block_idxcypher = 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_idxblock_idx_val = tb.block_idxname_val = 'block#' + str(block_idx_val) + '_' + tb.namehtml_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_idxtable_parent_block_idx_val = tb.parent.block_idxcypher = 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 Neo4jdef 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 Neo4jinitialiseNeo4j()# Parse PDFs and ingest into Neo4jparseAndIngestPDFs()
三、代码解释
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异步编程中,如何保证数据的最终一致性
一、背景 在微服务框架下,跨服务之间的调用,当遇到操作耗时或者量大的情况,我们一般会采用异步编程实现。 本文出现的问题是:异步回调过来时,却未查询到数据库中的任务,导致未能正常处理回调。 下面是当…...
W5100S实战入门:从SPI驱动到网络配置的完整指南
1. 硬件准备与连接指南 第一次拿到W5100S模块时,我盯着那排密密麻麻的引脚有点发懵。这个比指甲盖大不了多少的芯片,居然要承担整个网络通信的重任。不过别担心,跟着我的步骤来,保证你能顺利搞定硬件连接。 必备材料清单ÿ…...
Qwen3-ASR-0.6B保姆级教程:Linux终端直连Web服务+curl命令行调用
Qwen3-ASR-0.6B保姆级教程:Linux终端直连Web服务curl命令行调用 你是不是觉得语音识别模型一定要在网页上点点鼠标才能用?或者觉得部署一个AI服务特别麻烦,需要各种配置和调试? 今天我要分享一个完全不同的思路:直接…...
CentOS 7.9 SNAT/DNAT 详解与 VMware 17 实验全流程【20260412】002篇
文章目录 🖥️ VMware 17.0 Pro模拟SNAT/DNAT完整实验指南 📋 实验环境总体规划 网络拓扑设计 IP地址规划表 VMware网络配置步骤 步骤1:创建自定义虚拟网络 步骤2:创建三台CentOS 7.9虚拟机 🔧 详细配置步骤 1. 系统基础配置 1.1 配置主机名和网络 1.2 配置各虚拟机网络…...
Langchain Agent实战避坑:用通义千问调用高德API,我踩过的异步和工具定义那些坑
Langchain Agent实战避坑指南:异步调用与工具定义的那些坑 在构建基于Langchain的智能代理时,异步调用和工具定义是两个最容易让开发者踩坑的领域。本文将分享我在使用通义千问模型调用高德API过程中遇到的实际问题及其解决方案。 1. 异步调用的常见陷阱…...
Switch 2 第三方扩展坞:适配难题下的新选择
Switch 2 适配难题催生第三方扩展坞新机遇任天堂推出 Switch 2 时更改了控制器连接新系统的无线协议以及通过 USB - C 输出视频的方式,这使得所有第三方制造商都得从头开始研发适配产品。搞清楚如何与 Switch 2 “对话”,并确保在系统更新后仍能保持稳定…...
【关注合作源码】-家政服务管理系统|家政预约|家政平台
博主介绍: 所有项目都配有从入门到精通的安装教程,可二开,提供核心代码讲解,项目指导。 项目配有对应开发文档、解析等 项目都录了发布和功能操作演示视频;项目的界面和功能都可以定制,包安装运行ÿ…...
万字拆解 LLM 运行机制:Token、上下文与采样参数弦
springboot自动配置 自动配置了大量组件,配置信息可以在application.properties文件中修改。 当添加了特定的Starter POM后,springboot会根据类路径上的jar包来自动配置bean(比如:springboot发现类路径上的MyBatis相关类ÿ…...
OpenMatrix 架构解析:基于 Harness 思想的 AI 任务编排系统
引言:AI 编码的信任危机 AI 编码工具已经非常强大,但用户仍然不敢完全信任。为什么? 第一层:AI 补全代码(Copilot)→ 解决「写」的问题 第二层:AI 对话编程(Claude Code࿰…...
Vivado FFT IP核避坑指南:从Matlab数据生成到FPGA验证的完整流程
Vivado FFT IP核实战避坑指南:从Matlab数据生成到FPGA验证的全链路解析 在FPGA信号处理领域,FFT(快速傅里叶变换)是实现频域分析的核心运算单元。Xilinx Vivado提供的FFT IP核虽然功能强大,但在实际工程落地过程中&…...
别再只玩VAE了!用CVAE玩点新花样:可控图像生成与风格迁移实战
解锁CVAE的创意潜能:从可控图像生成到风格迁移的艺术 在生成式AI的世界里,我们常常被那些能够凭空创造图像的模型所震撼。但当你真正开始使用基础的变分自编码器(VAE)时,可能会感到一丝沮丧——生成的图像虽然多样&…...
