使用 LlamaParse 進行 PDF 解析并創建知識圖譜

此 Python 筆記本提供了有關利用 LlamaParse 從 PDF 文檔中提取信息并隨后將提取的內容存儲到 Neo4j 圖形數據庫中的綜合指南。本教程在設計時考慮到了實用性,適合對文檔處理、信息提取和圖形數據庫技術感興趣的開發人員、數據科學家和技術愛好者。

該筆記本電腦的主要特點:

  1. 設置環境:逐步說明如何設置 Python 環境,包括安裝必要的庫和工具,例如 LlamaParse 和 Neo4j 數據庫驅動程序。

  2. PDF 文檔處理:演示如何使用 LlamaParse 讀取 PDF 文檔,提取相關信息(例如文本、表格和圖像),并將這些信息轉換為適合數據庫插入的結構化格式。

  3. 文檔圖模型:設計有效圖模型的指南,該模型表示從 PDF 文檔中提取的關系和實體,確保查詢和分析的最佳結構。

  4. 在 Neo4j 中存儲提取的數據:詳細的代碼示例展示了如何從 Python 連接到 Neo4j 數據庫,根據提取的數據創建節點和關系,以及執行 Cypher 查詢來填充數據庫。

  5. 生成和存儲文本嵌入:使用過去創建的程序通過 OpenAI API 調用生成文本嵌入,并將嵌入存儲為 Neo4j 中的向量。

  6. 查詢和??分析數據:用于檢索和分析存儲數據的 Cypher 查詢示例,說明 Neo4j 如何發現隱藏在 PDF 內容中的見解和關系。

  7. 結論:有關處理 PDF、設計圖形模式和優化 Neo4j 查詢的最佳實踐的提示,以及針對在此過程中遇到的潛在問題的常見故障排除建議。

請注意,對于此示例,版本是必需的llama_index >=0.10.4。如果pip install --upgrade <package_name>不起作用,您可以pip uninstall <package_name>再次使用并安裝所需的軟件包。

1.搭建環境

pip?install?-qU?llama-index?llama-index-core?llama-index-embeddings-mistralai?llama-parse?neo4j
Note: you may need to restart the kernel to use updated packages.
#下載測試文件
!wget?"https://www.dropbox.com/scl/fi/g5ojyzk4m44hl7neut6vc/chinese_pdf.pdf?rlkey=45reu51kjvdvic6zucr8v9sh3&dl=1"?-O?chinese_pdf.pdf

LlamaParse簡介

LlamaParse 是由 LlamaIndex 創建的一項技術,專門用于高效地解析和表示PDF文件,以便通過 LlamaIndex 框架進行高效檢索和上下文增強,特別適用于復雜的PDF文檔。它基于RAG(Rule-based Approach with Grammar)技術,能夠準確地提取文本、圖像、表格等元素,同時保持良好的性能。這項技術的設計初衷是為了處理那些包含嵌入式對象(如表格和圖形)的復雜文檔,這類文檔的處理在以往往往是個挑戰。通過與 LlamaIndex 的直接整合,LlamaParse不僅能夠支持對這些復雜、半結構化文檔的解析,還能夠在檢索時提供支持,從而讓用戶能夠回答之前難以解決的復雜問題。

LlamaParse 的核心優勢在于它的專有解析技術,這使得它能夠理解和處理PDF文件中的復雜結構。此外,由于它與LlamaIndex 的緊密整合,用戶可以非常方便地將解析后的數據用于增強檢索和上下文理解,從而大大提高了信息檢索的效率和準確性。

LlamaParse 默認將 PDF 轉換為 Markdown,文檔的內容可以準確的解析出來。但LlamaCloud 官網因為不能設置解析文檔的語言,默認只能識別英文的文檔,中文的解析識別需要在 Python 代碼中指定。

2.PDF文檔處理

我們需要 OpenAI 和 LlamaParse API 密鑰來運行該項目。

我們將使用 Python 代碼展示 LlamaParse,在開始之前,你將需要一個 API 密鑰。它是免費的。你可以從下圖中看到設置密鑰的鏈接,因此現在單擊該鏈接并設置您的 API 密鑰。由于我使用 OpenAI 進行 LLM 和嵌入,因此我也需要獲取 OpenAI API 密鑰。

llamaParse_API_key
llamaParse_API_key
#?llama-parse?is?async-first,?running?the?async?code?in?a?notebook?requires?the?use?of?nest_asyncio
import?nest_asyncio
nest_asyncio.apply()

import?os
#?API?access?to?llama-cloud
os.environ["LLAMA_CLOUD_API_KEY"]?=?"llx-Pd9FqzqbITfp7KXpB0YHWngqXK4GWZvB5BSAf9IoiNDBeie4"

#?Using?OpenAI?API?for?embeddings/llms
#os.environ["OPENAI_API_KEY"]?=?"sk-OK5mvOSKVeRokboDB1eHrIuifAcUc6wAqU82ZgRVJMAg4tJ3"
os.environ["MISTRAL_API_KEY"]?=?"q9ebyLLL3KoZTLAeb8I81doRLZK5SXNO"
pip?install?-qU?llama-index-llms-mistralai?llama-index-embeddings-mistralai
Note: you may need to restart the kernel to use updated packages.
from?llama_index.llms.mistralai?import?MistralAI
from?llama_index.embeddings.mistralai?import?MistralAIEmbedding
from?llama_index.core?import??VectorStoreIndex
from?llama_index.core?import?Settings

EMBEDDING_MODEL??=?"mistral-embed"
GENERATION_MODEL?=?"open-mistral-7b"

llm?=?MistralAI(model=GENERATION_MODEL)

Settings.llm?=?llm

使用全新的“LlamaParse”PDF閱讀器進行PDF解析

我們還比較了兩種不同的檢索/查詢引擎策略:

  1. 使用原始 Markdown 文本作為節點來構建索引,并應用簡單的查詢引擎來生成結果;
  2. 用于MarkdownElementNodeParser解析LlamaParse輸出 Markdown 結果并構建遞歸檢索器查詢引擎以進行生成。

有一些參數值得關注:

  • result_type 選項僅限于 "text" 和 "markdown" 。 這里我們選擇 Markdown 格式輸出,因為它將很好地保留結構化信息。
  • num_workers 設置工作線程的數量。一般來說,我們可以根據需要解析的文件數量來設定工作線程的數量。 (最大值為 10 )
    • 配置工作線程的數量:你可以根據需要解析的文件數量來設定工作線程的數量。這樣做可以讓你根據任務的規模來優化資源的使用和提高處理效率。
    • 根據文件數量設定:通常,你會希望設置的工作線程數量與你打算解析的文件數量相匹配。例如,如果你有5個文件需要解析,那么設置5個工作線程可能是合理的,這樣可以確保每個文件都有一個專門的線程來處理。
    • 最大限制:LlamaParse對于工作線程的數量有一個最大限制,這里是設置為10。這意味著你最多可以同時設置10個工作線程來并行處理解析任務。這個限制可能是為了確保系統的穩定性和防止資源過度消耗。
from?llama_parse?import?LlamaParse
from?llama_parse.base?import?ResultType,?Language
pdf_file_name?=?'./chinese_pdf.pdf'

parser=?LlamaParse(
????result_type=ResultType.MD,
????language=Language.SIMPLIFIED_CHINESE,
????verbose=True,
????num_workers=1,
)

documents?=?parser.load_data(pdf_file_name)
Started parsing the file under job_id 2bd5a318-08f2-4b12-b9f3-424b8238bd96

執行以上代碼,會啟動一個PDF解析的異步任務。

解析完我們查看一下解析后的結果,這里分別輸出文檔中的兩部分內容。從結果可以看到,質量還是比較高的。

#?Check?loaded?documents

print(f"Number?of?documents:?{len(documents)}")

for?doc?in?documents:
????print(doc.doc_id)
????print(doc.text[:500]?+?'...')
Number of documents: 1
093b2e8e-03b2-4a07-aeb0-270adcb4f9ba
# CAICT pBEiwrHze BR+E  No.20230 8數據要素白皮書 (2023 年)中 國 信 息 通 信 研 究院 2023年9月
---
# 版權聲明本白皮書版權屬于中國信息通信研究院,并受法律保護。轉載、摘編或利用其它方式使用本白皮書文字或者觀點的,應注明“來源:中國信息通信研究院”。違反上述聲明者,本院將追究其相關法律責任。CaICT
---
# 前言2022年12月,中共中央、國務院印發《關于構建數據基礎制度更好發揮數據要素作用的意見》(下稱“數據二十條”),這是我國首部從生產要素高度系統部署數據要素價值釋放的國家級專項政策文件。“數據二十條”確立了數據基礎制度體系的“四梁八柱”,在數據要素發展進程中具有重大意義。...
#?Parse?the?documents?using?MarkdownElementNodeParser

from?llama_index.core.node_parser?import?MarkdownElementNodeParser

node_parser?=?MarkdownElementNodeParser(llm=llm,?num_workers=8)

nodes?=?node_parser.get_nodes_from_documents(documents)
3it [00:00, 3851.52it/s]
100%|█████████████████████████████████████████████| 3/3 [00:11<00:00,  3.74s/it]
#?Convert?nodes?into?objects

base_nodes,?objects?=?node_parser.get_nodes_and_objects(nodes)
import?json


#?Check?parsed?node?objects?

print(f"Number?of?nodes:?{len(base_nodes)}")
Number of nodes: 36
TABLE_REF_SUFFIX?=?'_table_ref'
TABLE_ID_SUFFIX??=?'_table'

#?Check?parsed?objects?

print(f"Number?of?objects:?{len(objects)}")

for?node?in?objects:?
????print(f"id:{node.node_id}")
????print(f"hash:{node.hash}")
????print(f"parent:{node.parent_node}")
????print(f"prev:{node.prev_node}")
????print(f"next:{node.next_node}")

????#?Object?is?a?Table
????if?node.node_id[-1?*?len(TABLE_REF_SUFFIX):]?==?TABLE_REF_SUFFIX:

????????if?node.next_node?is?not?None:
????????????next_node?=?node.next_node
????????
????????????print(f"next_node?metadata:{next_node.metadata}")
????????????print(f"next_next_node:{next_next_nod_id}")

????????????obj_metadata?=?json.loads(str(next_node.json()))

????????????print(str(obj_metadata))

????????????print(f"def:{obj_metadata['metadata']['table_df']}")
????????????print(f"summary:{obj_metadata['metadata']['table_summary']}")


????print(f"next:{node.next_node}")
????print(f"type:{node.get_type()}")
????print(f"class:{node.class_name()}")
????print(f"content:{node.get_content()[:200]}")
????print(f"metadata:{node.metadata}")
????print(f"extra:{node.extra_info}")
????
????node_json?=?json.loads(node.json())

????print(f"start_idx:{node_json.get('start_char_idx')}")
????print(f"end_idx:{node_json['end_char_idx']}")

????if?'table_summary'?in?node_json:?
????????print(f"summary:{node_json['table_summary']}")

????print("=====================================")???
Number of objects: 3
id:1ace071a-4177-4395-ae42-d520095421ff
hash:e593799944034ed3ff7d2361c0f597cd67f0ee6c43234151c7d80f84407d4c5f
parent:None
prev:node_id='9694e60e-6988-493b-89c3-2533ff1adcd2' node_type=<ObjectType.TEXT: '1'> metadata={} hash='898f4b8eb4de2dbfafa9062f479df61668c6a7604f2bea5b9937b70e234ba746'
next:node_id='9c71f897-f510-4b8c-a876-d0d8ab55e004' node_type=<ObjectType.TEXT: '1'> metadata={'table_df': "{'一、數據要素再認識': {0: '(一)國家戰略全方位布局數據要素發展', 1: '(二)人工智能發展對數據供給提出更高要求', 2: '(三)數據要素概念聚焦于數據價值釋放', 3: '二、資源:分類推進數據要素探索已成為共識', 4: '(一)不同類別數據資源面臨不同關鍵問題', 5: '(二)授權運營促進公共數據供給提質增效', 6: '(三)會計入表推動企業數據價值“顯性化”', 7: '(四)權益保護仍是個人數據開發利用主線', 8: '三、主體:企業政府雙向發力推進可持續探索', 9: '(一)企業側:數據管理與應用能力是前提', 10: '(二)政府側:建立公平高效的機制是關鍵', 11: '四、市場:場內外結合推動數據資源最優配置', 12: '(一)數據流通存在多層次多樣化形態', 13: '(二)場外交易活躍,場內交易多點突破', 14: '(三)多措并舉破除數據流通障礙', 15: '五、技術:基于業務需求加速創新與體系重構', 16: '(一)數據技術隨業務要求不斷演進', 17: '(二)數據要素時代新技術不斷涌現', 18: '(三)數據要素技術體系重構加速', 19: '六、趨勢與展望', 20: '參考文獻'}, '1': {0: 1, 1: 3, 2: 5, 3: 7, 4: 7, 5: 11, 6: 15, 7: 18, 8: 21, 9: 21, 10: 26, 11: 29, 12: 30, 13: 33, 14: 35, 15: 37, 16: 37, 17: 38, 18: 42, 19: 42, 20: 46}}", 'table_summary': 'Title: Data Element Development and Utilization in National Strategic Perspective\n\nSummary: This table discusses various aspects of data element development and utilization, including strategic layout, resource classification, subject involvement, market dynamics, technological advancements, and trends. It also highlights key issues in different categories of data resources, the role of authorization and operation in improving public data supply, the importance of data management and application capabilities for enterprises, the need for a fair and efficient mechanism on the government side, and the significance of equity protection in personal data development and utilization. The table concludes with a section on market and technological trends.\n\nTable ID: Not provided in the context.\n\nThe table should be kept as it provides valuable insights into the development and utilization of data elements from a national strategic perspective.,\nwith the following columns:\n'} hash='48055467b0febd41fcce52d02d72730f8ea97c7a7905749afb557b0dcecef7c2'
next:node_id='9c71f897-f510-4b8c-a876-d0d8ab55e004' node_type=<ObjectType.TEXT: '1'> metadata={'table_df': "{'一、數據要素再認識': {0: '(一)國家戰略全方位布局數據要素發展', 1: '(二)人工智能發展對數據供給提出更高要求', 2: '(三)數據要素概念聚焦于數據價值釋放', 3: '二、資源:分類推進數據要素探索已成為共識', 4: '(一)不同類別數據資源面臨不同關鍵問題', 5: '(二)授權運營促進公共數據供給提質增效', 6: '(三)會計入表推動企業數據價值“顯性化”', 7: '(四)權益保護仍是個人數據開發利用主線', 8: '三、主體:企業政府雙向發力推進可持續探索', 9: '(一)企業側:數據管理與應用能力是前提', 10: '(二)政府側:建立公平高效的機制是關鍵', 11: '四、市場:場內外結合推動數據資源最優配置', 12: '(一)數據流通存在多層次多樣化形態', 13: '(二)場外交易活躍,場內交易多點突破', 14: '(三)多措并舉破除數據流通障礙', 15: '五、技術:基于業務需求加速創新與體系重構', 16: '(一)數據技術隨業務要求不斷演進', 17: '(二)數據要素時代新技術不斷涌現', 18: '(三)數據要素技術體系重構加速', 19: '六、趨勢與展望', 20: '參考文獻'}, '1': {0: 1, 1: 3, 2: 5, 3: 7, 4: 7, 5: 11, 6: 15, 7: 18, 8: 21, 9: 21, 10: 26, 11: 29, 12: 30, 13: 33, 14: 35, 15: 37, 16: 37, 17: 38, 18: 42, 19: 42, 20: 46}}", 'table_summary': 'Title: Data Element Development and Utilization in National Strategic Perspective\n\nSummary: This table discusses various aspects of data element development and utilization, including strategic layout, resource classification, subject involvement, market dynamics, technological advancements, and trends. It also highlights key issues in different categories of data resources, the role of authorization and operation in improving public data supply, the importance of data management and application capabilities for enterprises, the need for a fair and efficient mechanism on the government side, and the significance of equity protection in personal data development and utilization. The table concludes with a section on market and technological trends.\n\nTable ID: Not provided in the context.\n\nThe table should be kept as it provides valuable insights into the development and utilization of data elements from a national strategic perspective.,\nwith the following columns:\n'} hash='48055467b0febd41fcce52d02d72730f8ea97c7a7905749afb557b0dcecef7c2'
type:3
class:IndexNode
content:Title: Data Element Development and Utilization in National Strategic PerspectiveSummary: This table discusses various aspects of data element development and utilization, including strategic layout
metadata:{'col_schema': ''}
extra:{'col_schema': ''}
start_idx:816
end_idx:1319
=====================================

3. 解析文檔的圖模型

無論使用哪種PDF解析工具,將結果作為知識圖譜保存到Neo4j中,圖模式實際上是相當一致的。

document_graph_schema
document_graph_schema

在本項目中,將使用類似的圖模型。讓我們從圖數據庫模式定義開始:

  • 關鍵屬性的唯一性約束
  • 嵌入向量索引
from?neo4j?import?GraphDatabase

#?Local?Neo4j?instance
NEO4J_URL?=?"bolt://localhost:7687"
#?Remote?Neo4j?instance?on?AuraDB
#NEO4J_URL?=?"http://localhost:7474"
NEO4J_USER?=?"neo4j"
NEO4J_PASSWORD?=?"langchain"
NEO4J_DATABASE?=?"neo4j"

def?initialiseNeo4jSchema():
????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?VECTOR?INDEX?`chunkVectorIndex`?IF?NOT?EXISTS?FOR?(e:Embedding)?ON?(e.value)?OPTIONS?{?indexConfig:?{`vector.dimensions`:?1536,?`vector.similarity_function`:?'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()
#?create?constraints?and?indexes

initialiseNeo4jSchema()

4. 在 Neo4j 中存儲提取的數據

driver?=?GraphDatabase.driver(NEO4J_URL,?database=NEO4J_DATABASE,?auth=(NEO4J_USER,?NEO4J_PASSWORD))

#?================================================
#?1)?Save?documents

print("Start?saving?documents?to?Neo4j...")
i?=?0
with?driver.session()?as?session:
????for?doc?in?documents:
????????cypher?=?"MERGE?(d:Document?{url_hash:?$doc_id})?ON?CREATE?SET?d.url=$url;"
????????session.run(cypher,?doc_id=doc.doc_id,?url=doc.doc_id)
????????i?=?i?+?1
????session.close()

print(f"{i}?documents?saved.")

#?================================================
#?2)?Save?nodes

print("Start?saving?nodes?to?Neo4j...")

i?=?0
with?driver.session()?as?session:
????for?node?in?base_nodes:?

????????#?>>1?Create?Section?node
????????cypher??=?"MERGE?(c:Section?{key:?$node_id})\n"
????????cypher?+=?"?FOREACH?(ignoreMe?IN?CASE?WHEN?c.type?IS?NULL?THEN?[1]?ELSE?[]?END?|\n"
????????cypher?+=?"?????SET?c.hash?=?$hash,?c.text=$content,?c.type=$type,?c.class=$class_name,?c.start_idx=$start_idx,?c.end_idx=$end_idx?)\n"
????????cypher?+=?"?WITH?c\n"
????????cypher?+=?"?MATCH?(d:Document?{url_hash:?$doc_id})\n"
????????cypher?+=?"?MERGE?(d)<-[:HAS_DOCUMENT]-(c);"

????????node_json?=?json.loads(node.json())

????????session.run(cypher,?node_id=node.node_id,?hash=node.hash,?content=node.get_content(),?type='TEXT',?class_name=node.class_name()
??????????????????????????,?start_idx=node_json['start_char_idx'],?end_idx=node_json['end_char_idx'],?doc_id=node.ref_doc_id)

????????#?>>2?Link?node?using?NEXT?relationship

????????if?node.next_node?is?not?None:?#?and?node.next_node.node_id[-1*len(TABLE_REF_SUFFIX):]?!=?TABLE_REF_SUFFIX:
????????????cypher??=?"MATCH?(c:Section?{key:?$node_id})\n"????#?current?node?should?exist
????????????cypher?+=?"MERGE?(p:Section?{key:?$next_id})\n"????#?previous?node?may?not?exist
????????????cypher?+=?"MERGE?(p)<-[:NEXT]-(c);"

????????????session.run(cypher,?node_id=node.node_id,?next_id=node.next_node.node_id)

????????if?node.prev_node?is?not?None:??#?Because?tables?are?in?objects?list,?so?we?need?to?link?from?the?opposite?direction
????????????cypher??=?"MATCH?(c:Section?{key:?$node_id})\n"????#?current?node?should?exist
????????????cypher?+=?"MERGE?(p:Section?{key:?$prev_id})\n"????#?previous?node?may?not?exist
????????????cypher?+=?"MERGE?(p)-[:NEXT]->(c);"

????????????if?node.prev_node.node_id[-1?*?len(TABLE_ID_SUFFIX):]?==?TABLE_ID_SUFFIX:
????????????????prev_id?=?node.prev_node.node_id?+?'_ref'
????????????else:
????????????????prev_id?=?node.prev_node.node_id

????????????session.run(cypher,?node_id=node.node_id,?prev_id=prev_id)

????????i?=?i?+?1
????session.close()

print(f"{i}?nodes?saved.")

#?================================================
#?3)?Save?objects

print("Start?saving?objects?to?Neo4j...")

i?=?0
with?driver.session()?as?session:
????for?node?in?objects:???????????????
????????node_json?=?json.loads(node.json())

????????#?Object?is?a?Table,?then?the?????_ref_table?object?is?created?as?a?Section,?and?the?table?object?is?Chunk
????????if?node.node_id[-1?*?len(TABLE_REF_SUFFIX):]?==?TABLE_REF_SUFFIX:
????????????if?node.next_node?is?not?None:??#?here?is?where?actual?table?object?is?loaded
????????????????next_node?=?node.next_node

????????????????obj_metadata?=?json.loads(str(next_node.json()))

????????????????cypher??=?"MERGE?(s:Section?{key:?$node_id})\n"
????????????????cypher?+=?"WITH?s?MERGE?(c:Chunk?{key:?$table_id})\n"
????????????????cypher?+=?"?FOREACH?(ignoreMe?IN?CASE?WHEN?c.type?IS?NULL?THEN?[1]?ELSE?[]?END?|\n"
????????????????cypher?+=?"?????SET?c.hash?=?$hash,?c.definition=$content,?c.text=$table_summary,?c.type=$type,?c.start_idx=$start_idx,?c.end_idx=$end_idx?)\n"
????????????????cypher?+=?"?WITH?s,?c\n"
????????????????cypher?+=?"?MERGE?(s)?<-[:UNDER_SECTION]-?(c)\n"
????????????????cypher?+=?"?WITH?s?MATCH?(d:Document?{url_hash:?$doc_id})\n"
????????????????cypher?+=?"?MERGE?(d)<-[:HAS_DOCUMENT]-(s);"

????????????????session.run(cypher,?node_id=node.node_id,?hash=next_node.hash,?content=obj_metadata['metadata']['table_df'],?type='TABLE'
??????????????????????????????????,?start_idx=node_json['start_char_idx'],?end_idx=node_json['end_char_idx']
??????????????????????????????????,?doc_id=node.ref_doc_id,?table_summary=obj_metadata['metadata']['table_summary'],?table_id=next_node.node_id)
????????????????
????????????if?node.prev_node?is?not?None:
????????????????cypher??=?"MATCH?(c:Section?{key:?$node_id})\n"????#?current?node?should?exist
????????????????cypher?+=?"MERGE?(p:Section?{key:?$prev_id})\n"????#?previous?node?may?not?exist
????????????????cypher?+=?"MERGE?(p)-[:NEXT]->(c);"

????????????????if?node.prev_node.node_id[-1?*?len(TABLE_ID_SUFFIX):]?==?TABLE_ID_SUFFIX:
????????????????????prev_id?=?node.prev_node.node_id?+?'_ref'
????????????????else:
????????????????????prev_id?=?node.prev_node.node_id
????????????????
????????????????session.run(cypher,?node_id=node.node_id,?prev_id=prev_id)
????????????????
????????i?=?i?+?1
????session.close()

#?================================================
#?4)?Create?Chunks?for?each?Section?object?of?type?TEXT
#?If?there?are?changes?to?the?content?of?TEXT?section,?the?Section?node?needs?to?be?recreated

print("Start?creating?chunks?for?each?TEXT?Section...")

with?driver.session()?as?session:

????cypher??=?"MATCH?(s:Section)?WHERE?s.type='TEXT'?\n"
????cypher?+=?"WITH?s?CALL?{\n"
????cypher?+=?"WITH?s?WITH?s,?split(s.text,?'\n')?AS?para\n"
????cypher?+=?"WITH?s,?para,?range(0,?size(para)-1)?AS?iterator\n"
????cypher?+=?"UNWIND?iterator?AS?i?WITH?s,?trim(para[i])?AS?chunk,?i?WHERE?size(chunk)?>?0\n"
????cypher?+=?"CREATE?(c:Chunk?{key:?s.key?+?'_'?+?i})?SET?c.type='TEXT',?c.text?=?chunk,?c.seq?=?i?\n"
????cypher?+=?"CREATE?(s)?<-[:UNDER_SECTION]-(c)?}?IN?TRANSACTIONS?OF?500?ROWS?;"
????
????session.run(cypher)
????
????session.close()


print(f"{i}?objects?saved.")

print("=================DONE====================")

driver.close()

Start saving documents to Neo4j...
1 documents saved.
Start saving nodes to Neo4j...
36 nodes saved.
Start saving objects to Neo4j...
Start creating chunks for each TEXT Section...
3 objects saved.
=================DONE====================

5. 生成和存儲文本嵌入

from?mistralai.client?import?MistralClient


def?get_embedding(client,?text,?model):
????response?=?client.embeddings.create(
????????????????????input=text,
????????????????????model=model,
????????????????)
????return?response.data[0].embedding

def?LoadEmbedding(label,?property):
????driver?=?GraphDatabase.driver(NEO4J_URL,?auth=(NEO4J_USER,?NEO4J_PASSWORD),?database=NEO4J_DATABASE)
????mistralai_client?=?MistralClient?(api_key?=?os.environ["MISTRAL_API_KEY"])

????with?driver.session()?as?session:
????????#?get?chunks?in?document,?together?with?their?section?titles
????????result?=?session.run(f"MATCH?(ch:{label})?RETURN?id(ch)?AS?id,?ch.{property}?AS?text")
????????#?call?OpenAI?embedding?API?to?generate?embeddings?for?each?proporty?of?node
????????#?for?each?node,?update?the?embedding?property
????????count?=?0
????????for?record?in?result:
????????????id?=?record["id"]
????????????text?=?record["text"]
????????????
????????????#?For?better?performance,?text?can?be?batched
????????????embedding_batch_response?=?mistralai_client.embeddings(model=EMBEDDING_MODEL,input=text,?)
????????????#print(embedding_batch_response.data[0])
????????????#print(embedding_batch_response.data[0].embedding)
????????????#?key?property?of?Embedding?node?differentiates?different?embeddings
????????????cypher?=?"CREATE?(e:Embedding)?SET?e.key=$key,?e.value=$embedding,?e.model=$model"
????????????cypher?=?cypher?+?"?WITH?e?MATCH?(n)?WHERE?id(n)?=?$id?CREATE?(n)?-[:HAS_EMBEDDING]->?(e)"
????????????session.run(cypher,key=property,?embedding=embedding_batch_response.data[0].embedding,?id=id,?model=EMBEDDING_MODEL)?
????????????count?=?count?+?1

????????session.close()
????????
????????print("Processed?"?+?str(count)?+?"?"?+?label?+?"?nodes?for?property?@"?+?property?+?".")
????????return?count

#?For?smaller?amount?(<2000)?of?text?data?to?embed
LoadEmbedding("Chunk",?"text")
Processed 368 Chunk nodes for property @text.368

6. 查詢文檔知識圖譜

讓我們打開 Neo4j 瀏覽器來檢查加載的文檔圖。

在文本框中輸入MATCH (n:Section) RETURN n并運行它,我們將看到文檔的一系列部分。通過點擊并展開一個Section節點,我們可以看到它所連接的Chunk節點。 knowgraph_section

如果“Section”節點的類型為“type” TEXT,則它具有一組“Chunk”節點,每個節點在“text”屬性中存儲一個段落。 knowgraph_section_text

如果一個Section節點的類型為TABLE,那么它只有一個Chunk節點,其中text屬性存儲表內容的摘要,definition屬性存儲表的內容。

每個Chunk節點都連接一個Embedding節點,該節點存儲Chunk節點文本內容的嵌入。在這個項目的開始,我們定義了一個向量索引,以便我們能夠更有效地執行相似性搜索。

由于部分節點的文本內容可能超出嵌入模型強制執行的標記長度限制(8k,~ 5k 個單詞),因此通過將內容拆分為段落可以幫助糾正此限制,并且嵌入更相關的文本,因為它們出現在相同的文本中段落。

七、結論

LlamaParse 是一款功能強大的 PDF 文檔解析工具,擅長以卓越的效率處理復雜的結構化和非結構化數據。其先進的算法和直觀的 API 有助于從 PDF 中無縫提取文本、表格、圖像和元數據,將通常具有挑戰性的任務轉變為簡化的流程。

在 Neo4j 中將提取的數據存儲為圖表進一步放大了優勢。通過在圖形數據庫中表示數據實體及其關系,用戶可以發現使用傳統關系數據庫很難(如果不是不可能)檢測到的模式和連接。 Neo4j 的圖形模型提供了一種自然直觀的方式來可視化復雜關系,增強了進行復雜分析和得出可行見解的能力。

一致的文檔知識圖模式使得與下游任務的其他工具集成變得更加容易,例如使用GenAI Stack(LangChain 和 Streamlit)構建檢索增強生成。

LlamaParse 的提取功能與 Neo4j 基于圖形的存儲和分析相結合,為數據驅動決策開辟了新的可能性。它允許更細致地理解數據關系、高效的數據查詢以及隨著數據集規模和復雜性不斷增長而擴展的能力。這種協同作用不僅加速了提取和分析過程,還有助于采用更明智和更具戰略性的數據管理方法。

目前還沒有辦法把文件中的內容作為節點準確識別,這是后續要研究的方向。

本文由 mdnice 多平臺發布

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/14178.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/14178.shtml
英文地址,請注明出處:http://en.pswp.cn/web/14178.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

可視化大屏,不搞點3D效果,感覺有點對不起觀眾呢。

使用3D模型可以為可視化展現增加更多的維度和真實感&#xff0c;提供更直觀、生動的視覺效果。以下是一些3D模型在可視化展現中的作用&#xff1a; 增強沉浸感&#xff1a;通過使用3D模型&#xff0c;可以讓觀眾感受到更真實的場景和物體&#xff0c;增強他們的沉浸感。這有助…

playwright相關的文章

霍格沃茲測試開發Muller老師 - 個人中心 - 騰訊云開發者社區-騰訊云 霍格沃茲測試開發Muller老師 &#xff1a;

【數組】Leetcode 452. 用最少數量的箭引爆氣球【中等】

用最少數量的箭引爆氣球 有一些球形氣球貼在一堵用 XY 平面表示的墻面上。墻面上的氣球記錄在整數數組 points &#xff0c;其中points[i] [xstart, xend] 表示水平直徑在 xstart 和 xend之間的氣球。你不知道氣球的確切 y 坐標。 一支弓箭可以沿著 x 軸從不同點 完全垂直 地…

golang問題

文章目錄 Go里有哪些數據結構是并發安全的&#xff1f;int類型是并發安全的嗎&#xff1f;為什么int不是并發安全的&#xff1f; Go如何實現一個單例模式&#xff1f;sync.Once是如何實現的&#xff0c;如何不使用sync.Once實現單例模式&#xff1f;Go語言里的map是并發安全的嗎…

Freeswitch-Python3開發

文章目錄 一、Freeswitch如何使用mod_python31.1 Freeswitch和python1.2 Freeswitch版本選擇1.3 Freeswitch編譯mod_python31.3.1 debian安裝python31.3.2 Freeswitch編譯mod_python31.3.3 加載 二、如何編寫腳本2.1 函數的基本框架2.2 基本使用2.2.1 觸發條件2.2.2 默認腳本位…

pycharm更改遠程編輯器設置

pycharm的遠程編輯器可以分為兩個部分&#xff1a;SFTP服務器(用于傳輸文件&#xff09;和命令行&#xff08;用于控制linux&#xff09;系統。那么當創建完成后&#xff0c;如何才能更改其設置呢&#xff1f; 一、遠程SFTP服務器設置 找到導航欄依次點擊tools-deployment-co…

運行vue2項目基本過程

目錄 步驟1 步驟2 步驟3 補充&#xff1a; 解決方法&#xff1a; node-scss安裝失敗解決辦法 步驟1 安裝npm 步驟2 切換淘寶鏡像 #最新地址 淘寶 NPM 鏡像站喊你切換新域名啦! npm config set registry https://registry.npmmirror.com 步驟3 安裝vue-cli npm install…

取消頁面按鈕回車事件

html頁面登錄按鈕 <button class"btn btn-success btn-block" id"btnSubmit" data-loading"正在驗證登錄&#xff0c;請稍候...">登 錄</button>js部分 在回車鍵按下時&#xff0c;阻止默認行為 $(document).keyup(function (event…

采用偽代碼及C代碼演示如何解決脫機最小值問題

采用偽代碼及C代碼演示如何解決脫機最小值問題 問題背景算法設計偽代碼實現C代碼實現證明數組正確性使用不相交集合數據結構最壞情況運行時間的緊確界 問題背景 脫機最小值問題涉及到一個動態集合 &#xff08; T &#xff09; &#xff08;T&#xff09; &#xff08;T&…

并網逆變器學習筆記9---VSG控制

參考文獻&#xff1a;《新型電力系統主動構網機理與技術路徑》 “構網技術一般包含下垂控制&#xff0c;功率同步控制&#xff0c;虛擬同步機控制&#xff0c;直接功率控制&#xff0c;虛擬振蕩器控制 等。其中&#xff0c;虛擬同步機技術&#xff0c;即 VSG&#xff0c;因其物…

藍牙(2):BR/EDR的連接過程;查詢(發現)=》尋呼(連接)=》安全建立=》認證=》pair成功;類比WiFi連接過程。

4.2.1 BR/EDR 流程&#xff1a; 查詢&#xff08;發現&#xff09;》尋呼&#xff08;連接&#xff09;》安全建立》認證》pair成功 4.2.1.1 查詢&#xff08;發現&#xff09;流程Inquiry (discovering) 類比WiFi的probe request/response 藍牙設備使用查詢流程來發現附近的…

Github 2024-05-24 Java開源項目日報 Top10

根據Github Trendings的統計,今日(2024-05-24統計)共有10個項目上榜。根據開發語言中項目的數量,匯總情況如下: 開發語言項目數量Java項目10Java設計模式:提高開發效率的正規化實踐 創建周期:3572 天開發語言:Java協議類型:OtherStar數量:86766 個Fork數量:25959 次關…

探數API統計分享-1949年-2021年中國歷年夏糧產量統計報告

????????中國歷年夏糧產量?&#xff0c;為1949年到2021年我國每年的夏糧產量數據。2021年&#xff0c;我國夏糧產量為14596萬噸&#xff0c;比上年增長2.2%。 數據統計單位為&#xff1a;萬噸 。 我國夏糧產量有多少&#xff1f; 2021年&#xff0c;我國夏糧產量為1…

在Juniper SRX系列防火墻上配置DNS

SRX# set system name-server 17.20.0.11 SRX# show system name-server

vue中v-for的key值怎么使用?如何選擇?

在 Vue 中&#xff0c;v-for 指令用于渲染列表數據。當使用 v-for 時&#xff0c;強烈建議為每一項提供一個唯一的 key 屬性。這個 key 不僅是 Vue 區分節點的標識&#xff0c;也是 Vue 實現列表高效更新的一種機制。 如何使用 key 在 v-for 中&#xff0c;key 應該綁定到列表…

202206青少年軟件編程(Python)等級考試試卷(三級)

第 1 題 【單選題】 下圖所示, 有一個名為"書目.csv"的文件。 小明針對這個文件編寫了 5 行代碼,請問, 代碼運行到最后打印在屏幕上的結果是? ( ) with open(書目.csv, r, encoding=utf-8) as f:for line in f.readlines

適配arm架構國產服務器(銀河麒麟、中科方德)依賴下載

在計算機硬件領域&#xff0c;兩種主流的CPU架構分別是X86和ARM。X86架構&#xff0c;也稱為CISC&#xff08;復雜指令集計算機&#xff09;&#xff0c;主要服務于PC和服務器行業。而ARM架構&#xff0c;代表RISC&#xff08;精簡指令集計算機&#xff09;&#xff0c;則在移動…

利用Axure模板快速設計,可視化大屏信息大屏,含近200例資源和各類部件

模板類別&#xff1a; **通用模板&#xff1a;**提供基礎的布局和設計元素&#xff0c;適用于各種場景。 **行業特定模板&#xff1a;**如農業、醫院、銷售、能源、物流、政府機關等&#xff0c;針對不同行業提供專業模板。 **數據展示模板&#xff1a;**包括大數據駕駛艙、統…

1.1 什么是internet?

什么是Internet&#xff1a;從具體構成角度 節點 主機及其上運行的應用程序路由器、交換機等網絡交換設備 ? 邊&#xff1a;通信鏈路接入網鏈路&#xff1a;主機連接到互聯網的鏈路主干鏈路&#xff1a;路由器間的鏈路 ? 協議 ? 數以億計的、互聯的計算設備: ? 主機 端系…

webgl開發家居設計軟件

WebGL是一種在網頁瀏覽器中渲染3D圖形的JavaScript API&#xff0c;它基于OpenGL ES標準&#xff0c;允許開發者創建和顯示交互式的3D圖形。開發基于WebGL的家居設計軟件可以為用戶提供一種全新的、沉浸式的家居設計體驗。以下是開發此類軟件的一些關鍵步驟和特點。北京木奇移動…