2. 数据处理
# 2.1 本地数据加载
SimpleDirectoryReader 是一个简单的本地文件加载器。它会遍历指定目录,并根据文件扩展名自动加载文件(文本内容)。
支持的文件类型:
.csv- comma-separated values.docx- Microsoft Word.epub- EPUB ebook format.hwp- Hangul Word Processor.ipynb- Jupyter Notebook.jpeg,.jpg- JPEG image.mbox- MBOX email archive.md- Markdown.mp3,.mp4- audio and video.pdf- Portable Document Format.png- Portable Network Graphics.ppt,.pptm,.pptx- Microsoft PowerPoint
使用 SimpleDirectoryReader 加载目录下的 PDF 文件:
from llama_index.core import SimpleDirectoryReader
from llama_index.readers.file import PyMuPDFReader
reader = SimpleDirectoryReader(
input_dir="./data", # 目标目录
recursive=False, # 是否递归遍历子目录
required_exts=[".pdf"], # (可选)只读取指定后缀的文件
file_extractor={".pdf": PyMuPDFReader()} # (可选)指定文件读取器,pip install PyMuPDF
)
documents = reader.load_data()
for doc in documents:
print(doc.text)
2
3
4
5
6
7
8
9
10
11
12
更多的 PDF 加载器还有 SmartPDFLoader 和 LlamaParse 等,二者都提供了更丰富的解析能力,包括解析章节与段落结构等。但不是 100% 准确,偶有文字丢失或错位情况,建议根据自身需求详细测试评估。
默认的文件加载器参考地址:https://llamahub.ai/l/readers/llama-index-readers-file (opens new window)
# 2.2 Data Connectors
Data Connectors 用于连接不同数据源的工具或组件,允许应用程序、服务或平台从各种不同的存储系统或数据库中读取、写入或操作数据。这些连接器使得数据流动更为流畅,并且能够在不同的系统之间进行无缝集成。
相关资源:
- 三方服务数据加载器:https://docs.llamaindex.ai/en/stable/module_guides/loading/connector/modules/ (opens new window)
- 更多的加载器可以在 LlamaHub 找到:https://llamahub.ai/ (opens new window)
飞书文档示例
(1)准备飞书文档、飞书开放平台创建应用
参考文档:飞书文档相关权限申请.pdf (opens new window)
(2)安装 llama-index 飞书文档读取器依赖
pip install llama-index-readers-feishu-docs
(3)代码示例
from llama_index.readers.feishu_docs import FeishuDocsReader
# 见说明文档
app_id = "your_app_id"
app_secret = "your_secret"
# https://d8bzmrpxh3.feishu.cn/docx/IVTkdWOgzoIknQx4Yynct6SPnjb?from=from_copylink
# 链接最后的 "IVTkdWOgzoIknQx4Yynct6SPnjb" 为文档 ID
doc_ids = ["IVTkdWOgzoIknQx4Yynct6SPnjb"]
# 定义飞书文档加载器
loader = FeishuDocsReader(app_id, app_secret)
# 加载文档
documents = loader.load_data(document_ids=doc_ids)
# 显示前1000字符
print(documents[0].text[:1000])
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 2.3 TextSplitters 文本切分
对上文本地数据加载中的 documents 进行分割解析:
from llama_index.core import SimpleDirectoryReader
from llama_index.readers.file import PyMuPDFReader
from llama_index.core.node_parser import TokenTextSplitter
reader = SimpleDirectoryReader(
input_dir="./data", # 目标目录
recursive=False, # 是否递归遍历子目录
required_exts=[".pdf"], # (可选)只读取指定后缀的文件
file_extractor={".pdf": PyMuPDFReader()} # (可选)指定文件读取器
)
documents = reader.load_data()
node_parser = TokenTextSplitter(
chunk_size=100, # 每个 chunk 的最大长度
chunk_overlap=50 # chunk 之间重叠长度
)
nodes = node_parser.get_nodes_from_documents(
documents, show_progress=False
)
print(nodes[0].get_content())
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
LlamaIndex 提供了丰富的 TextSplitter,例如:
- SentenceSplitter:在切分指定长度的 chunk 同时尽量保证句子边界不被切断
- CodeSplitter:根据 AST(编译器的抽象句法树)切分代码,保证代码功能片段完整
- SemanticSplitterNodeParser:根据语义相关性将文本切分为片段
# 2.4 NodeParsers 解析有结构的文档
找到一个 Markdown 尝试解析:
from llama_index.readers.file import FlatReader
from llama_index.core.node_parser import MarkdownNodeParser
from pathlib import Path
md_docs = FlatReader().load_data(Path("./data/README.md"))
parser = MarkdownNodeParser()
nodes = parser.get_nodes_from_documents(md_docs)
print(nodes[1].get_content())
2
3
4
5
6
7
8
更多的 NodeParser 包括 HTMLNodeParser、JSONNodeParser 等等。
# 2.5 TextSplitters 和 NodeParsers 的区别
功能定位
TextSplitters:用于将大量文本数据切分成较小的块(chunks),这对于处理较长文本(如长篇文章、PDF 文件等)时非常有用。切分后的块可以更有效地进行进一步处理和分析。
NodeParsers:用于解析结构化文档,通常用于将具有明确结构的文档(如 Markdown、HTML 等)转换为更具语义的"节点"。这些节点通常包含更丰富的元数据或格式信息。
适用场景
TextSplitters:
- 适用于处理没有明确结构或需要通过长度控制来拆分的文本
- 例如,拆分长文档或大量文本为多个小块,以便于后续的处理(如检索、索引等)
- 适用于 PDF、Word 文档等不含复杂格式或结构的文件
NodeParsers:
- 适用于解析结构化或有标记的文档,如 Markdown、HTML、JSON 等
- 这些文档通常包含标题、段落、列表等结构信息,NodeParser 会根据这些信息拆分并生成包含结构的节点
- 例如,Markdown 文档的解析可以将每个段落、标题或列表项提取为独立的节点
# 2.6 索引与检索
在 LlamaIndex 中,索引(Indexing)和检索(Retrieval)是处理文档和数据的核心功能,它们用于优化大规模文本数据的存储、查找与检索过程。
# 常见的索引方式
Token-based Indexing(基于标记的索引):
- 将文档的文本内容分解为小块(chunks)或标记(tokens),然后将每个标记与其所在的文档建立关联
- 这样可以加速对文档中某个特定标记的检索
- 例如,使用
TokenTextSplitter将文档拆分成小块后进行索引
Embedding-based Indexing(基于嵌入的索引):
- 利用自然语言处理模型生成文档或文本块的嵌入向量,并通过这些向量来索引文档
- 这样可以在检索时利用相似度搜索(例如,通过余弦相似度)来找到最相关的文档
- 例如,可以使用 OpenAI 的 Embedding 模型来生成文档嵌入,并使用这些嵌入在索引中查找相似文档
# SimpleVectorStore 内存构建向量库
需要注意的是:LlamaIndex 默认的 Embedding 模型是 OpenAIEmbedding(model="text-embedding-ada-002")
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
from llama_index.core.node_parser import TokenTextSplitter
from llama_index.readers.file import PyMuPDFReader
# 加载 pdf 文档
documents = SimpleDirectoryReader(
input_dir="./data",
required_exts=[".pdf"],
file_extractor={".pdf": PyMuPDFReader()}
).load_data()
# 定义 Node Parser
node_parser = TokenTextSplitter(chunk_size=300, chunk_overlap=100)
# 切分文档
nodes = node_parser.get_nodes_from_documents(documents)
# 构建 index
index = VectorStoreIndex(nodes)
# 获取 retriever
vector_retriever = index.as_retriever(
similarity_top_k=2 # 返回2个结果
)
# 检索
results = vector_retriever.retrieve("Llama2有多少参数")
print(results[0].text)
print()
print(results[1].text)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 自定义向量库:ChromaDB
import chromadb
from chromadb import Settings
from llama_index.core import VectorStoreIndex
from llama_index.vector_stores.chroma import ChromaVectorStore
from llama_index.core import StorageContext
from llama_index.core import SimpleDirectoryReader
from llama_index.readers.file import PyMuPDFReader
from llama_index.core.node_parser import TokenTextSplitter
reader = SimpleDirectoryReader(
input_dir="./data", # 目标目录
recursive=False, # 是否递归遍历子目录
required_exts=[".pdf"], # (可选)只读取指定后缀的文件
file_extractor={".pdf": PyMuPDFReader()} # (可选)指定文件读取器
)
# 读取并解析pdf
documents = reader.load_data()
node_parser = TokenTextSplitter(chunk_size=300, chunk_overlap=100)
nodes = node_parser.get_nodes_from_documents(
documents, show_progress=False
)
# 创建 ChromaDB 实例
chroma_client = chromadb.HttpClient(settings=Settings(allow_reset=True), port=8000)
chroma_client.reset()
chroma_collection = chroma_client.get_or_create_collection("llama_index_demo")
# 创建 ChromaDB VectorStore
vector_store = ChromaVectorStore(chroma_collection=chroma_collection)
storage_context = StorageContext.from_defaults(vector_store=vector_store)
chroma_index = VectorStoreIndex(nodes, storage_context=storage_context)
# 获取 retriever
vector_retriever = chroma_index.as_retriever(similarity_top_k=2)
# 检索
results = vector_retriever.retrieve("Llama2有多少参数")
for result in results:
print(result.node.get_content())
print("--------------------------------------------------")
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# 更多索引与检索方式
LlamaIndex 内置了丰富的检索机制,例如:
关键字检索:
- BM25Retriever:基于 tokenizer 实现的 BM25 经典检索算法
- KeywordTableGPTRetriever:使用 GPT 提取检索关键字
- KeywordTableSimpleRetriever:使用正则表达式提取检索关键字
- KeywordTableRAKERetriever:使用 RAKE 算法提取检索关键字(有语言限制)
RAG-Fusion:QueryFusionRetriever
还支持 KnowledgeGraph、SQL、Text-to-SQL 等等。