3.4 索引的持久化、更新与管理


3.4 索引的持久化、更新与管理

本节摘要:索引不能每次进程重启都重建——嵌入费用和时间都不允许。本节覆盖三件事:默认存储的 persist/load 三件套、外接向量库下的增量更新(insert / 更新 / 删除)、以及多版本索引的生命周期管理(什么时候全量重建、灰度切换怎么做)。

默认存储的持久化三件套

不接外部向量库时,LlamaIndex 的 StorageContext 可以把三部分内容落盘:向量(docstore 里的 Node 与 embedding)、索引结构(每种索引自己的元数据)、文档存储。

from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, load_index_from_storage, StorageContext # 存 index = VectorStoreIndex.from_documents(SimpleDirectoryReader("./data").load_data()) index.storage_context.persist(persist_dir="./storage_2024q3") # 取(另一个进程) storage = StorageContext.from_defaults(persist_dir="./storage_2024q3") index2 = load_index_from_storage(storage) print(index2.as_query_engine().query("试用期多长?"))

注意这是"整套存储"的快照,不是数据库——没有并发写保护。单机脚本与实验用它足够;多进程服务请走上一节的外接向量库。

增量更新:插、改、删

知识库的常态是"每天进来几十篇、改十几篇、删几篇"。外接向量库下三个操作各有讲究:

# 插入:对已有索引对象直接 insert,只嵌入新文档 new_docs = SimpleDirectoryReader(input_files=["new_policy.md"]).load_data() index2.insert(new_docs[0]) # 仅这一篇产生嵌入调用 # 更新 = 删旧 + 插新:稳定 id 在这里生效 from llama_index.core.vector_stores import ( MetadataFilters, ExactMatchFilter) engine = index2.as_query_engine() # 按 2.1 节约定,filename_as_id 让节点 id 稳定可定位 index2.delete_nodes(node_ids=[...]) # 或向量库按 metadata 条件删 index2.insert(revised_doc) # 全刷新:文档有结构性大改(章节重排)时局部修补不可靠,整篇删了重来
# 刷新文档句柄:refresh_documents 会对比新旧并只重嵌有变化的 from llama_index.core import Document fresh = SimpleDirectoryReader("./data").load_data() refreshed = index2.refresh_documents(fresh) print("有变化的文档数:", refreshed)

一个工程细节:refresh_documents 判断"变化"依赖稳定 id 与内容比对,配合 2.4 节的 IngestionPipeline 缓存,可以把"每周全量同步"做得和"只处理变更"一样便宜。

多版本与灰度

索引一旦承载线上流量,"边改边用"就变成危险动作。稳妥做法是把索引当成有版本的数据资产:

# 版本化目录 + 显式切换 persist(index, "./storage_2024q4_v2") # 上层用一个"当前指针"决定读哪个版本,出问题一键回滚 CURRENT = "./storage_2024q4_v2" index_prod = load_index_from_storage(StorageContext.from_defaults(persist_dir=CURRENT))

什么时候必须全量重建而不是修补?三种情况:换嵌入模型(3.1 节的铁律)、切分策略大改(块边界全变,旧节点失去意义)、向量库迁移。除此之外,增量永远是更经济的选择。

⚠️ 常见坑:内存里 insert 了大量新文档却忘了 persist 或没写进外部向量库,重启后全部蒸发。养成"写操作后立刻持久化"的习惯,或干脆全部走带持久化的向量库,绕开这个坑。

本节要点回顾

  • 三件套:persist / from_defaults / load_index_from_storage,单机快照式持久化。
  • 增量三态:insert 只嵌新的、更新靠稳定 id 定位、结构性大改整篇重建。
  • refresh + 缓存:refresh_documents 与摄取缓存组合,全量同步的价格、增量的成本。
  • 版本化思维:索引是有版本的数据资产,指针切换支持灰度与回滚。
  • 全量重建三条件:换嵌入模型、改切分策略、迁向量库;其余场景增量优先。

常见问题

persist 目录越攒越多,怎么管理? 当成构建产物管理:保留"当前版 + 上一版 + 最近一个里程碑版"三份,其余清理。配合 3.4 节的版本指针,磁盘占用可控且回滚能力保留。用时间戳命名目录,排查"上周的索引是什么状态"这类问题时有据可查。

增量插入的节点会破坏索引质量吗? 单纯的插入不会,但长期只增不查的"熵增"会:早期文档与新增文档的表述风格漂移、重复内容累积。周期性做一次全量体检(5.4 节评估集回归加重复节点扫描),发现指标下滑再考虑计划性重建,比无脑定期重建省得多。

多个服务进程共享一个向量库,写入怎么协调? 让摄取管道单点写入(离线管道天然单点),线上服务只读。如果确实存在多个写入方,按集合或批次号划分写入范围,避免对同一节点的并发写覆盖。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U