RAG取り込みの鮮度・更新・削除チェックリスト|差分同期を壊さない設計(2026)
RAGの差分取り込みを運用するための実務チェックリスト。決定的ID、冪等upsert、tombstone、派生データ削除、ACL反映、freshness SLO、照合、replayを整理します。
目次
- 1分要約
- どんな人向けか
- 結論
- 解説
- 差分取り込みは「状態を収束させる」処理
- 安定したIDがretryとcleanupを簡単にする
- 削除はすべての派生層へ伝える
- ACLの鮮度は本文の鮮度と別物
- freshnessは期限と観測点を決める
- 実務ガイド
- Step 1: source of truthの変更契約を決める
- Step 2: 安定IDとsource manifestを作る
- Step 3: handlerを冪等かつversion-awareにする
- Step 4: tombstoneのlifecycleを設計する
- Step 5: vector・chunk・cacheをまとめて消す
- Step 6: 権限変更を独立した変更として反映する
- Step 7: schedule・監視・retryを運用する
- Step 8: 定期照合とreplayを用意する
- ありがちな落とし穴
- チェックリスト
- FAQ
- 1. 文書更新はupsertだけで十分?
- 2. 全件reindexをすればdelete処理は不要?
- 3. freshness SLOはどう決める?
- 4. vector削除後もtombstoneを残す理由は?
- 5. 照合完了をどう判断する?
- 参考資料
- 内部リンク
- 免責事項
RAGの差分取り込みで、更新漏れと削除漏れをどう防ぐ?
1分要約
- sourceとchunkに毎回同じ決定的IDを割り当て、同じイベントを再実行しても同じ状態へ収束する冪等upsertにする。
- 削除とACL取り消しを独立したイベントとして扱う。tombstoneを残し、chunk・vector・cacheまで消して、検索できないことを確かめる。
- 更新・削除・権限反映に別々のfreshness SLOを置く。end-to-endの遅延を測り、定期照合と安全なreplayでdriftを直す。
どんな人向けか
- 初回投入後も更新・削除される文書をRAGで扱うチーム
- 定期実行、イベント駆動、または両方を組み合わせた取り込み基盤を作るエンジニア
- 削除、権限取り消し、監査証跡に責任を持つplatform・security担当者
結論
本番のRAG indexは一度だけ作る成果物ではなく、source of truthから再生成される派生storeである。作成、更新、削除、権限変更、retry、部分失敗の後にも、正しい状態へ収束できなければならない。
基本の流れは次の通り。
- source文書と派生chunkを決定的に識別する
- 観測したsource versionと、出力したchunk ID集合を保存する
- 新versionを冪等にupsertする
- source削除時は物理cleanupより先にtombstoneを記録する
- 古いchunk、vector、enrichment、semantic cacheを削除する
- ACL変更を本文更新とは別の経路・期限で反映する
- 変更が検索結果へ現れる、または消えるまでを計測する
- 定期的に全体を照合し、driftがあれば安全にreplayする
製品機能はこの一部を担うが、契約は製品ごとに異なる。Azure AI Search indexerにはsource別の変更・削除検出、schedule、status history、reset、index projectionがある。Pineconeはnamespaceを指定したupsertとdeleteを提供する。どちらを使っても、ID、manifest、SLO、検証をアプリケーション側で設計する責任は残る。
解説
差分取り込みは「状態を収束させる」処理
取り込みjobは文章を転送するだけではない。file抽出、section分割、metadata enrichment、embedding生成、keyword/vector recordの書き込み、cache更新など複数の段階を通る。途中のどこでも失敗し得る。
したがって「jobがsuccessだった」ことと、「検索結果が最新かつ現在の権限に合っている」ことは同義ではない。各source versionがすべての派生storeへ反映されたかを追跡する。
source単位で次のstateを持つとよい。
- 不変の
source_id - 観測済みの
source_versionまたは単調増加するchange token - content hashとACL version
- 現在有効なchunk IDのmanifest
active、tombstoned、purgedなどのlifecycle state- 最後に成功したstageと各timestamp
source側の契約が重要な理由はAzure AI Searchにも表れている。SQLのhigh-water-mark policyではinsertとupdateのたびに対象columnが進む必要があり、Microsoftは同時transaction下の同期には rowversion を推奨している。一方、high water markだけでは物理削除されたrowを推測できない。SQL削除にはintegrated change trackingか、設定済みのsoft-delete markerが必要になる。
安定したIDがretryとcleanupを簡単にする
通常の編集やrenameで変わらないsource IDを使う。chunk IDも、可能なら安定した構造から生成する。
chunk_id = hash(tenant_id + source_id + section_anchor + chunk_variant)
chunk配列の現在位置だけに依存すると、途中へ1段落追加しただけで後続IDがすべて変わる。chunk境界を変えた場合は、新旧manifestの差分を取り、消えたIDを明示的に削除する。
決定的IDならretryも同じrecordへ向かう。Pineconeでは、既存IDへのupsertはrecord全体をoverwriteし、一部だけを変える操作はupdateとして区別される。ただし、これはPineconeの契約であり、すべてのvector databaseに共通する保証ではない。利用製品のoverwrite、merge、順序、consistencyを確認する。
削除はすべての派生層へ伝える
source objectを消しても、RAG側には次が残り得る。
- 抽出済みtextと一時artifact
- chunk rowとkeyword search document
- embeddingとvector record
- enrichment cache
- semantic cacheと生成済み回答
- manifest、backup、export、評価fixture
物理cleanupの前にtombstoneを記録し、遅れて届いたupdateが削除済みデータを復活させないようにする。tombstoneにはsource ID、削除version、認可scope、retention判断を持たせる。各workerは派生物を冪等に消し、完了証跡を残す。
Azureの仕様は製品固有だが参考になる。reset後にrunしても、sourceに存在しないorphan documentは自動削除されない。Azure Blob indexerでは、削除検出policyを最初のindexer runから設定する必要があり、後から加えても過去の削除は遡って検出できない。native blob soft deleteの保持期間も、indexerが削除状態を観測できるよう、実行間隔より十分長くする必要がある。
ACLの鮮度は本文の鮮度と別物
本文が同じまま、閲覧可能なuserやgroupだけ変わることがある。acl_version と content_version を分け、sourceが対応していればpermission専用のupdateやresyncを実行する。
Azure AI Searchのpush APIでACLを扱うにはschemaにpermission-filter fieldを用意し、取り込み時にrepositoryの権限をidentity IDへ解決する。またADLS Gen2では、ACL変更でblobの LastModified が更新されない場合があり、通常のcontent change detectionでは拾えないとMicrosoftが説明している。製品を問わず、本文の更新時刻をpermission変更signalとして兼用しないことが重要である。
freshnessは期限と観測点を決める
source eventから検索上の結果まで、種類別にSLOを置く。
- 更新freshness: source commitから新しい認可済みversionを検索できるまで
- 削除freshness: 削除決定からlive retrievalとresponse cacheが何も返さなくなるまで
- ACL freshness: 権限変更から、取り消された利用者が拒否され、新規許可された利用者が正しいversionを得るまで
- 照合freshness: driftが存在できる最長時間と、全体照合が検出するまでの期限
平均job時間だけでなくpercentileと、未完了eventの最古時刻を見る。schedule間隔は遅延の一部にすぎない。Azure AI Search indexerのscheduleは5分から24時間まで設定できるが、queue待ち、処理、failure、後段cache invalidationもend-to-endの鮮度へ影響する。
実務ガイド
Step 1: source of truthの変更契約を決める
connectorごとに、作成、更新、削除、復元、権限変更をどう通知するか整理する。cursorが単調増加するか、eventが順不同で届くか、delete markerをどれだけ観測できるかも記録する。
delete eventを出せないconnectorには、定期的な全件listingかinventory exportを組み合わせる。現存rowしか見ないhigh water markでは、「消えたrowが削除された」と証明できない。
Step 2: 安定IDとsource manifestを作る
source versionごとにmanifestを保存する。
{
"source_id": "tenant_7:policy_42",
"source_version": "018f3d6a",
"acl_version": "acl_109",
"state": "active",
"chunk_ids": ["c_31aa", "c_90bf", "c_a712"]
}
新しいchunk集合を作り、直前の確定manifestと比較する。現行IDをupsertし、差分で消えたIDを削除する。Azureのindex projectionもparent keyを保持しながら1つのsourceをchild search documentへ展開する。利用する場合は、一般的なparent-child動作を想定せず、同機能のmapping ruleに従う。
Step 3: handlerを冪等かつversion-awareにする
次は製品非依存のpseudocodeである。
async function applySourceEvent(event: SourceEvent) {
const current = await manifests.get(event.sourceId);
if (current && compareVersion(event.version, current.version) <= 0) return;
if (event.type === 'deleted') {
await tombstones.put(event.sourceId, event.version);
await removeDerivedData(current?.chunkIds ?? [], event.sourceId);
await manifests.markPurged(event.sourceId, event.version);
return;
}
if (await tombstones.blocks(event.sourceId, event.version)) return;
const next = await buildChunks(event);
await vectorStore.upsert(next.records);
await deleteIds(difference(current?.chunkIds ?? [], next.chunkIds));
await caches.invalidateBySource(event.sourceId);
await manifests.commit(next.manifest);
}
基盤が対応するならcompare-and-set、transaction、outboxなどを使う。正確なatomicityの方法はplatformごとに異なる。守るべきinvariantは、古いeventが新versionを上書きしないことと、同じeventを繰り返しても余計なrecordを作らないこと。
Step 4: tombstoneのlifecycleを設計する
明示的なstateを用意する。
active -> tombstoned -> derived-data-deleting -> purged
遅延event、retry、connectorのlookback、restore policyをカバーできる期間はtombstoneを保持する。万人に共通する固定日数はない。source systemと保持義務から決める。復元はtombstoneを無条件に消す操作ではなく、新しいversionを持つeventにする。
Step 5: vector・chunk・cacheをまとめて消す
source_id と記録済みchunk manifestをkeyに、削除処理をfan-outする。Pineconeの2026-04 APIは、1つのnamespace内でIDまたはmetadata filterを指定してrecordを削除でき、namespace全体を対象にする deleteAll も備える。ほかのstoreは仕様が異なるため、実APIの契約を確認し、最も狭く安全なselectorを選ぶ。
削除後は、正確なsource IDと代表的な本文を使い、関係するすべてのtenant・ACL scopeから検索する。keyword index、semantic cache、生成回答cache、enrichment artifactも確認する。Azureのenrichment cacheでは、blob削除をcacheとindexの両方へ同期するためにindexer deletion policyが必要とされている。
Step 6: 権限変更を独立した変更として反映する
各chunkへ acl_version を保存する。権限変更時は次を行う。
- 信頼できるrepositoryから現在のsource ACLを解決する
- すべての有効chunkへ新しいpermission fieldを書き込む
- 古い認可scopeをkeyにしたcacheを無効化する
- revokeされたprincipalと、新しく許可されたprincipalで試す
- ACL freshness SLOに対する完了時刻を記録する
必須ACL metadataが欠落・不一致ならfail closedにする。本文だけ速く更新できても、権限が古ければ十分にfreshとはいえない。
Step 7: schedule・監視・retryを運用する
低遅延が必要ならevent-driven、取りこぼし対策にはscheduled catch-up、必要なら両方を使う。同じsourceを複数workerが競合更新しないよう、version checkまたはsource単位の直列化を行う。
event受信、source parse、chunk出力、upsert受付、delete受付、cache無効化、検証完了をstage別に数え、lagを測る。Azure AI Searchのstatus APIでは最新結果と直近のexecution historyを取得でき、処理件数と失敗件数も確認できる。ただし、これはpipelineの証跡であって、アプリのretrievalが正しい証明ではない。end-to-end probeを追加する。
Step 8: 定期照合とreplayを用意する
定期的に次を比較する。
- source inventoryとactive manifest
- manifestのchunk IDとkeyword/vector ID
- sourceのcontent・ACL versionとindex metadata
- tombstoneと、現在も検索可能な派生record
不一致はmissing、stale、orphaned、ACL-divergent、duplicateなどに分類する。専用の未検証repair処理を作らず、通常の冪等handlerへversion付きrepair eventを流す。
connector、tenant、source、期間を絞ってreplayできるだけのimmutable eventまたはsnapshotを残す。Azure indexer resetは全件再処理のための製品機能だが、reset後にはrunが必要で、orphan documentを自動cleanupしない。replayと削除確認は別々に考える。
ありがちな落とし穴
- retryのたびにrandomなchunk IDを作る
- chunk配列のpositionだけを安定IDに使う
- 新versionの後に届いた古いeventを適用する
- downstream workerがdelete markerを見る前にsourceを物理削除する
- resetや全件reindexでorphanも自動的に消えると思い込む
- vectorだけ消し、keyword document、抽出text、cacheを残す
- stale dataが入った後からdeletion policyを設定する
- content timestampをACL変更timestampとして使う
- retrievalの鮮度ではなくschedulerのsuccessだけを測る
- storeのoverwrite・merge契約を確かめずにupsertをretryする
- 廃止IDを特定する前にmanifestを置き換える
- 通常経路と別の非冪等なrepair pathで照合結果を直す
- tenant、connector、source単位のreplay境界を持たない
- write受付responseだけでretrievalが収束したと判断する
チェックリスト
- [ ] すべてのsourceに不変かつtenant-scopedな
source_idがある - [ ] すべてのchunk IDがretry間で決定的に再生成できる
- [ ] chunk identityを現在の配列positionだけに依存させていない
- [ ] sourceのcontent versionとACL versionを別々に追跡する
- [ ] 古いeventとduplicate eventが新しいstateを上書きしない
- [ ] 選んだstoreのupsert、merge、consistency、error semanticsを確認した
- [ ] source manifestに現在の全chunk IDを記録する
- [ ] 新manifest確定前に廃止chunk IDを特定する
- [ ] delete時は派生データcleanupより先にdurable tombstoneを作る
- [ ] tombstone保持期間がretry、遅延配送、restore policyをカバーする
- [ ] keyword record、vector、抽出artifact、enrichment、cacheを削除対象に含める
- [ ] productionと同じretrieval経路で削除を検証する
- [ ] ACLだけの変更でもchunk metadataとcacheを更新する
- [ ] ACL metadata欠落・不一致はfail closedにする
- [ ] 更新・削除・ACL反映に別々のfreshness SLOがある
- [ ] dashboardでend-to-end lagと最古の未完了eventを確認できる
- [ ] failure・partial runを重複recordなしでretryできる
- [ ] 照合でmissing、stale、orphaned、ACL-divergentを検出する
- [ ] repair eventを通常の冪等取り込み経路へ流す
- [ ] connector、tenant、source、期間を絞ってreplayできる
- [ ] 全件rebuild訓練にorphan cleanupとretrieval probeを含める
- [ ] backupとexportにも削除・保持ruleを適用する
FAQ
1. 文書更新はupsertだけで十分?
storeのIDとoverwrite契約を理解し、旧chunkを削除できる場合に限る。Pineconeでは既存IDへのupsertがrecord全体をoverwriteする。ただし、以前のchunkingで作られた別IDまでは消えない。manifestを持ち、廃止された集合を明示的に削除する必要がある。
2. 全件reindexをすればdelete処理は不要?
一般論としては置き換えられない。既存recordをoverwriteしても、sourceから消えたorphanが残るrebuildがある。Azure AI Searchでもresetとrunだけではorphan documentを削除しない。対応する削除検出を最初から設定するか、明示的なdelete actionを発行し、retrievalで確認する。
3. freshness SLOはどう決める?
user影響とsecurity影響から逆算する。権限取り消しや法的削除は、通常の本文更新より厳しい期限が必要な場合がある。connector delay、queue、処理、index可視化、cache invalidationを含め、schedule間隔ではなく経路全体を測る。
4. vector削除後もtombstoneを残す理由は?
遅れて届いたupdate、retry、replayで削除済み文書が復活するのを防ぐため。tombstoneが削除versionを示し、それより古いeventを拒否する。保持期間はconnectorの最大遅延、replay window、restore動作、保持要件から決める。
5. 照合完了をどう判断する?
期待するsource母集団を定義し、source inventory、manifest、index、tombstone間でIDとversionを比較する。jobがerror 0で終わっても、最初からjobへ渡されなかったsourceの欠落は検出できない。
参考資料
- indexer・skill・documentのrun/reset(Microsoft Learn)
- Azure SQL indexerの変更・削除検出(Microsoft Learn)
- Azure AI Searchで変更・削除されたblobを扱う(Microsoft Learn)
- index projectionを定義する(Microsoft Learn)
- enrichment cacheを設定する(Microsoft Learn)
- recordをupsertする(Pinecone Docs)
- recordを削除する・API version 2026-04(Pinecone Docs)
- push REST APIでACLをindexする(Microsoft Learn)
- indexer実行をscheduleする(Microsoft Learn)
- indexerのstatusと結果を監視する(Microsoft Learn)
- Pinecone quickstart
内部リンク
- 親記事(Hub):AI開発:まずはここから
- 関連記事:
免責事項
一般的な開発・セキュリティ情報です。lifecycle、API version、consistency、retention、削除、権限の実際の動作は、利用中のsource system、search platform、vector store、契約、法規制に照らして検証してください。