Skip to content

Commit 75d1473

Browse files
Add ability drop all keys from the index (#183)
From our chat today I'm pulling out this method from the semantic cache and moving it into index. Rather can modify the `clear()` method to take an optional list of keys it's a new method. The goal is to stop the accidental calling of clear() with no args, thinking it will clear no keys, but actually delete everything.
1 parent 042f7d8 commit 75d1473

File tree

3 files changed

+94
-0
lines changed

3 files changed

+94
-0
lines changed

redisvl/index/index.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,20 @@ def clear(self) -> int:
497497

498498
return total_records_deleted
499499

500+
def drop_keys(self, keys: Union[str, List[str]]) -> int:
501+
"""Remove a specific entry or entries from the index by it's key ID.
502+
503+
Args:
504+
keys (Union[str, List[str]]): The document ID or IDs to remove from the index.
505+
506+
Returns:
507+
int: Count of records deleted from Redis.
508+
"""
509+
if isinstance(keys, List):
510+
return self._redis_client.delete(*keys) # type: ignore
511+
else:
512+
return self._redis_client.delete(keys) # type: ignore
513+
500514
def load(
501515
self,
502516
data: Iterable[Any],
@@ -935,6 +949,20 @@ async def clear(self) -> int:
935949

936950
return total_records_deleted
937951

952+
async def drop_keys(self, keys: Union[str, List[str]]) -> int:
953+
"""Remove a specific entry or entries from the index by it's key ID.
954+
955+
Args:
956+
keys (Union[str, List[str]]): The document ID or IDs to remove from the index.
957+
958+
Returns:
959+
int: Count of records deleted from Redis.
960+
"""
961+
if isinstance(keys, List):
962+
return await self._redis_client.delete(*keys) # type: ignore
963+
else:
964+
return await self._redis_client.delete(keys) # type: ignore
965+
938966
async def load(
939967
self,
940968
data: Iterable[Any],

tests/integration/test_async_search_index.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,39 @@ async def test_search_index_clear(async_client, async_index):
184184
assert await async_index.exists()
185185

186186

187+
@pytest.mark.asyncio
188+
async def test_search_index_drop_key(async_client, async_index):
189+
async_index.set_client(async_client)
190+
await async_index.create(overwrite=True, drop=True)
191+
data = [{"id": "1", "test": "foo"}, {"id": "2", "test": "bar"}]
192+
keys = await async_index.load(data, id_field="id")
193+
194+
dropped = await async_index.drop_keys(keys[0])
195+
assert dropped == 1
196+
assert not await async_index.fetch(keys[0])
197+
assert await async_index.fetch(keys[1]) is not None
198+
199+
200+
@pytest.mark.asyncio
201+
async def test_search_index_drop_keys(async_client, async_index):
202+
async_index.set_client(async_client)
203+
await async_index.create(overwrite=True, drop=True)
204+
data = [
205+
{"id": "1", "test": "foo"},
206+
{"id": "2", "test": "bar"},
207+
{"id": "3", "test": "baz"},
208+
]
209+
keys = await async_index.load(data, id_field="id")
210+
211+
dropped = await async_index.drop_keys(keys[0:2])
212+
assert dropped == 2
213+
assert not await async_index.fetch(keys[0])
214+
assert not await async_index.fetch(keys[1])
215+
assert await async_index.fetch(keys[2]) is not None
216+
217+
assert await async_index.exists()
218+
219+
187220
@pytest.mark.asyncio
188221
async def test_search_index_load_and_fetch(async_client, async_index):
189222
async_index.set_client(async_client)

tests/integration/test_search_index.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,39 @@ def test_search_index_clear(client, index):
170170
assert index.exists()
171171

172172

173+
def test_search_index_drop_key(client, index):
174+
index.set_client(client)
175+
index.create(overwrite=True, drop=True)
176+
data = [{"id": "1", "test": "foo"}, {"id": "2", "test": "bar"}]
177+
keys = index.load(data, id_field="id")
178+
179+
# test passing a single string key removes only that key
180+
dropped = index.drop_keys(keys[0])
181+
assert dropped == 1
182+
assert not index.fetch(keys[0])
183+
assert index.fetch(keys[1]) is not None # still have all other entries
184+
185+
186+
def test_search_index_drop_keys(client, index):
187+
index.set_client(client)
188+
index.create(overwrite=True, drop=True)
189+
data = [
190+
{"id": "1", "test": "foo"},
191+
{"id": "2", "test": "bar"},
192+
{"id": "3", "test": "baz"},
193+
]
194+
keys = index.load(data, id_field="id")
195+
196+
# test passing a list of keys selectively removes only those keys
197+
dropped = index.drop_keys(keys[0:2])
198+
assert dropped == 2
199+
assert not index.fetch(keys[0])
200+
assert not index.fetch(keys[1])
201+
assert index.fetch(keys[2]) is not None
202+
203+
assert index.exists()
204+
205+
173206
def test_search_index_load_and_fetch(client, index):
174207
index.set_client(client)
175208
index.create(overwrite=True, drop=True)

0 commit comments

Comments
 (0)