52.llama_index-文档存储
内容参考于:图灵AI大模型全栈
LLamaIndex中使用StorageContext来管理存储
LLamaIndex会存储原始数据(Docstore)、索引元数据(IndexStore)、向量数据(VectorStore)、知识图谱(GraphStore)
原始数据存储的是分割完的原始文档
索引元数据存储的是相当于一个目录,通过目录去找文档和向量的映射关系
上方的原始数据(Docstore)、索引元数据(IndexStore)、向量数据(VectorStore)是可以插拔的可以更换存储方式,StorageContext是用来管理上方4个的存储
首先查看官网说明,下图是文档的存储方式
地址:https://developers.llamaindex.ai/python/framework-api-reference/storage/docstore/
如下图红框,可以看到它可以存到Simple(会本地存储)、Readis(内存数据库)、Mongodb(数据库)中
这里使用SimpleDocumentStore,也就是下图红框来管理存储
它会创建下图的5个文件
default__vector_store文件存放向量数据
docstore文件存放文档内容,里面存的就是之前的节点格式的json
graph_store文件存放图数据
image__vector_store文件存放图片信息
index_store文件存放索引
如下图1和3,1是源文档,3是下一个文本节点
代码
# 导入目录文件加载器,用于读取本地文件并封装为 Document 对象 from llama_index.core import SimpleDirectoryReader # 导入句子分割器,用于按语义边界将长文档切分为文本节点(TextNode) from llama_index.core.node_parser import SentenceSplitter # 导入简单文档存储类,内存型文档存储实现,支持节点的增删查改与本地持久化 # 作用:统一管理文本节点/文档的内容与元数据,是索引体系中文本数据的持久化载体 from llama_index.core.storage.docstore import SimpleDocumentStore # 导入存储上下文容器,是 LlamaIndex 存储体系的统一调度入口 # 作用:聚合管理 docstore(文档存储)、vector_store(向量存储)、index_store(索引存储)等所有存储组件 # 提供统一的持久化、加载、初始化能力,避免单独管理各类存储 from llama_index.core import StorageContext # ========== 第一步:加载本地文档 ========== # 通过 SimpleDirectoryReader 加载指定的单个文本文件,返回 Document 对象列表 # input_files:直接指定目标文件路径列表,无需扫描整个目录,适合精准加载少量文件 documents = SimpleDirectoryReader(input_files=["./data_file/小说.txt"]).load_data() # ========== 第二步:文档切分为文本节点 ========== # 实例化默认配置的句子分割器(默认 chunk_size=1024、chunk_overlap=200) # 调用 get_nodes_from_documents 将完整文档按语义边界切分为多个 TextNode 节点 nodes = SentenceSplitter().get_nodes_from_documents(documents) # 打印切分后的节点列表,可查看节点数量与概览信息 print(nodes) # ========== 第三步:创建文档存储并写入节点 ========== # 实例化简单文档存储,默认是内存级存储,数据仅保存在运行内存中 # SimpleDocumentStore 特点:轻量、无外部依赖,基于字典存储节点,支持序列化到本地 JSON 文件 doc_store = SimpleDocumentStore() # 向文档存储中批量添加节点 # 方法名 add_documents 兼容 Document 和 BaseNode 两类对象,节点会以 node_id 为键存入内部字典 doc_store.add_documents(nodes) # ========== 第四步:构建存储上下文容器 ========== # 通过 from_defaults 工厂方法创建存储上下文 # 作用:将我们自定义的 doc_store 注册到存储上下文中统一管理 # 未显式指定的存储组件(如 vector_store、index_store)会自动使用默认的内存实现 storage_context = StorageContext.from_defaults(docstore=doc_store) # ========== 第五步:持久化存储到本地磁盘 ========== # 调用 persist 方法将存储上下文中的所有存储组件序列化到本地目录 # 入参:目标目录路径,若目录不存在会自动创建 # 本示例会在 ./documents 目录下生成 docstore.json 文件,保存所有节点的完整数据 storage_context.persist("./documents") # ========== 第六步:从本地磁盘加载已持久化的存储 ========== # 通过 from_defaults 指定 persist_dir,读取本地持久化文件,重建存储上下文 # 底层会自动解析目录下的各类存储文件,还原 docstore、vector_store 等所有存储组件 new_storage_context = StorageContext.from_defaults(persist_dir="./documents") # 打印文档存储中的所有文档字典 # docstore.docs 是存储的核心数据结构,类型为 Dict[str, BaseNode] # 键为节点 ID(node_id),值为对应的节点完整对象,可直接读取节点文本、元数据等信息 print(new_storage_context.docstore.docs)
使用Mongodb存储,注意要连接外网
Mongodb官网下载地址:https://www.mongodb.com/try/download/community
首先下载Mongodb数据库,官网下载地址是一个msi的安装包,下载完双击运行即可,这里使用Docker下载
如下图配置,然后点击Run就可以了
如果想设置账户密码去问ai,把下图给ai
到这就安装好了Mongodb数据库了,接下来开始使用
首先安装下方的两个库
pip install llama-index-storage-docstore-mongodb pip install pymongo代码运行完就会有数据了,如下图,llama_index代码会自己创建
如下图读取的效果图
如下图红框,它会有三个集合,前面的novel是代码中设置的命名空间
点击下图红框
点击后会出现下图红框的内容,可以看到有embedding(向量)、metadata(元数据)、text(原始文档数据)
如下图data存放的是元数据、原始文档数据
metadata专门用来存储元数据,LlamaIndex自身用的
ref_doc_info就是之前说的目录,它对应一个原始文件,就是说通过SimpleDirectoryReader读取到原始文档后未分块之前它会有一个文档的唯一ID,这个ref_doc_info就把这个唯一ID保存了下来,然后分块后的文档,每一个分块都会带着这个文档的唯一ID,点击下图红框
可以看到这些id
然后复制下图红框的内容
然后来到data里,按CTRL+F搜索,是可以找到的,如下图红框的黄色高亮
代码
# 导入 LlamaIndex 核心组件:目录文件加载器、存储上下文 # SimpleDirectoryReader:批量/单个加载本地文件,封装为 Document 对象 # StorageContext:存储体系统一入口,聚合管理文档存储、向量存储等各类存储组件 from llama_index.core import ( SimpleDirectoryReader, StorageContext ) # 导入句子分割器,用于按语义边界将长文档切分为指定大小的文本节点 from llama_index.core.node_parser import SentenceSplitter # 导入 MongoDB 版本文档存储实现 # 类全称:MongoDocumentStore # 定位:生产级持久化文档存储,基于 MongoDB 数据库存储节点数据,替代内存/本地文件级的 SimpleDocumentStore # 核心优势:支持海量节点持久化、多进程/多服务共享数据、支持查询与索引、适合线上生产环境 # 所属扩展包:llama-index-storage-docstore-mongodb,需单独安装 from llama_index.storage.docstore.mongodb import MongoDocumentStore # ========== 1. 加载本地文档 ========== # 使用 SimpleDirectoryReader 加载指定的单个文本文件,返回 Document 对象列表 # input_files:直接指定目标文件路径列表,无需扫描目录,适合精准加载少量文件 documents = SimpleDirectoryReader( input_files=["./data_file/小说.txt"] ).load_data() # ========== 2. 文档切分为文本节点 ========== # 实例化句子分割器,自定义切分粒度 # chunk_size=512:单个文本节点最大字符数为 512 # chunk_overlap=50:相邻节点首尾重叠 50 个字符,避免跨节点语义断裂 # 调用 get_nodes_from_documents 执行切分,返回 TextNode 列表 nodes = SentenceSplitter( chunk_size=512, chunk_overlap=50 ).get_nodes_from_documents(documents) # 打印切分后的节点总数,校验切分结果 print(f"切分后的 Node 数量:{len(nodes)}") # ========== 3. 初始化 MongoDB 文档存储 ========== # 使用 from_uri 工厂方法创建 MongoDocumentStore 实例,通过连接 URI 对接 MongoDB # 入参说明: # uri:MongoDB 标准连接字符串,格式为 mongodb://账号:密码@地址:端口,本地无认证可简写为 mongodb://localhost:27017 # db_name:目标数据库名称,所有存储数据会存入该数据库下 # namespace:命名空间,用于同一数据库内的业务数据隔离 # 本质是集合名前缀,不同 namespace 对应不同的 MongoDB 集合,数据完全独立 # 适合多项目、多业务共用同一个 MongoDB 实例的场景,避免数据混淆 docstore = MongoDocumentStore.from_uri( uri="mongodb://localhost:27017", db_name="llama_index", # 命名空间文档多了之后方便做隔离 namespace="novel" ) # ========== 4. 构建存储上下文 ========== # 将自定义的 MongoDB 文档存储注册到存储上下文中统一管理 # 未显式指定的向量存储、索引存储等组件,会自动使用默认的内存实现 # 如果后续想换数据库,执行修改下方docstore的值就可以了 storage_context = StorageContext.from_defaults( docstore=docstore ) # ========== 5. 批量写入节点到 MongoDB ========== # 调用 add_documents 方法,将所有切分后的节点存入 MongoDB 文档存储 # 注意: # 1. 首次运行需打开该行注释执行写入;后续重复运行建议注释,避免重复写入数据 # 2. 节点以 node_id 为主键,重复写入的行为以官方实现为准,建议做好去重处理 # storage_context.docstore.add_documents(nodes) # print("Node 已成功存入 MongoDB") # ========== 6. 读取并预览 MongoDB 中的节点数据 ========== print("\n=============== DocStore 数据 ===============\n") # storage_context.docstore.docs 返回所有节点的字典,键为 node_id,值为节点完整对象 # 此处截取前 3 个节点做预览,避免输出过多内容 for node_id, node in list(storage_context.docstore.docs.items())[:3]: # 打印节点唯一 ID print(f"Node ID: {node_id}") # 打印节点文本的前 100 个字符,做内容预览 print(node.text[:100]) # 打印分隔线,区分不同节点 print("-" * 50)