Current behavior
SearchIndex.drop_keys (redisvl/index/index.py:826) issues a synchronous DEL:
def drop_keys(self, keys: str | list[str]) -> int:
if isinstance(keys, list):
return self._redis_client.delete(*keys)
else:
return self._redis_client.delete(keys)
DEL reclaims memory on the main thread. A single drop of tens of thousands of keys stalls the server proportionally to the freed keyspace. For a SemanticCache use case where scope-targeted invalidation routinely produces sweeps in the 10K–1M+ range (e.g., a policy version rollover in a multi-tenant deployment), this is a customer-visible latency event on every invalidation.
Proposed change
Switch the bulk path to UNLINK, which queues memory reclamation on a background thread:
return self._redis_client.unlink(*keys)
UNLINK returns the same count semantics. It is available on Redis 4+ so there is no minimum-version concern for current RedisVL targets.
If there is a reason to preserve DEL semantics for some callers, expose use_unlink: bool = True and default to True.
Backwards compatibility
UNLINK is a strict superset of DEL for this use case. The only observable difference is that the keys may not be immediately reclaimed from a MEMORY USAGE standpoint — which is the point. Behavior in tests and at the protocol level is identical.
Notes
Surfaced while writing a scoped semantic caching architecture spec. Also relevant to SemanticCache.drop(), which calls drop_keys under the hood when invoked with keys=.
Current behavior
SearchIndex.drop_keys(redisvl/index/index.py:826) issues a synchronousDEL:DELreclaims memory on the main thread. A single drop of tens of thousands of keys stalls the server proportionally to the freed keyspace. For aSemanticCacheuse case where scope-targeted invalidation routinely produces sweeps in the 10K–1M+ range (e.g., a policy version rollover in a multi-tenant deployment), this is a customer-visible latency event on every invalidation.Proposed change
Switch the bulk path to
UNLINK, which queues memory reclamation on a background thread:UNLINKreturns the same count semantics. It is available on Redis 4+ so there is no minimum-version concern for current RedisVL targets.If there is a reason to preserve
DELsemantics for some callers, exposeuse_unlink: bool = Trueand default toTrue.Backwards compatibility
UNLINKis a strict superset ofDELfor this use case. The only observable difference is that the keys may not be immediately reclaimed from aMEMORY USAGEstandpoint — which is the point. Behavior in tests and at the protocol level is identical.Notes
Surfaced while writing a scoped semantic caching architecture spec. Also relevant to
SemanticCache.drop(), which callsdrop_keysunder the hood when invoked withkeys=.