Skip to content

Python: fix FAISS delete leaving stale vectors after removing several records - #14702

Open
alexcastgonz (pcbeingused333) wants to merge 2 commits into
microsoft:mainfrom
pcbeingused333:fix/faiss-delete-multiple
Open

alexcastgonz (pcbeingused333) wants to merge 2 commits into
microsoft:mainfrom
pcbeingused333:fix/faiss-delete-multiple

Conversation

@pcbeingused333

Copy link
Copy Markdown
Contributor

Fixes #14695

Motivation and Context

FaissCollection.delete with several keys leaves stale vectors in the FAISS index: the repro in #14695 ends with ntotal == 1 and an empty key map, so later searches can return vectors for records that no longer exist.

Root cause: _inner_delete removes a vector with remove_ids, which shifts every later vector in a flat index down by one position, but the key map kept the old positions. Every delete after the first then targeted the wrong position.

Description

After removing a key's vector, decrement the stored position of every key that sat after it in the same vector field's map. The change is limited to _inner_delete in python/semantic_kernel/connectors/faiss.py.

Tests added in tests/unit/connectors/memory/test_faiss.py:

  • test_delete_multiple_keeps_index_in_sync: the issue's scenario; index and key map are empty after deleting all records.
  • test_delete_updates_remaining_positions: positions stay correct after partial deletes.

Both fail on main and pass with the change; the rest of test_faiss.py passes, and ruff format --check / ruff check are clean on the touched files.

Contribution Checklist

This change was prepared with the help of an AI coding assistant.

… records

remove_ids shifts every later vector down by one position, but the key map kept the old positions, so later deletes removed the wrong vectors. Update the remaining positions after each removal.
Copilot AI balanced review requested due to automatic review settings November 1, 2026 00:07
@semantic-kernel-automation semantic-kernel-automation Bot added the python Pull requests for the Python Semantic Kernel label Nov 1, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Deletion can corrupt key mappings when index removal fails and incorrectly renumber stable-ID indexes, leaving orphaned vectors.

2 open issues
What changed in this PR

This PR addresses #14695 by updating the Python FAISS connector’s key mappings after flat-index deletions, preventing subsequent deletes from targeting stale positions.

Changes:

  • Decrement later mapped positions after each vector removal.
  • Add regression tests for deleting all records and maintaining correct positions after partial deletes.
File Description
python/​tests/​unit/​connectors/​memory/​test_faiss.py Adds full and partial deletion regression tests.
python/​semantic_kernel/​connectors/​faiss.py Updates remaining key positions after vector deletion.

Review effort: Balanced

Comment on lines 193 to 194
vector_index = key_map.pop(key)
self.indexes[vector_field].remove_ids(np.array([vector_index]))
Comment on lines +195 to +198
# removing a vector shifts every later vector down by one position
for other_key, position in key_map.items():
if position > vector_index:
key_map[other_key] = position - 1
…n-flat indexes

Remove the vector from the index before dropping the key mapping. Only flat indexes compact ids on removal, which the key map relies on (positions in search, start offset in upsert), so deleting from other indexes (e.g. IVF, HNSW) is rejected before anything is mutated.
@pcbeingused333

Copy link
Copy Markdown
Contributor Author

Thanks, both Copilot points were valid and are addressed in the new commit:

  • _inner_delete now calls remove_ids first and drops the key mapping only after it succeeds, so an index that can't remove vectors (e.g. the custom IndexHNSWFlat) no longer loses its mapping. Test: test_delete_keeps_key_map_when_index_cannot_remove.
  • Only flat indexes compact ids on removal, and the key map relies on that (search resolves ids by position, upsert starts from the current count). Deleting from any other index (e.g. IVF, HNSW) now raises VectorStoreOperationException before anything is mutated, instead of leaving a broken mapping. Test: test_delete_rejected_for_index_that_preserves_ids.

Both new tests fail against the previous revision; tests/unit/connectors/memory/test_faiss.py passes (25 tests) and ruff format/ruff check are clean.

This comment was drafted with Claude Code.

This branch was successfully deployed

1 active deployment
github-app-auth — 4de28a86 Deployed Nov 1, 2026 by pcbeingused333 via add_label #29527
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

python Pull requests for the Python Semantic Kernel

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Python: Bug: Python FAISS flat index retains vectors after deleting records

2 participants