Deleting a document orphans its segment-attachment vectors and destroys attachments other documents still reference
まだ誰も着手していません。
評価
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 初心者へのやさしさ
- 72/100
調査の方向性
Start with api/tasks/clean_document_task.py and the batch-clean path dispatched from api/services/dataset_service.py:2074, then compare their cleanup flow with delete_segment_from_index_task.py and document_indexing_update_task.py. Run the shared-segment-image case in test_segment_index_cleanup_tasks.py and verify document deletion removes unreferenced attachment vectors, rows, and blobs while preserving attachments still referenced elsewhere.
索引モデルが issue の本文から書いたものです。
説明
Self Checks
- I have read the Contributing Guide and Language Policy
- I have searched for existing issues, including closed ones
- I confirm that I am using English to submit this report
Dify version
main at 22aff66cc0
Cloud or Self Hosted
Self Hosted (Source), Cloud
Steps to reproduce
In a multimodal knowledge base, delete a document that has segments with attachments. Both deletion paths mishandle those attachments: clean_document_task (single delete, dispatched from api/events/event_handlers/clean_when_document_deleted.py:13) and batch_clean_document_task (batch delete, dispatched from api/services/dataset_service.py:2074).
1. The attachment vectors are never removed.
Attachment vectors are written under doc_id == UploadFile.id (api/core/rag/datasource/vdb/vector_factory.py:201,209), but the node id list handed to index_processor.clean is built only from DocumentSegment.index_node_id:
# api/tasks/clean_document_task.py:64
index_node_ids = [segment.index_node_id for segment in segments if segment.index_node_id]
so the attachment vectors outlive the document permanently. RetrievalService.get_segment_attachment_infos then finds no UploadFile/binding for them and drops them silently, so they keep consuming top-k slots and quietly degrade recall for every subsequent query against that collection.
2. An attachment another document still references is destroyed.
SegmentAttachmentBinding.attachment_id is a user-supplied UploadFile id copied verbatim in SegmentService.create_segment (api/services/dataset_service.py:3512-3521) and carries no uniqueness constraint, so the same image may legitimately be bound to segments of several documents. Both tasks delete the UploadFile row and its storage blob for every binding the deleted document held, with no check for bindings that survive — and in the single-delete path the UploadFile delete even runs before the binding delete:
# api/tasks/clean_document_task.py:137-145
if attachment_ids:
session.execute(delete(UploadFile).where(UploadFile.id.in_(attachment_ids)))
if binding_ids:
session.execute(delete(SegmentAttachmentBinding).where(SegmentAttachmentBinding.id.in_(binding_ids)))
The rest of the codebase already treats this as the contract. delete_segment_from_index_task.py:86-121 and document_indexing_update_task.py:103-150 both delete the bindings, flush(), recompute orphan_attachment_ids from the bindings that remain, clean only those from the vector store, and only then drop the rows and blobs. test_segment_index_cleanup_tasks.py even has a shared-segment-image case pinning it. The two document-deletion tasks are the only paths that skip both steps.
✔️ Expected Behavior
Deleting a document removes the vectors, rows and blobs of the attachments nothing else references, and leaves attachments that another document still binds untouched — the same contract delete_segment_from_index_task already implements.
❌ Actual Behavior
Attachment vectors are orphaned in the collection forever, and an attachment shared with another document has its row and blob deleted out from under that document, so the surviving document's segment renders a broken attachment.
- 主要言語
- TypeScript
- スター
- 157k
- フォーク
- 24.7k
- 平均マージ
- 22時間 32分
- マージ済み PR(30日)
- 611
コントリビューションガイド
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
langgenius/dify のほかの issue
-
Annotation Reply: a stored score threshold of 0.0 is silently replaced with 1, disabling the feature オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 88/100
langgenius/dify#42639 · コメント 1 件 · リアクション 1 件 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 70/100
langgenius/dify#42468 · コメント 1 件 · リアクション 1 件 ·
-
🐞 bug
難易度 2/5 1〜3時間 初心者へのやさしさ 86/100
langgenius/dify#42446 · リアクション 1 件 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 88/100
langgenius/dify#42355 · コメント 1 件 · リアクション 1 件 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 88/100
langgenius/dify#42350 · コメント 1 件 · リアクション 1 件 ·
langgenius/dify の issue をすべて見る
似ている issue
-
calcite-components needs triage refactor
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
Esri/calcite-design-system#15203 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 91/100
-
community first-timers-only good first issue hacktoberfest help wanted low hanging fruit up-for-grabs
難易度 1/5 1時間未満 初心者へのやさしさ 95/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
Automattic/studio#4908 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 90/100