結論: RAGのインデックスは「作って終わり」ではなく、元データの追加・変更・削除に追従し続ける運用が前提です。日常の鮮度維持はIDを設計したうえでの増分更新(upsert+削除反映)で行い、チャンク戦略や埋め込みモデルを変えたときだけ全件の再インデックスを行う——この二本立てが、コストと精度を両立させる最短ルートです。
この記事の要点:
- 要点1: 元データが更新されてもインデックスは自動では古くなるだけ。SHA-256などのコンテンツハッシュ+安定したID設計で「変わった分だけ」を検出・反映するのが増分更新の核心です。
- 要点2:
upsertはIDで「全置換」、削除はIDやメタデータフィルタで行うのが各ベクトルストアの共通挙動。古いチャンクの削除を必ずセットで反映しないと、消したはずの情報が検索結果に残ります。 - 要点3: チャンク幅や埋め込みモデルを変えたら全件の再インデックスが必要。エイリアス切り替えによるゼロダウンタイム再構築で、検索を止めずに入れ替えられます。
対象読者: RAGを一度構築し、運用フェーズで「元データが変わったのにインデックスが古い」問題に直面している開発者・DX担当者
難易度: 中級
読了時間: 約14分
「社内ドキュメントを更新したのに、RAGが古い内容を返してくる」——RAGを本番投入した開発者なら、一度はこの壁にぶつかったのではないでしょうか。プロトタイプ段階では、ドキュメント一式をまとめて埋め込んでインデックスを作れば動きます。ところが本番では、元データは毎日のように追加・修正・削除されます。インデックスは作った瞬間のスナップショットなので、放っておけば確実に陳腐化していきます。
厄介なのは、これが「壊れる」のではなく「静かにズレる」問題だということです。エラーは出ません。検索は普通に返ります。ただし返ってくるのは古い情報や、すでに削除されたはずの内容。ユーザーは気づきにくく、しかし信頼を確実に損ないます。本番RAGの保守性に関する実務知見でも、ナレッジベースの更新サイクル設計は「後回しにすると最も高くつく領域」とされています。
この記事では、RAGのインデックスを最新に保つ運用を、①なぜ更新が要るか ②増分更新(upsert・削除・ID設計)③再インデックスが必要なとき ④鮮度と整合性(更新中の検索・ゼロダウンタイム)⑤運用の自動化、の順に、各ベクトルストアの公式ドキュメントで裏取りしながら実装イメージ付きで解説します。なお製品固有の挙動はバージョンで変わるため、最終的な仕様は必ず各製品のdocsで確認してください(本記事の挙動は2026年6月時点)。
なぜインデックスの更新が必要なのか — 「作って終わり」が崩れる瞬間
RAGのインデックスは、元文書をチャンク(分割断片)に切り、それぞれを埋め込みベクトルに変換してベクトルストアに格納したものです。検索時はクエリをベクトル化し、近いベクトルを引いてLLMの文脈に詰めます。つまりインデックスは「ある時点の元データのコピー」であり、元データが動けばインデックスとの間に必ず差分が生まれます。
元データとインデックスがズレる原因は、大きく3種類に整理できます。
| 変更の種類 | 元データ側で起きること | インデックスで必要な操作 | 放置したときの症状 |
|---|---|---|---|
| 追加 | 新しい文書・FAQ・記事が増える | 新規チャンクを埋め込んでupsert | 新情報が検索に出ない(カバレッジ低下) |
| 変更 | 既存文書の本文が書き換わる | 該当文書の旧チャンクを削除し、新チャンクをupsert | 古い記述が返る(鮮度低下) |
| 削除 | 文書が廃止・非公開になる | 該当文書のチャンクをインデックスから削除 | 消したはずの情報が返る(整合性破綻・コンプラ事故) |
特に見落とされやすいのが削除の反映です。追加は「出ないから気づく」、変更も「内容が古いから気づける」ことがありますが、削除はインデックスに残ったままでも検索は正常に動いてしまうため、誰も気づかないまま「公開停止した社内規定」や「契約終了した顧客情報」が返り続ける、という事故につながります。鮮度(freshness)と整合性(consistency)は別の問題として扱う必要があります。
ここで重要な前提が一つあります。インデックスを最新に保つ運用の質は、その手前のチャンク戦略と埋め込みモデルの設計に大きく依存します。チャンクの切り方が安定していれば差分の特定が容易になり、埋め込みモデルが固定されていれば増分追加したベクトルが既存ベクトルと同じ空間で比較できます。分割設計の基礎はRAGチャンキング戦略 完全ガイド|検索精度を決める分割設計で詳しく解説しているので、本記事と合わせて押さえておくと運用設計がぶれません。
増分更新の基本 — upsert・削除・ID設計
日常運用の主役は増分更新(incremental update)です。全件を作り直すのではなく、「変わった分だけ」を反映します。これを支えるのが、upsert・削除・ID設計の3点セットです。
upsert — IDで「全置換」する仕組み
upsertは「指定IDのレコードが無ければ挿入、あれば置換」する操作です。ここで多くの開発者がハマるのが、upsertは部分更新ではなく全置換であるという点です。Pineconeの公式ドキュメントは「IDが既に存在する場合、upsertはレコード全体を上書きする」と明記しており、特定フィールドだけを書き換えたい場合はupdateを使うよう案内しています。pgvectorでも同じ考え方で、ON CONFLICT ... DO UPDATEで衝突時にベクトルを差し替えます。
# Pinecone: IDを指定して upsert(同じIDなら全置換)
# ※ クライアントの引数・メソッド名はバージョンで変わるため公式docsで確認
index.upsert(
vectors=[
{
"id": "doc-42:chunk-3", # 文書ID:チャンク番号 で安定化
"values": embedding, # 埋め込みベクトル
"metadata": {
"doc_id": "doc-42",
"content_hash": "9f2c...", # 変更検知用ハッシュ
"updated_at": "2026-06-06",
},
}
],
namespace="handbook", # 名前空間で論理分離
)
-- pgvector: ON CONFLICT で upsert(衝突時に embedding を差し替え)
INSERT INTO chunks (id, doc_id, embedding, content_hash)
VALUES ('doc-42:chunk-3', 'doc-42', '[0.12, 0.04, ...]', '9f2c...')
ON CONFLICT (id)
DO UPDATE SET embedding = EXCLUDED.embedding,
content_hash = EXCLUDED.content_hash;
ここで「全置換」と「部分更新」を使い分ける感覚が重要になります。Weaviateを例に取ると、特定プロパティだけを書き換える部分更新(PATCH相当のupdate())と、オブジェクト全体を上書きする全置換(PUT相当のreplace())が用意されており、後者では指定しなかったプロパティは消えます。Pineconeでも、ベクトルやレコード全体を入れ替えるならupsert、メタデータの一部だけ直すならupdate、と役割が分かれています。「メタデータのタグを1つ直したいだけなのにupsertでベクトルごと作り直す」のは、埋め込み生成コストを無駄に払う典型的なアンチパターンです。
また、テキストプロパティを更新すると自動で再ベクトル化・再インデックスされるストアもあります(Weaviateのベクトライザ連携など)。一方で「コレクション定義に新しいプロパティを追加しても、既存オブジェクトは再ベクトル化されない(更新時のみ)」という挙動の差もあるため、自動化に頼る範囲は各製品のdocsで必ず確認してください。自前で埋め込みを生成して渡す構成なら、いつベクトルを作り直すかは完全にこちらの制御下に置けます。
削除の反映 — 「変更」は実質「削除+追加」
文書が更新されたとき、新チャンクをupsertするだけでは不十分です。元の文書が5チャンクから3チャンクに減った場合、余った2チャンク分の古いベクトルがインデックスに残り、検索に混入します。そこで「該当文書の旧チャンクを全削除 → 新チャンクをupsert」という手順が基本形になります。
- 更新対象の
doc_idに紐づく旧チャンクのIDを、メタデータ登録簿(後述)から引く - そのIDまたは
doc_idのメタデータフィルタで、インデックスから旧チャンクを削除する - 更新後の文書を再チャンク化し、埋め込みを生成する
- 新チャンクを安定IDでupsertする
- 登録簿のハッシュ・タイムスタンプ・チャンクIDリストを更新する
削除のインターフェースはストアごとに用意されています。代表的なベクトルストアの削除手段を整理すると、共通するのは「ID指定が最も確実」「メタデータフィルタは便利だがレート制限がかかりやすい」という点です。
| ストア | ID指定削除 | フィルタ削除 | 一括削除の単位 |
|---|---|---|---|
| Pinecone | ✅(1リクエスト最大1,000件) | ✅(メタデータフィルタ・レート制限あり) | 名前空間(namespace)単位 |
| Weaviate | ✅(オブジェクトID) | ✅(whereフィルタで一括削除) | コレクション/テナント単位 |
| pgvector | ✅(DELETE ... WHERE id = ...) |
✅(任意のSQL条件) | テーブル単位(TRUNCATE) |
ただし多くのベクトルストアは結果整合性(eventual consistency)で、削除直後はクエリに一時的に残ることがある点に注意が必要です。Pineconeのdocsも「削除済みレコードが一時的にクエリに見えることがある」と明記しています。「削除したのにまだ出る」を即バグと判断せず、伝播を待つか統計情報で反映を確認しましょう。具体的な挙動・レート制限・整合性モデルはバージョンで変わるため、各製品のdocsで確認してください。
# 文書単位での「全置換」更新パターン
def reindex_document(index, doc_id, new_chunks, namespace):
# 1) 旧チャンクをメタデータフィルタで一括削除
index.delete(filter={"doc_id": doc_id}, namespace=namespace)
# 2) 新チャンクを安定IDで upsert
vectors = [
{
"id": f"{doc_id}:chunk-{i}",
"values": embed(chunk.text),
"metadata": {"doc_id": doc_id, "content_hash": chunk.hash},
}
for i, chunk in enumerate(new_chunks)
]
index.upsert(vectors=vectors, namespace=namespace)
ID設計 — 増分更新の成否を決める土台
増分更新が成立するかどうかは、IDが決定論的(deterministic)であることにかかっています。毎回ランダムなUUIDを振っていると、「同じ文書の同じチャンク」を後から特定できず、削除も上書きもできません。実務では次の方針が安定します。
| ID設計の方針 | 具体例 | メリット | 注意点 |
|---|---|---|---|
| 文書ID:チャンク番号 | doc-42:chunk-3 |
人間が読める/更新時に旧チャンクを範囲削除しやすい | チャンク数が減ると末尾IDが残る→doc_id一括削除と併用 |
| 文書ID+本文ハッシュ | doc-42:9f2c1a |
本文が同一なら再生成不要と判定できる | 順序情報が失われるのでメタデータに位置を保持 |
| 名前空間で論理分離 | テナント・部署ごとにnamespace |
マルチテナントで削除・全更新の影響範囲を限定 | 横断検索が必要な要件では設計を再検討 |
埋め込みモデルが固定されている前提でこのID設計が機能します。モデルを変えると同じテキストでも別のベクトルになるため、増分追加では空間が混ざってしまいます。モデル選定の考え方はEmbeddingモデル選定ガイド|RAG精度を上げる実装と比較を参照してください。

再インデックスが必要なとき — 全件作り直しの判断基準
増分更新は「日常」の手段ですが、設計そのものを変えたときは増分では追いつきません。全件の再インデックス(reindexing)が必要になる代表的なケースは次の通りです。
| 変更内容 | 増分でOK? | 理由 |
|---|---|---|
| 文書の追加・修正・削除 | ✅ 増分 | 既存ベクトルと同じ空間・同じ分割粒度のまま反映できる |
| チャンク戦略の変更(幅・オーバーラップ) | ❌ 再インデックス | 全文書を切り直すため、既存チャンクと境界が一致しない |
| 埋め込みモデルの変更・バージョン更新 | ❌ 再インデックス | ベクトル空間が変わり、新旧ベクトルを同じ尺度で比較できない |
| 距離指標・次元数の変更 | ❌ 再インデックス | インデックス構造そのものを作り直す必要がある |
| メタデータスキーマの大幅変更 | △ 場合による | フィルタ要件次第。再取り込みが必要なこともある |
再インデックスは「ベクトルストアのインデックス構造を貼り直す」話と、「全文書を再チャンク・再埋め込みして入れ直す」話の2層があります。pgvectorのようなRDB系では、大量の更新・削除のあとにREINDEX INDEX CONCURRENTLYでHNSWインデックスを貼り直すと検索性能を維持しやすく、公式ドキュメントもVACUUM前のREINDEXを推奨しています。
-- pgvector: 大量更新・削除後の索引メンテナンス
-- CONCURRENTLY で検索を止めずに貼り直す
REINDEX INDEX CONCURRENTLY chunks_embedding_hnsw_idx;
VACUUM chunks;
マネージドのナレッジベース(例: Amazon Bedrock Knowledge Bases)では、データソースを同期(sync / ingestion job)すると差分取り込みが走る一方、チャンク設定や埋め込みモデルを変えると全体の再取り込みが必要になります。どこまでを増分でカバーし、どこからを全件作り直しにするかは、製品の取り込みジョブの仕様に従って判断してください。
鮮度と整合性 — 更新中の検索とゼロダウンタイム
運用で最も神経を使うのが、「更新している最中の検索」をどう扱うかです。チャンクを削除してから新チャンクをupsertするまでの間にクエリが来ると、一時的に情報が欠けたインデックスを参照してしまいます。再インデックスのように全件を入れ替える場合は、この影響が全文書に及びます。
ゼロダウンタイム再構築 — エイリアス切り替え
全件再インデックスの定番が、エイリアス(別名)切り替えによるブルーグリーン方式です。本番が参照する論理名(エイリアス)はそのままに、裏で新インデックスを完成させてから、原子的にエイリオスの向き先を差し替えます。これにより、どのクエリも「中途半端なインデックス」を見ることがありません。
- 現行インデックス(v1)を本番エイリアスが参照したまま稼働させる
- 新しい設定(新チャンク幅/新モデル)で空のインデックス v2 を作る
- 全文書を再チャンク・再埋め込みして v2 にロードする
- v2 に対して評価用クエリを流し、品質・件数・レイテンシを検証する
- 検証OKなら、本番エイリアスを v1 → v2 へ原子的に切り替える
- ロールバック用に v1 を一定期間(リテンション)残してから破棄する
ベクトルストアにエイリアス機能がない場合でも、アプリ側に「アクティブインデックス名」を持つ設定値(環境変数や設定テーブル)を一つ置けば、同じ切り替えを実装できます。切り替えを1か所のフラグに集約するのがポイントです。
バージョン管理と鮮度の可視化
整合性を保つには、各レコードにバージョン情報を持たせるのが有効です。メタデータにupdated_atやindex_versionを入れておけば、検索結果に「いつ時点の情報か」を添えられ、古いバージョンが混ざったときの検知やフィルタリングもできます。鮮度を運用指標として可視化しておくと、「最終同期からの経過時間」や「未反映ドキュメント数」をダッシュボードで監視でき、ズレを早期に発見できます。
運用の自動化 — 変更検知・スケジュール・監視
ここまでの操作を手作業で回すのは現実的ではありません。最後に、増分更新を回し続けるための自動化パイプラインを整理します。本番RAGでは、この更新サイクルの自動化こそが保守性の中心です。
変更検知 — 何が変わったかを特定する
「変わった分だけ」反映するには、まず変更を検出する必要があります。実務では次の手段を組み合わせます。
| 検知方法 | 仕組み | 向いている元データ |
|---|---|---|
| タイムスタンプ | last_modifiedを前回同期時刻と比較 |
更新日時が信頼できるDB・CMS |
| コンテンツハッシュ | 本文のSHA-256を前回値と比較 | 更新日時が当てにならないファイル群 |
| イベント/メッセージキュー | 更新イベントを購読してリアルタイム反映 | 更新頻度が高い・即時性が要るデータ |
| バージョン管理履歴 | コミット差分から変更ファイルを抽出 | Git管理されたドキュメント |
堅実なのは、信頼できるときはタイムスタンプ、当てにならないときはコンテンツハッシュにフォールバックする併用です。そのために、何をインデックス済みかを記録するメタデータ登録簿(registry)を別途持ち、文書ID・コンテンツハッシュ・チャンクIDリスト・タイムスタンプを管理します。同期処理は「登録簿と現在の元データを突き合わせ、ハッシュが変わったものだけ処理」する形になります。
# 変更検知 → 増分同期の擬似コード
import hashlib
def sha256(text: str) -> str:
return hashlib.sha256(text.encode("utf-8")).hexdigest()
def sync(source_docs, registry, index, namespace):
seen = set()
for doc in source_docs:
seen.add(doc.id)
new_hash = sha256(doc.text)
old = registry.get(doc.id)
if old and old["hash"] == new_hash:
continue # 変更なし → スキップ
chunks = chunk_document(doc.text) # 再チャンク
reindex_document(index, doc.id, chunks, namespace) # 削除+upsert
registry.put(doc.id, {"hash": new_hash, "chunks": len(chunks)})
# 元データから消えた文書をインデックスからも削除
for missing_id in registry.ids() - seen:
index.delete(filter={"doc_id": missing_id}, namespace=namespace)
registry.delete(missing_id)
スケジュールと監視
同期の起動方式は、要件に応じて使い分けます。日次・時間次のバッチ同期はシンプルで監視しやすく、多くの社内ナレッジには十分です。即時性が要る場合はイベント駆動で更新を即反映します。大規模では「日常は増分、定期的に全件再インデックス」のハイブリッドが定番で、増分で取りこぼした差分を全件再構築でリセットします。
監視では、最低限「同期ジョブの成否」「処理件数(追加/更新/削除)」「最終同期からの経過時間」「インデックスの総レコード数の推移」を取りましょう。総レコード数が想定外に急増・急減したら、削除漏れや重複upsertのサインです。RAG全体の品質をどう測るかはRAGの精度を測る|RAGASと評価指標の実装ガイドと合わせて設計すると、鮮度と精度の両面で運用を監視できます。
【注意】よくある失敗パターンと回避策
増分更新・再インデックスの運用でつまずきやすいポイントを、❌⭕形式で整理します。
失敗1: 更新時に旧チャンクを消し忘れる
❌ 新チャンクをupsertするだけで、減ったチャンク分の古いベクトルが残る
⭕ 「該当doc_idを全削除 → 新チャンクをupsert」を1トランザクション的に扱う
失敗2: ランダムIDで増分更新できなくなる
❌ 毎回UUIDを振り、同じチャンクを後から特定できない
⭕ doc_id:chunk番号など決定論的IDにし、削除・上書きを再現可能にする
失敗3: 結果整合性を考慮せず即バグ判定する
❌ 削除直後にクエリで出てきたのを見て「削除が効かない」と誤判断する
⭕ 伝播の遅延を前提に、統計情報や少しの待機で反映を確認する
失敗4: モデル変更を増分でごまかす
❌ 埋め込みモデルを変えたのに新規分だけ新モデルでupsert、空間が混在する
⭕ モデル変更は全件再インデックス。エイリアス切り替えで安全に入れ替える
まとめ: 今日から始める3つのアクション
- 今日: 自分のRAGのIDがランダムか決定論的かを確認する。ランダムなら、まず
doc_id:chunk番号形式へ移行する設計メモを書く。 - 今週中: 文書ID・コンテンツハッシュ・チャンクIDを記録するメタデータ登録簿を用意し、「ハッシュが変わったものだけ削除+upsert」する同期スクリプトを試作する。
- 今月中: チャンク戦略やモデル変更に備え、エイリアス切り替えによるゼロダウンタイム再構築の手順を1本通しで検証し、監視(同期成否・レコード数推移)をダッシュボード化する。
RAGの土台づくり全体の流れはAIエージェント実装ロードマップ|RAG・実行・運用の必須技術でも俯瞰しています。インデックスの鮮度維持は、構築よりもむしろ運用フェーズで効いてくる差別化ポイントです。
AIエージェント・ツールの最新情報をキャッチアップしたい方へ
Agent Labでは、週1回のニュースレターでAIツールの最新比較・活用事例をお届けしています。
著者: 佐藤傑(さとう・すぐる)
株式会社Uravation代表取締役。X(@SuguruKun_ai)フォロワー約10万人。100社以上の企業向けAI研修・導入支援。著書『AIエージェント仕事術』(SBクリエイティブ)。
ご質問・ご相談は お問い合わせフォーム からお気軽にどうぞ。
参考・出典
- Upsert data — Pinecone Docs(参照日: 2026-06-06)
- Delete data — Pinecone Docs(参照日: 2026-06-06)
- Update objects — Weaviate Docs(参照日: 2026-06-06)
- pgvector/pgvector — GitHub(参照日: 2026-06-06)
- Sync your data source with your knowledge base — Amazon Bedrock User Guide(参照日: 2026-06-06)
