news 2026/9/12 1:31:20

LlamaIndex Key-Value Stores 存储抽象全解析:Simple、MongoDB 与 Tablestore 的实现原理与实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
LlamaIndex Key-Value Stores 存储抽象全解析:Simple、MongoDB 与 Tablestore 的实现原理与实战

LlamaIndex Key-Value Stores 存储抽象全解析:Simple、MongoDB 与 Tablestore 的实现原理与实战

【免费下载链接】llama_indexLlamaIndex is the document processing platform for AI项目地址: https://gitcode.com/GitHub_Trending/ll/llama_index

导读

本文围绕 LlamaIndex 框架中支撑 Document Store 与 Index Store 的底层存储抽象——Key-Value Store(KV Store)展开,系统梳理其抽象接口设计、内置的三种实现(内存版 SimpleKVStore、MongoDB 版与 Tablestore 版)以及它们如何被上层存储组件消费。读完本文,你将掌握 KV Store 的统一操作语义(put/get/delete及异步变体)、持久化与序列化机制、三种实现的选型依据,以及如何用 KV Store 自定义底层存储来构建可复用的文档与索引存储。

关联文档:docs/src/content/docs/framework/module_guides/storing/kv_stores.md


一、KV Store 在 LlamaIndex 存储体系中的定位

在 LlamaIndex 的存储体系中,KV Store 是最底层的"键值存取"抽象,它是 Document Store 与 Index Store 的存储底座。也就是说,节点(Node)内容的存取、索引结构(IndexStruct)的序列化,最终都会落到 KV Store 的key -> dict操作上。

从 核心存储目录结构 可以看到清晰的分层:

storage/ ├── kvstore/ # KV Store 抽象与实现(本文主题) │ ├── types.py # BaseKVStore 抽象基类与常量 │ ├── simple_kvstore.py # 内存版实现 │ └── __init__.py ├── docstore/ # 文档/节点存储(依赖 kvstore) │ ├── keyval_docstore.py # KVDocumentStore │ └── simple_docstore.py # SimpleDocumentStore ├── index_store/ # 索引结构存储(依赖 kvstore) │ ├── keyval_index_store.py # KVIndexStore │ └── simple_index_store.py # SimpleIndexStore └── storage_context.py # StorageContext 统一装配入口

文档明确指出:KV Store 是驱动 Document Store 和 Index Store 的底层存储抽象。原文档同时强调"目前这些存储抽象并非面向外部用户的公开 API",因此本文把它当作理解 LlamaIndex 存储机制的内部知识来深入讲解。

注意:原文档列出三种 KV Store——内存版(Simple Key-Value Store)、MongoDB 版与 Tablestore 版。其中后两种以独立集成包的形式维护在 llama-index-integrations/storage/kvstore/ 目录下,读者可按需单独安装。


二、统一抽象:BaseKVStore 接口设计

所有 KV Store 实现都继承自 BaseKVStore 抽象基类。它定义了一套统一的操作契约,每个方法都同时提供同步与异步(带a前缀)两个版本

方法作用说明
put(key, val, collection)/aput(...)写入键值对每个实现都必须支持
put_all(kv_pairs, collection, batch_size)/aput_all(...)批量写入基类默认仅支持batch_size=1,即逐个调用put;不支持批量的实现会抛出NotImplementedError
get(key, collection)/aget(...)读取单个值不存在时返回None
get_all(collection)/aget_all(...)读取整个 collection 的全部键值返回Dict[str, dict]
delete(key, collection)/adelete(...)删除键返回布尔值表示是否删除成功

基类还定义了两个重要常量(types.py):

  • DEFAULT_COLLECTION = "data":默认 collection 名称。collection 是 KV Store 中用于逻辑分区的命名空间,类似 MongoDB 中的集合(collection)或关系型数据库中的表——不同用途的数据(如节点正文、ref_doc 信息、索引结构)会写入不同的 collection。
  • DEFAULT_BATCH_SIZE = 1:批量写入的默认批次大小。

BaseKVStore外,抽象层还提供两个中间基类:

  • BaseInMemoryKVStore(types.py#L77-L89):在BaseKVStore之上补充persist(persist_path, fs)from_persist_path(persist_path)两个持久化相关的抽象方法,是"可落盘内存型 KV Store"的契约。
  • MutableMappingKVStore(types.py#L95-L183):泛型实现,内部用_collections_mappings: Dict[str, MutableMappingT]把"collection -> 可变映射"组织起来,通过mapping_factory工厂函数创建每个 collection 的实际映射容器。它实现了大部分读写逻辑,但persist/from_persist_path默认抛NotImplementedError,提示"请使用SimpleKVStore等子类"——这正是SimpleKVStore存在的原因。

从源码结构看,这套抽象刻意把"接口契约"(BaseKVStore)、"通用内存映射逻辑"(MutableMappingKVStore)与"具体后端"(SimpleKVStoreMongoDBKVStoreTablestoreKVStore)三层分离,使得上层KVDocumentStore/KVIndexStore无需关心底层是内存、MongoDB 还是 Tablestore。


三、Simple Key-Value Store:内存实现与持久化

SimpleKVStore 是 LlamaIndex 内置的纯内存 KV Store,继承自MutableMappingKVStore[dict],数据格式为Dict[str, Dict[str, dict]](即collection -> (key -> value))。

3.1 核心能力

  • 初始化SimpleKVStore(data=None),可选传入已有数据字典进行恢复。
  • 持久化persist(persist_path, fs=None)将整个 store 以 JSON 形式写入磁盘;fs使用 fsspec 文件系统抽象,默认fsspec.filesystem("file"),因此天然支持传 S3、GCS 等 fsspec 兼容文件系统。写入前会自动创建目录。
  • 从磁盘加载:类方法from_persist_path(persist_path, fs=None)读取 JSON 并构造新实例。
  • 字典互转to_dict()/from_dict()支持把整个 store 导出为普通字典,或在SimpleKVStore与字典之间互转。

由于它完全驻留内存,进程退出后数据即丢失,只有显式调用persist才会落盘——这是它与 MongoDB / Tablestore 版本最本质的区别,适用于原型验证、单机小规模场景。

3.2 序列化细节

persist直接执行json.dumps(self._collections_mappings),即把collection -> {key: value_dict}的嵌套结构整体序列化。这要求 value 必须是可 JSON 序列化的字典;上层KVDocumentStore在写入前会通过doc_to_json把 Node 转为 JSON 字典,恰好满足这一前提。


四、MongoDB Key-Value Store:服务化后端

MongoDBKVStore 将 MongoDB 作为 KV Store 后端,包名为llama-index-storage-kvstore-mongodb。它直接继承BaseKVStore,是面向生产环境的分布式存储方案。

4.1 构造与连接

参数类型说明
mongo_clientAny必填,外部传入的 pymongoMongoClient
mongo_aclientOptional可选的 pymongoAsyncMongoClient,用于异步操作
uri/host/portOptional连接信息(用于记录,实际连接由 client 建立)
db_nameOptional数据库名,默认"db_docstore"

两种推荐的构造方式:

# 方式一:URI 连接 from llama_index.storage.kvstore.mongodb import MongoDBKVStore kvstore = MongoDBKVStore.from_uri("mongodb://localhost:27017", db_name="my_kvstore") # 方式二:主机与端口连接 kvstore = MongoDBKVStore.from_host_and_port("localhost", 27017, db_name="my_kvstore")

源码中两类工厂方法都会同时创建同步MongoClient与异步AsyncMongoClient(异步客户端用于aget/aput等异步 API),并以appname="Llama-Index-KVStore-Python"标识应用。若系统缺少pymongo,会抛出提示pip install pymongoImportError

4.2 存储映射与读写实现

MongoDBKVStore 的映射策略非常直接(base.py#L186-L298):

  • collection 映射到 MongoDB 的 collectionself._db[collection]
  • key 映射到文档的_id字段:写入时构造{"_id": key, **value},即 value 的所有字段平铺到文档中;
  • 写入使用UpdateOne(..., upsert=True)批量执行put_allbatch_size分片,对每个文档执行 upsert,保证幂等写入;
  • 读取时剥离_idget/get_all取出文档后pop("_id"),将剩余字段作为 value 返回,对上层透明;
  • 删除按_id执行delete_one({"_id": key}),返回deleted_count > 0作为成功标志。

异步版本(aput_all/aget/aget_all/adelete)依赖异步客户端,若未传入mongo_aclient会抛出ValueError提示"未使用异步客户端初始化"。

MongoDB 版本支持真正的batch_size批量写入(这是它相对基类默认行为的重要增强),并原生具备数据持久化、副本集与分布式能力,适合对数据可靠性要求高的场景。


五、Tablestore Key-Value Store:阿里云表格存储后端

TablestoreKVStore 以阿里云 Tablestore(表格存储,OTS)为后端,包名为llama-index-storage-kvstore-tablestore

5.1 构造参数

参数类型说明
tablestore_clientOptional[OTSClient]外部传入的 OTS 客户端;一旦传入,以下四个参数全部被忽略
endpointOptional[str]Tablestore 实例端点
instance_nameOptional[str]Tablestore 实例名
access_key_id/access_key_secretOptional[str]阿里云访问密钥

当不传客户端时,内部自动构造tablestore.OTSClient(endpoint, access_key_id, access_key_secret, instance_name, retry_policy=tablestore.WriteRetryPolicy(), **kwargs),其中显式启用了写入重试策略

5.2 Tablestore 特有的表管理与序列化

与 MongoDB 不同,Tablestore 是"表 + 主键列 + 属性列"模型,因此实现上有两个显著特色:

  1. collection 映射为表,表不存在时自动创建(base.py#L71-L93):_create_collection_if_not_exist会先查list_table(),若目标表不存在,则以单主键列[("pk", "STRING")]建表(预留吞吐CapacityUnit(0, 0)),创建成功后sleep(5)等待表生效。
  2. value 序列化策略(base.py#L54-L64):_flatten_dict_to_json_strings把 value 字典中非标量类型(非 bool/bytearray/float/int/binary/str)的值json.dumps成字符串存储,标量原样保留;读取时_parse_row反向尝试json.loads还原 JSON 字符串。这一机制规避了 Tablestore 对列类型的限制。

5.3 读写与遍历

  • put:以key作为主键("pk", key),把 value 的属性列写入tablestore.Rowput_row
  • getget_row按主键读取,解析后返回;当服务端返回OTSParameterInvalid且错误信息包含table not exist时返回None
  • get_all:使用get_rangeINF_MININF_MAX正向遍历整表(每批limit=5000),通过next_start_primary_key分页循环取完全部数据
  • delete_all:同样用get_range遍历并逐行删除。

需要特别说明:Tablestore 版本的异步方法(aput/aget/aget_all/adelete)目前直接抛出NotImplementedError,仅支持同步 API——这是从源码确认的实现现状,选用时需注意。


六、KV Store 如何驱动 Document Store 与 Index Store

理解了三种实现之后,再看它们在上层如何被消费,就能完整还原 KV Store 的价值。

6.1 KVDocumentStore:文档存储的 KV 视角

KVDocumentStore 是 LlamaIndex 文档存储的通用实现,它把文档(Node)存储建模为三个逻辑 collection(源码常量定义):

Collection 常量实际名称(默认 namespace=docstore存储内容
DEFAULT_COLLECTION_DATA_SUFFIXdocstore/data每个 Node 的正文与属性(序列化 JSON)
DEFAULT_REF_DOC_COLLECTION_SUFFIXdocstore/ref_doc_info文档 -> 其节点 ID 列表的映射(RefDocInfo)
DEFAULT_METADATA_COLLECTION_SUFFIXdocstore/metadata节点 -> 所属 ref_doc_id 与 doc_hash 的元数据

add_documents会把 Node 转换成三类键值对(_prepare_kv_pairs),再通过kvstore.put_all(..., batch_size=batch_size)分别批量写入三个 collection;读取、删除、哈希校验等操作也都落在kvstore.get/get_all/delete上。因此,KVDocumentStore 的底层行为完全由你传入的 KV Store 决定——换一个 KV Store 实现,就等于换了一套存储后端。

6.2 KVIndexStore:索引结构的 KV 视角

KVIndexStore 同样依赖BaseKVStore,把IndexStruct序列化为 JSON 后存入默认 collectionindex_store/data(namespace=index_store+ 后缀/data)。add_index_structindex_struct.index_id为 key 写入,get_index_struct/index_structs从 KV Store 读回并反序列化。

6.3 组装方式与共享存储

两个通用实现分别派生出默认的简单版本:

  • SimpleDocumentStore(KVDocumentStore):simple_docstore.py,默认使用SimpleKVStore
  • SimpleIndexStore(KVIndexStore):simple_index_store.py,默认同样使用SimpleKVStore

提示:KVDocumentStore/KVIndexStore的命名空间(namespace)与 collection 后缀均可自定义,MongoDBKVStoreTablestoreKVStore也可以直接作为这两个类的kvstore参数传入,实现"同一套存储逻辑、不同的底层后端"。


七、实战:三种 KV Store 的选型与用法速查

7.1 安装

# 内存版已包含在 llama-index-core 中,无需额外安装 pip install llama-index-core # MongoDB 版 pip install llama-index-storage-kvstore-mongodb # Tablestore 版 pip install llama-index-storage-kvstore-tablestore

7.2 直接使用 KV Store

# SimpleKVStore:内存 + 持久化 from llama_index.core.storage.kvstore import SimpleKVStore kv = SimpleKVStore() kv.put("key1", {"content": "hello"}, collection="my_coll") print(kv.get("key1", collection="my_coll")) # {'content': 'hello'} kv.persist("./kvstore.json") # 落盘 loaded = SimpleKVStore.from_persist_path("./kvstore.json")
# MongoDBKVStore:服务化后端 from llama_index.storage.kvstore.mongodb import MongoDBKVStore kv = MongoDBKVStore.from_uri("mongodb://localhost:27017", db_name="my_db") kv.put("key1", {"content": "hello"}, collection="my_coll") print(kv.get("key1", collection="my_coll"))

7.3 将 KV Store 接入 Document Store / Index Store

from llama_index.core.storage.docstore import KVDocumentStore from llama_index.core.storage.index_store import KVIndexStore from llama_index.storage.kvstore.mongodb import MongoDBKVStore kvstore = MongoDBKVStore.from_uri("mongodb://localhost:27017", db_name="my_db") # 使用同一个 KV Store 构建 docstore 与 index_store docstore = KVDocumentStore(kvstore=kvstore) index_store = KVIndexStore(kvstore=kvstore)

7.4 选型建议

维度SimpleKVStoreMongoDBKVStoreTablestoreKVStore
存储位置进程内存(可选落盘 JSON)MongoDB 服务阿里云 Tablestore
异步 API✅ 支持✅ 支持(需异步客户端)❌ 抛NotImplementedError
批量写入batch_size=1✅ 原生批量 + upsert逐行写入
持久化/高可用手动persist由 MongoDB 提供由 Tablestore 提供
典型场景原型、单机、临时缓存生产环境、多实例共享阿里云生态内生产环境

八、总结

KV Store 是 LlamaIndex 存储体系的"地基":BaseKVStore定义了put/get/delete与异步变体的统一契约,MutableMappingKVStore提供了通用的内存映射骨架,而SimpleKVStoreMongoDBKVStoreTablestoreKVStore则分别面向"进程内存 + JSON 落盘""MongoDB 服务""阿里云表格存储"三种后端。上层KVDocumentStoreKVIndexStore通过 collection 划分逻辑空间,把节点内容、ref_doc 关系、索引结构全部映射为键值操作。

理解这层抽象后,你可以:

  • SimpleKVStore.persist快速实现可复现的原型;
  • MongoDBKVStore.from_uri无缝切换生产级后端,且获得原生批量写入与异步支持;
  • 结合 StorageContext 统一装配自定义的 docstore / index_store,实现多索引共享同一套底层存储。

更深入的接口签名与参数细节,可查阅 API Reference(KV Store 部分) 及本文引用的各源码文件。

【免费下载链接】llama_indexLlamaIndex is the document processing platform for AI项目地址: https://gitcode.com/GitHub_Trending/ll/llama_index

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/12 1:29:48

30秒把 RetroArch 整个菜单切成中文,不碰配置文件也能完成

30秒把 RetroArch 整个菜单切成中文,不碰配置文件也能完成 【免费下载链接】RetroArch Cross-platform, sophisticated frontend for the libretro API. Licensed GPLv3. 项目地址: https://gitcode.com/GitHub_Trending/re/RetroArch 刚装好 RetroArch 打开…

作者头像 李华
网站建设 2026/9/12 1:25:42

微信小程序点餐外卖源码实战:解压配置与微信支付对接

简介:一套完整的微信小程序点餐外卖系统源码,面向希望快速上手小程序开发或搭建同类订餐应用的开发者与学习者。资源将前端小程序界面与后端服务逻辑整合在一起,涉及菜品浏览、下单支付、订单处理、配送跟踪、评价等常见业务场景,…

作者头像 李华
网站建设 2026/9/12 1:24:35

半边数据结构:三维CAD建模的拓扑基石与欧拉操作实现

简介:本资源是一份高质量的三维CAD课程设计源码,面向计算机、自动化等专业本科生及三维建模初学者,聚焦几何建模核心能力训练——基于半边数据结构实现欧拉操作与扫掠建模,并通过OpenGL完成实体可视化。项目完整实现5种欧拉操作&a…

作者头像 李华
网站建设 2026/9/12 1:24:09

A3C强化学习实战:流量数据序贯决策在入侵检测系统中的应用

简介:这是一份基于异步优势演员-评论家(A3C)算法实现的入侵检测系统(IDS)Python源码包,面向网络安全方向的毕业设计学生及强化学习实践者,解决网络流量数据异常识别与分类问题。压缩包共包含24个…

作者头像 李华
网站建设 2026/9/12 1:21:06

FastAPI与Uvicorn高性能Web开发实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华