Docling 提供了一种高效自动化方法,能够从文档中自动提取实体与关系,快速构建结构化的知识图谱。本教程将从零开始,带你深入理解知识图谱的核心概念,掌握 Docling 的文档解析能力,并通过实战代码将 PDF 文档转化为可视化的知识网络。
一、知识图谱基础概念与核心价值
知识图谱是一种以节点(Node)和边(Edge)为核心的数据结构,用于表示信息。节点代表现实世界中的实体,例如人物、地点、概念;边则定义实体之间的关联,例如“位于”、“设计”、“出生于”。这种结构化表示方式使数据探索更加直观,能够支持复杂的关联查询,并在搜索引擎、推荐系统、数据集成等领域显著提升决策能力。
二、Docling 如何简化文档预处理流程
传统构建知识图谱需要大量预处理步骤,例如文本清洗、格式转换、实体识别等。而 Docling 能够直接解析包括复杂 PDF 在内的多种文档格式,输出结构化文档内容。它保留了文档的层次关系(如标题、段落、列表),让你可以跳过繁琐的处理管道,直接聚焦于实体与关系的提取。例如,从一段描述“巴黎”和“埃菲尔铁塔”的文本中,Docling 能帮助你快速定位实体与关系,减少人工标注成本,提升最终知识图谱的准确性。
三、实战:从 PDF 到知识图谱
3.1 环境准备
首先创建虚拟环境并安装所需依赖。请确保你的 Python 版本为 3.8 或更高版本。
# preparation
python3 -m venv venv
source venv/bin/activate
pip install --upgrade pip
pip install 'docling[all]'
pip install spacy
pip install networkx
pip install matplotlib
pip install nlp
安装完成后,还需要下载 spaCy 的英文模型,用于命名实体识别:
python -m spacy download en_core_web_sm
3.2 完整代码实现
下面代码将完成三个关键步骤:1)使用 Docling 解析 PDF 并提取文本;2)借助 spaCy 识别实体并构建关系;3)利用 NetworkX 和 Matplotlib 可视化知识图谱。
import json
import logging
import time
from pathlib import Path
import spacy
import networkx as nx
import matplotlib.pyplot as plt
from docling.datamodel.base_models import InputFormat
from docling.datamodel.pipeline_options import (
AcceleratorDevice,
AcceleratorOptions,
PdfPipelineOptions,
)
from docling.document_converter import DocumentConverter, PdfFormatOption
# Load a spaCy language model
nlp = spacy.load("en_core_web_sm")
def extract_text_from_docling_document(docling_document):
"""Extracts text content from a Docling Document object."""
text = docling_document.export_to_text()
return text
def build_knowledge_graph(text):
doc = nlp(text)
graph = nx.Graph()
# Extract entities
for ent in doc.ents:
graph.add_node(ent.text, label=ent.label_)
# Simple relationship extraction (can be improved)
for sent in doc.sents:
for i, token in enumerate(sent):
if token.dep_ in ["nsubj", "dobj"]:
subject = [w for w in token.head.lefts if w.dep_ == "nsubj"]
object_ = [w for w in token.head.rights if w.dep_ == "dobj"]
if subject and object_:
graph.add_edge(subject[0].text, object_[0].text, relation=token.head.lemma_)
elif subject and token.head.lemma_ in ["be", "ha ve"]:
right_children = [child for child in token.head.rights if child.dep_ in ["attr", "acomp"]]
if right_children:
graph.add_edge(subject[0].text, right_children[0].text, relation=token.head.lemma_)
return graph
def visualize_knowledge_graph(graph):
"""Visualizes the knowledge graph."""
pos = nx.spring_layout(graph)
nx.draw(graph, pos, with_labels=True, node_size=3000, node_color="skyblue", font_size=10, font_weight="bold")
edge_labels = nx.get_edge_attributes(graph, 'relation')
nx.draw_networkx_edge_labels(graph, pos, edge_labels=edge_labels)
plt.title("Knowledge Graph from Document")
plt.show()
def main():
logging.basicConfig(level=logging.INFO)
_log = logging.getLogger(__name__) # Initialize the logger here
#nlp = spacy.load("en_core_web_sm") # Load spacy # Removed from here
#input_doc_path = Path("./input/2503.11576v1.pdf")
input_doc_path = Path("./input.pdf")
# 使用 Docling 转换文档
pipeline_options = PdfPipelineOptions()
pipeline_options.do_ocr = False # 如果 PDF 包含扫描文字,可设为 True
converter = DocumentConverter(
format_options={
InputFormat.PDF: PdfFormatOption(pipeline_options=pipeline_options)
}
)
start_time = time.time()
result = converter.convert(input_doc_path)
docling_doc = result.document
_log.info(f"Document converted in {time.time()-start_time:.2f} seconds.")
# 提取文本
text = extract_text_from_docling_document(docling_doc)
# 构建知识图谱
graph = build_knowledge_graph(text)
print(f"Number of nodes: {graph.number_of_nodes()}")
print(f"Number of edges: {graph.number_of_edges()}")
# 打印节点和边详情
print("\nNodes:")
for node, data in graph.nodes(data=True):
print(f" {node}: {data}")
print("\nEdges:")
for u, v, data in graph.edges(data=True):
print(f" ({u}, {v}): {data}")
# 可视化
visualize_knowledge_graph(graph)
if __name__ == "__main__":
main()
3.3 准备测试文档
我们使用大型语言模型(LLM,如 granite)生成一段包含清晰实体与关系的文本,并将其保存为 PDF 文件(例如 input.pdf)。
巴黎市位于法国,以其标志性的埃菲尔铁塔而闻名。它是一处热门旅游目的地。这座铁塔由古斯塔夫・埃菲尔设计。著名科学家玛丽・居里出生于巴黎,她为放射学领域做出了重大贡献。她曾在镭研究所工作。塞纳河流经巴黎。
说明其适用性的原因:
该文本包含多个实体和关系,这些实体和关系可被轻松提取并在知识图谱中呈现:
・实体:巴黎、法国、埃菲尔铁塔、古斯塔夫・埃菲尔、玛丽・居里、镭研究所、塞纳河
・关系:
巴黎位于法国。
巴黎因埃菲尔铁塔而闻名。
埃菲尔铁塔由古斯塔夫・埃菲尔设计。
玛丽・居里出生于巴黎。
玛丽・居里是一位科学家。
玛丽・居里为放射学领域做出了贡献。
玛丽・居里曾在镭研究所工作。
塞纳河流经巴黎。
根据该文本构建的知识图谱会将这些实体表示为节点,将关系表示为边,从而提供信息的结构化呈现。
你可以将上述文本保存为 TXT 文件,然后使用任意工具(如 Word、LaTeX)转换为 PDF,并命名为 input.pdf,放置在代码同级目录的 ./input.pdf 路径下。
3.4 运行结果与分析
执行 main() 函数后,你将看到类似如下的输出:
INFO:__main__:Document converted in 8.63 seconds.
WARNING:docling_core.types.doc.document:Parameter `strict_text` has been deprecated and will be ignored.
Number of nodes: 23
Number of edges: 7
2025-04-23 21:33:52.828 python3[73966:691115] The class 'NSSa vePanel' overrides the method identifier. This method is implemented by class 'NSWindow'
Nodes: [('Paris', {'label': 'GPE'}), ('France', {'label': 'GPE'}), ('Eiffel Tower', {'label': 'FAC'}), ('Gusta ve Eiffel', {'label': 'PERSON'}), ('Marie Curie', {'label': 'PERSON'}), ('the Radium Institute', {'label': 'FAC'}), ('Seine River', {'label': 'LOC'}), ('## Explanation', {'label': 'MONEY'}), ('Radium Institute', {'label': 'ORG'}), ('the Eiffel Tower', {'label': 'LOC'}), ('The Eiffel Tower', {'label': 'LOC'}), ('city', {}), ('renowned', {}), ('It', {}), ('destination', {}), ('Explanation', {}), ('entities', {}), ('this', {}), ('suitable', {}), ('Curie', {}), ('scientist', {}), ('contributions', {}), ('graph', {})]
Edges: [('city', 'renowned', {'relation': 'be'}), ('It', 'destination', {'relation': 'be'}), ('Explanation', 'entities', {'relation': 'contain'}), ('entities', 'graph', {'relation': 'represent'}), ('this', 'suitable', {'relation': 'be'}), ('Curie', 'scientist', {'relation': 'be'}), ('Curie', 'contributions', {'relation': 'make'})]
观察输出可以发现:
- 节点总数 23 个,其中正确识别了主要实体(Paris、France、Eiffel Tower、Gustave Eiffel、Marie Curie 等),但也混入了一些非实体词(如
city、renowned)和格式部分(如## Explanation)。 - 边共 7 条,成功提取了部分关系(如
Curie - scientist的be关系),但缺少理想中“巴黎位于法国”、“埃菲尔铁塔由古斯塔夫·埃菲尔设计”等关键边。
这表明简单的规则依赖句法分析(nsubj/dobj)只能覆盖部分关系,后续可以引入大语言模型(LLM)或更成熟的依存解析算法来提升提取准确率。但无论如何,Docling 已经成功将 PDF 中的文本结构化输出,为后续提取打下了坚实基础。
四、小提示
- PDF 格式影响:如果 PDF 是扫描件(非文本原生),请确保设置
pipeline_options.do_ocr = True,并安装 Tesseract 等 OCR 引擎。 - 关系提取优化:示例代码仅演示了基础规则,实际生产环境可结合
spaCy的实体链接或OpenIE库(如allenai/openie-standalone)获得更丰富的关系三元组。 - 调试用日志:开启
logging.DEBUG可查看 Docling 内部解析细节,便于排查问题。 - 大文档处理:Docling 支持流式处理,对于超长文档可采用
DocumentConverter.create_pipeline()分批转换,避免内存溢出。
五、常见问题
Q1:安装 docling[all] 时出现依赖冲突怎么办?
建议在干净的虚拟环境中安装,并优先使用 Python 3.10 或 3.11。如果仍出现冲突,可以尝试仅安装核心依赖:pip install docling,然后根据报错提示手动补充缺失包(如 torch、transformers)。
Q2:运行代码后得到“FileNotFoundError: ./input.pdf”,如何处理?
请确保 input.pdf 文件位于代码文件 同级目录 下。你也可以修改 input_doc_path = Path("./your_path/your_file.pdf") 为实际路径。此外,PDF 文件必须包含可提取的文本(非纯图片扫描)。
Q3:提取的实体和关系与预期偏差很大,如何改进?
核心原因在于简单的句法规则无法处理所有句式。推荐两种改进方向:
- 使用预训练的 OpenIE 模型:例如
pip install openie并调用openie.extract()从句子中抽取(subject, relation, object)三元组。 - 微调大语言模型(LLM):将 Docling 抽取的文本段落送入 GPT、Gemini 等模型,要求其以 JSON 格式输出实体关系,准确率更高。
Q4:可视化窗口没有弹出,或者 Matplotlib 报错如何处理?
如果你在远程服务器或无图形界面的环境下运行,Matplotlib 无法显示窗口。可以将 plt.show() 替换为 plt.savefig('graph.png') 将图片保存到本地。同时确保系统已安装 tkinter 或使用 %matplotlib inline(如在 Jupyter 中)。
六、总结
通过本教程,你学会了如何借助 Docling 的强大功能从 PDF 中提取结构化文本,再结合 spaCy 与 NetworkX 构建出知识图谱的雏形。尽管基础关系提取仍有局限,但 Docling 已经大幅降低了文档预处理的门槛。后续你可以在此框架上集成更强大的 NLP 模型,实现从任意文档到精准知识图谱的完整自动化管道。
