[docs]classRedisStore(ByteStore):"""BaseStore implementation using Redis as the underlying store. Examples: Create a RedisStore instance and perform operations on it: .. code-block:: python # Instantiate the RedisStore with a Redis connection from langchain_community.storage import RedisStore from langchain_community.utilities.redis import get_client client = get_client('redis://localhost:6379') redis_store = RedisStore(client=client) # Set values for keys redis_store.mset([("key1", b"value1"), ("key2", b"value2")]) # Get values for keys values = redis_store.mget(["key1", "key2"]) # [b"value1", b"value2"] # Delete keys redis_store.mdelete(["key1"]) # Iterate over keys for key in redis_store.yield_keys(): print(key) # noqa: T201 """
[docs]def__init__(self,*,client:Any=None,redis_url:Optional[str]=None,client_kwargs:Optional[dict]=None,ttl:Optional[int]=None,namespace:Optional[str]=None,)->None:"""Initialize the RedisStore with a Redis connection. Must provide either a Redis client or a redis_url with optional client_kwargs. Args: client: A Redis connection instance redis_url: redis url client_kwargs: Keyword arguments to pass to the Redis client ttl: time to expire keys in seconds if provided, if None keys will never expire namespace: if provided, all keys will be prefixed with this namespace """try:fromredisimportRedisexceptImportErrorase:raiseImportError("The RedisStore requires the redis library to be installed. ""pip install redis")fromeifclientand(redis_urlorclient_kwargs):raiseValueError("Either a Redis client or a redis_url with optional client_kwargs ""must be provided, but not both.")ifnotclientandnotredis_url:raiseValueError("Either a Redis client or a redis_url must be provided.")ifclient:ifnotisinstance(client,Redis):raiseTypeError(f"Expected Redis client, got {type(client).__name__} instead.")_client=clientelse:ifnotredis_url:raiseValueError("Either a Redis client or a redis_url must be provided.")_client=get_client(redis_url,**(client_kwargsor{}))self.client=_clientifnotisinstance(ttl,int)andttlisnotNone:raiseTypeError(f"Expected int or None, got {type(ttl)=} instead.")self.ttl=ttlself.namespace=namespace
def_get_prefixed_key(self,key:str)->str:"""Get the key with the namespace prefix. Args: key (str): The original key. Returns: str: The key with the namespace prefix. """delimiter="/"ifself.namespace:returnf"{self.namespace}{delimiter}{key}"returnkey
[docs]defmget(self,keys:Sequence[str])->List[Optional[bytes]]:"""Get the values associated with the given keys."""returncast(List[Optional[bytes]],self.client.mget([self._get_prefixed_key(key)forkeyinkeys]),)
[docs]defmset(self,key_value_pairs:Sequence[Tuple[str,bytes]])->None:"""Set the given key-value pairs."""pipe=self.client.pipeline()forkey,valueinkey_value_pairs:pipe.set(self._get_prefixed_key(key),value,ex=self.ttl)pipe.execute()
[docs]defmdelete(self,keys:Sequence[str])->None:"""Delete the given keys."""_keys=[self._get_prefixed_key(key)forkeyinkeys]self.client.delete(*_keys)
[docs]defyield_keys(self,*,prefix:Optional[str]=None)->Iterator[str]:"""Yield keys in the store."""ifprefix:pattern=self._get_prefixed_key(prefix)else:pattern=self._get_prefixed_key("*")scan_iter=cast(Iterator[bytes],self.client.scan_iter(match=pattern))forkeyinscan_iter:decoded_key=key.decode("utf-8")ifself.namespace:relative_key=decoded_key[len(self.namespace)+1:]yieldrelative_keyelse:yielddecoded_key