Skip to content

Commit 53ab49d

Browse files
committed
Add a drop_documents() method to search index classes
1 parent 61334ff commit 53ab49d

File tree

3 files changed

+105
-1
lines changed

3 files changed

+105
-1
lines changed

redisvl/index/index.py

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,27 @@ def drop_keys(self, keys: Union[str, List[str]]) -> int:
592592
else:
593593
return self._redis_client.delete(keys) # type: ignore
594594

595+
def drop_documents(self, ids: Union[str, List[str]]) -> int:
596+
"""Remove documents from the index by their document IDs.
597+
598+
This method converts document IDs to Redis keys automatically by applying
599+
the index's key prefix and separator configuration.
600+
601+
Args:
602+
ids (Union[str, List[str]]): The document ID or IDs to remove from the index.
603+
604+
Returns:
605+
int: Count of documents deleted from Redis.
606+
"""
607+
if isinstance(ids, list):
608+
if not ids:
609+
return 0
610+
keys = [self.key(id) for id in ids]
611+
return self._redis_client.delete(*keys) # type: ignore
612+
else:
613+
key = self.key(ids)
614+
return self._redis_client.delete(key) # type: ignore
615+
595616
def expire_keys(
596617
self, keys: Union[str, List[str]], ttl: int
597618
) -> Union[int, List[int]]:
@@ -1236,6 +1257,28 @@ async def drop_keys(self, keys: Union[str, List[str]]) -> int:
12361257
else:
12371258
return await client.delete(keys)
12381259

1260+
async def drop_documents(self, ids: Union[str, List[str]]) -> int:
1261+
"""Remove documents from the index by their document IDs.
1262+
1263+
This method converts document IDs to Redis keys automatically by applying
1264+
the index's key prefix and separator configuration.
1265+
1266+
Args:
1267+
ids (Union[str, List[str]]): The document ID or IDs to remove from the index.
1268+
1269+
Returns:
1270+
int: Count of documents deleted from Redis.
1271+
"""
1272+
client = await self._get_client()
1273+
if isinstance(ids, list):
1274+
if not ids:
1275+
return 0
1276+
keys = [self.key(id) for id in ids]
1277+
return await client.delete(*keys)
1278+
else:
1279+
key = self.key(ids)
1280+
return await client.delete(key)
1281+
12391282
async def expire_keys(
12401283
self, keys: Union[str, List[str]], ttl: int
12411284
) -> Union[int, List[int]]:
@@ -1356,7 +1399,7 @@ async def fetch(self, id: str) -> Optional[Dict[str, Any]]:
13561399
async def _aggregate(
13571400
self, aggregation_query: AggregationQuery
13581401
) -> List[Dict[str, Any]]:
1359-
"""Execute an aggretation query and processes the results."""
1402+
"""Execute an aggregation query and processes the results."""
13601403
results = await self.aggregate(
13611404
aggregation_query, query_params=aggregation_query.params # type: ignore[attr-defined]
13621405
)

tests/integration/test_async_search_index.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,37 @@ async def test_search_index_drop_keys(async_index):
246246
assert await async_index.exists()
247247

248248

249+
@pytest.mark.asyncio
250+
async def test_search_index_drop_documents(async_index):
251+
await async_index.create(overwrite=True, drop=True)
252+
data = [
253+
{"id": "1", "test": "foo"},
254+
{"id": "2", "test": "bar"},
255+
{"id": "3", "test": "baz"},
256+
]
257+
await async_index.load(data, id_field="id")
258+
259+
# Test dropping a single document by ID
260+
dropped = await async_index.drop_documents("1")
261+
assert dropped == 1
262+
assert not await async_index.fetch("1")
263+
assert await async_index.fetch("2") is not None
264+
assert await async_index.fetch("3") is not None
265+
266+
# Test dropping multiple documents by ID
267+
dropped = await async_index.drop_documents(["2", "3"])
268+
assert dropped == 2
269+
assert not await async_index.fetch("2")
270+
assert not await async_index.fetch("3")
271+
272+
# Test dropping with an empty list
273+
dropped = await async_index.drop_documents([])
274+
assert dropped == 0
275+
276+
# Ensure the index still exists
277+
assert await async_index.exists()
278+
279+
249280
@pytest.mark.asyncio
250281
async def test_search_index_load_and_fetch(async_index):
251282
await async_index.create(overwrite=True, drop=True)

tests/integration/test_search_index.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,36 @@ def test_search_index_drop_keys(index):
240240
assert index.exists()
241241

242242

243+
def test_search_index_drop_documents(index):
244+
index.create(overwrite=True, drop=True)
245+
data = [
246+
{"id": "1", "test": "foo"},
247+
{"id": "2", "test": "bar"},
248+
{"id": "3", "test": "baz"},
249+
]
250+
index.load(data, id_field="id")
251+
252+
# Test dropping a single document by ID
253+
dropped = index.drop_documents("1")
254+
assert dropped == 1
255+
assert not index.fetch("1")
256+
assert index.fetch("2") is not None
257+
assert index.fetch("3") is not None
258+
259+
# Test dropping multiple documents by ID
260+
dropped = index.drop_documents(["2", "3"])
261+
assert dropped == 2
262+
assert not index.fetch("2")
263+
assert not index.fetch("3")
264+
265+
# Test dropping with an empty list
266+
dropped = index.drop_documents([])
267+
assert dropped == 0
268+
269+
# Ensure the index still exists
270+
assert index.exists()
271+
272+
243273
def test_search_index_load_and_fetch(index):
244274
index.create(overwrite=True, drop=True)
245275
data = [{"id": "1", "test": "foo"}]

0 commit comments

Comments
 (0)