redis 6.0.0b1__py3-none-any.whl → 6.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- redis/__init__.py +9 -1
- redis/_parsers/resp3.py +2 -2
- redis/asyncio/client.py +83 -71
- redis/asyncio/cluster.py +74 -50
- redis/asyncio/connection.py +43 -17
- redis/asyncio/retry.py +12 -0
- redis/asyncio/sentinel.py +2 -0
- redis/backoff.py +54 -0
- redis/client.py +99 -89
- redis/cluster.py +1085 -359
- redis/commands/core.py +105 -105
- redis/commands/helpers.py +19 -6
- redis/commands/json/__init__.py +1 -1
- redis/commands/json/commands.py +8 -8
- redis/commands/redismodules.py +27 -9
- redis/commands/search/commands.py +2 -2
- redis/commands/timeseries/__init__.py +1 -1
- redis/commands/vectorset/__init__.py +46 -0
- redis/commands/vectorset/commands.py +367 -0
- redis/commands/vectorset/utils.py +94 -0
- redis/connection.py +46 -13
- redis/exceptions.py +18 -0
- redis/retry.py +25 -0
- redis/sentinel.py +2 -0
- redis/utils.py +7 -0
- {redis-6.0.0b1.dist-info → redis-6.1.0.dist-info}/METADATA +14 -8
- {redis-6.0.0b1.dist-info → redis-6.1.0.dist-info}/RECORD +29 -26
- {redis-6.0.0b1.dist-info → redis-6.1.0.dist-info}/WHEEL +0 -0
- {redis-6.0.0b1.dist-info → redis-6.1.0.dist-info}/licenses/LICENSE +0 -0
redis/commands/helpers.py
CHANGED
|
@@ -43,19 +43,32 @@ def parse_to_list(response):
|
|
|
43
43
|
"""Optimistically parse the response to a list."""
|
|
44
44
|
res = []
|
|
45
45
|
|
|
46
|
+
special_values = {"infinity", "nan", "-infinity"}
|
|
47
|
+
|
|
46
48
|
if response is None:
|
|
47
49
|
return res
|
|
48
50
|
|
|
49
51
|
for item in response:
|
|
52
|
+
if item is None:
|
|
53
|
+
res.append(None)
|
|
54
|
+
continue
|
|
50
55
|
try:
|
|
51
|
-
|
|
52
|
-
except ValueError:
|
|
53
|
-
try:
|
|
54
|
-
res.append(float(item))
|
|
55
|
-
except ValueError:
|
|
56
|
-
res.append(nativestr(item))
|
|
56
|
+
item_str = nativestr(item)
|
|
57
57
|
except TypeError:
|
|
58
58
|
res.append(None)
|
|
59
|
+
continue
|
|
60
|
+
|
|
61
|
+
if isinstance(item_str, str) and item_str.lower() in special_values:
|
|
62
|
+
res.append(item_str) # Keep as string
|
|
63
|
+
else:
|
|
64
|
+
try:
|
|
65
|
+
res.append(int(item))
|
|
66
|
+
except ValueError:
|
|
67
|
+
try:
|
|
68
|
+
res.append(float(item))
|
|
69
|
+
except ValueError:
|
|
70
|
+
res.append(item_str)
|
|
71
|
+
|
|
59
72
|
return res
|
|
60
73
|
|
|
61
74
|
|
redis/commands/json/__init__.py
CHANGED
|
@@ -120,7 +120,7 @@ class JSON(JSONCommands):
|
|
|
120
120
|
startup_nodes=self.client.nodes_manager.startup_nodes,
|
|
121
121
|
result_callbacks=self.client.result_callbacks,
|
|
122
122
|
cluster_response_callbacks=self.client.cluster_response_callbacks,
|
|
123
|
-
cluster_error_retry_attempts=self.client.
|
|
123
|
+
cluster_error_retry_attempts=self.client.retry.get_retries(),
|
|
124
124
|
read_from_replicas=self.client.read_from_replicas,
|
|
125
125
|
reinitialize_steps=self.client.reinitialize_steps,
|
|
126
126
|
lock=self.client._lock,
|
redis/commands/json/commands.py
CHANGED
|
@@ -15,7 +15,7 @@ class JSONCommands:
|
|
|
15
15
|
|
|
16
16
|
def arrappend(
|
|
17
17
|
self, name: str, path: Optional[str] = Path.root_path(), *args: List[JsonType]
|
|
18
|
-
) -> List[
|
|
18
|
+
) -> List[Optional[int]]:
|
|
19
19
|
"""Append the objects ``args`` to the array under the
|
|
20
20
|
``path` in key ``name``.
|
|
21
21
|
|
|
@@ -33,7 +33,7 @@ class JSONCommands:
|
|
|
33
33
|
scalar: int,
|
|
34
34
|
start: Optional[int] = None,
|
|
35
35
|
stop: Optional[int] = None,
|
|
36
|
-
) -> List[
|
|
36
|
+
) -> List[Optional[int]]:
|
|
37
37
|
"""
|
|
38
38
|
Return the index of ``scalar`` in the JSON array under ``path`` at key
|
|
39
39
|
``name``.
|
|
@@ -53,7 +53,7 @@ class JSONCommands:
|
|
|
53
53
|
|
|
54
54
|
def arrinsert(
|
|
55
55
|
self, name: str, path: str, index: int, *args: List[JsonType]
|
|
56
|
-
) -> List[
|
|
56
|
+
) -> List[Optional[int]]:
|
|
57
57
|
"""Insert the objects ``args`` to the array at index ``index``
|
|
58
58
|
under the ``path` in key ``name``.
|
|
59
59
|
|
|
@@ -66,7 +66,7 @@ class JSONCommands:
|
|
|
66
66
|
|
|
67
67
|
def arrlen(
|
|
68
68
|
self, name: str, path: Optional[str] = Path.root_path()
|
|
69
|
-
) -> List[
|
|
69
|
+
) -> List[Optional[int]]:
|
|
70
70
|
"""Return the length of the array JSON value under ``path``
|
|
71
71
|
at key``name``.
|
|
72
72
|
|
|
@@ -79,7 +79,7 @@ class JSONCommands:
|
|
|
79
79
|
name: str,
|
|
80
80
|
path: Optional[str] = Path.root_path(),
|
|
81
81
|
index: Optional[int] = -1,
|
|
82
|
-
) -> List[
|
|
82
|
+
) -> List[Optional[str]]:
|
|
83
83
|
"""Pop the element at ``index`` in the array JSON value under
|
|
84
84
|
``path`` at key ``name``.
|
|
85
85
|
|
|
@@ -89,7 +89,7 @@ class JSONCommands:
|
|
|
89
89
|
|
|
90
90
|
def arrtrim(
|
|
91
91
|
self, name: str, path: str, start: int, stop: int
|
|
92
|
-
) -> List[
|
|
92
|
+
) -> List[Optional[int]]:
|
|
93
93
|
"""Trim the array JSON value under ``path`` at key ``name`` to the
|
|
94
94
|
inclusive range given by ``start`` and ``stop``.
|
|
95
95
|
|
|
@@ -113,7 +113,7 @@ class JSONCommands:
|
|
|
113
113
|
|
|
114
114
|
def objkeys(
|
|
115
115
|
self, name: str, path: Optional[str] = Path.root_path()
|
|
116
|
-
) -> List[
|
|
116
|
+
) -> List[Optional[List[str]]]:
|
|
117
117
|
"""Return the key names in the dictionary JSON value under ``path`` at
|
|
118
118
|
key ``name``.
|
|
119
119
|
|
|
@@ -357,7 +357,7 @@ class JSONCommands:
|
|
|
357
357
|
|
|
358
358
|
return set_files_result
|
|
359
359
|
|
|
360
|
-
def strlen(self, name: str, path: Optional[str] = None) -> List[
|
|
360
|
+
def strlen(self, name: str, path: Optional[str] = None) -> List[Optional[int]]:
|
|
361
361
|
"""Return the length of the string JSON value under ``path`` at key
|
|
362
362
|
``name``.
|
|
363
363
|
|
redis/commands/redismodules.py
CHANGED
|
@@ -1,4 +1,14 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
from json import JSONDecoder, JSONEncoder
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from .bf import BFBloom, CFBloom, CMSBloom, TDigestBloom, TOPKBloom
|
|
8
|
+
from .json import JSON
|
|
9
|
+
from .search import AsyncSearch, Search
|
|
10
|
+
from .timeseries import TimeSeries
|
|
11
|
+
from .vectorset import VectorSet
|
|
2
12
|
|
|
3
13
|
|
|
4
14
|
class RedisModuleCommands:
|
|
@@ -6,7 +16,7 @@ class RedisModuleCommands:
|
|
|
6
16
|
modules into the command namespace.
|
|
7
17
|
"""
|
|
8
18
|
|
|
9
|
-
def json(self, encoder=JSONEncoder(), decoder=JSONDecoder()):
|
|
19
|
+
def json(self, encoder=JSONEncoder(), decoder=JSONDecoder()) -> JSON:
|
|
10
20
|
"""Access the json namespace, providing support for redis json."""
|
|
11
21
|
|
|
12
22
|
from .json import JSON
|
|
@@ -14,7 +24,7 @@ class RedisModuleCommands:
|
|
|
14
24
|
jj = JSON(client=self, encoder=encoder, decoder=decoder)
|
|
15
25
|
return jj
|
|
16
26
|
|
|
17
|
-
def ft(self, index_name="idx"):
|
|
27
|
+
def ft(self, index_name="idx") -> Search:
|
|
18
28
|
"""Access the search namespace, providing support for redis search."""
|
|
19
29
|
|
|
20
30
|
from .search import Search
|
|
@@ -22,7 +32,7 @@ class RedisModuleCommands:
|
|
|
22
32
|
s = Search(client=self, index_name=index_name)
|
|
23
33
|
return s
|
|
24
34
|
|
|
25
|
-
def ts(self):
|
|
35
|
+
def ts(self) -> TimeSeries:
|
|
26
36
|
"""Access the timeseries namespace, providing support for
|
|
27
37
|
redis timeseries data.
|
|
28
38
|
"""
|
|
@@ -32,7 +42,7 @@ class RedisModuleCommands:
|
|
|
32
42
|
s = TimeSeries(client=self)
|
|
33
43
|
return s
|
|
34
44
|
|
|
35
|
-
def bf(self):
|
|
45
|
+
def bf(self) -> BFBloom:
|
|
36
46
|
"""Access the bloom namespace."""
|
|
37
47
|
|
|
38
48
|
from .bf import BFBloom
|
|
@@ -40,7 +50,7 @@ class RedisModuleCommands:
|
|
|
40
50
|
bf = BFBloom(client=self)
|
|
41
51
|
return bf
|
|
42
52
|
|
|
43
|
-
def cf(self):
|
|
53
|
+
def cf(self) -> CFBloom:
|
|
44
54
|
"""Access the bloom namespace."""
|
|
45
55
|
|
|
46
56
|
from .bf import CFBloom
|
|
@@ -48,7 +58,7 @@ class RedisModuleCommands:
|
|
|
48
58
|
cf = CFBloom(client=self)
|
|
49
59
|
return cf
|
|
50
60
|
|
|
51
|
-
def cms(self):
|
|
61
|
+
def cms(self) -> CMSBloom:
|
|
52
62
|
"""Access the bloom namespace."""
|
|
53
63
|
|
|
54
64
|
from .bf import CMSBloom
|
|
@@ -56,7 +66,7 @@ class RedisModuleCommands:
|
|
|
56
66
|
cms = CMSBloom(client=self)
|
|
57
67
|
return cms
|
|
58
68
|
|
|
59
|
-
def topk(self):
|
|
69
|
+
def topk(self) -> TOPKBloom:
|
|
60
70
|
"""Access the bloom namespace."""
|
|
61
71
|
|
|
62
72
|
from .bf import TOPKBloom
|
|
@@ -64,7 +74,7 @@ class RedisModuleCommands:
|
|
|
64
74
|
topk = TOPKBloom(client=self)
|
|
65
75
|
return topk
|
|
66
76
|
|
|
67
|
-
def tdigest(self):
|
|
77
|
+
def tdigest(self) -> TDigestBloom:
|
|
68
78
|
"""Access the bloom namespace."""
|
|
69
79
|
|
|
70
80
|
from .bf import TDigestBloom
|
|
@@ -72,9 +82,17 @@ class RedisModuleCommands:
|
|
|
72
82
|
tdigest = TDigestBloom(client=self)
|
|
73
83
|
return tdigest
|
|
74
84
|
|
|
85
|
+
def vset(self) -> VectorSet:
|
|
86
|
+
"""Access the VectorSet commands namespace."""
|
|
87
|
+
|
|
88
|
+
from .vectorset import VectorSet
|
|
89
|
+
|
|
90
|
+
vset = VectorSet(client=self)
|
|
91
|
+
return vset
|
|
92
|
+
|
|
75
93
|
|
|
76
94
|
class AsyncRedisModuleCommands(RedisModuleCommands):
|
|
77
|
-
def ft(self, index_name="idx"):
|
|
95
|
+
def ft(self, index_name="idx") -> AsyncSearch:
|
|
78
96
|
"""Access the search namespace, providing support for redis search."""
|
|
79
97
|
|
|
80
98
|
from .search import AsyncSearch
|
|
@@ -23,7 +23,6 @@ ALTER_CMD = "FT.ALTER"
|
|
|
23
23
|
SEARCH_CMD = "FT.SEARCH"
|
|
24
24
|
ADD_CMD = "FT.ADD"
|
|
25
25
|
ADDHASH_CMD = "FT.ADDHASH"
|
|
26
|
-
DROP_CMD = "FT.DROP"
|
|
27
26
|
DROPINDEX_CMD = "FT.DROPINDEX"
|
|
28
27
|
EXPLAIN_CMD = "FT.EXPLAIN"
|
|
29
28
|
EXPLAINCLI_CMD = "FT.EXPLAINCLI"
|
|
@@ -35,7 +34,6 @@ SPELLCHECK_CMD = "FT.SPELLCHECK"
|
|
|
35
34
|
DICT_ADD_CMD = "FT.DICTADD"
|
|
36
35
|
DICT_DEL_CMD = "FT.DICTDEL"
|
|
37
36
|
DICT_DUMP_CMD = "FT.DICTDUMP"
|
|
38
|
-
GET_CMD = "FT.GET"
|
|
39
37
|
MGET_CMD = "FT.MGET"
|
|
40
38
|
CONFIG_CMD = "FT.CONFIG"
|
|
41
39
|
TAGVALS_CMD = "FT.TAGVALS"
|
|
@@ -406,6 +404,7 @@ class SearchCommands:
|
|
|
406
404
|
doc_id, conn=None, score=score, language=language, replace=replace
|
|
407
405
|
)
|
|
408
406
|
|
|
407
|
+
@deprecated_function(version="2.0.0", reason="deprecated since redisearch 2.0")
|
|
409
408
|
def delete_document(self, doc_id, conn=None, delete_actual_document=False):
|
|
410
409
|
"""
|
|
411
410
|
Delete a document from index
|
|
@@ -440,6 +439,7 @@ class SearchCommands:
|
|
|
440
439
|
|
|
441
440
|
return Document(id=id, **fields)
|
|
442
441
|
|
|
442
|
+
@deprecated_function(version="2.0.0", reason="deprecated since redisearch 2.0")
|
|
443
443
|
def get(self, *ids):
|
|
444
444
|
"""
|
|
445
445
|
Returns the full contents of multiple documents.
|
|
@@ -84,7 +84,7 @@ class TimeSeries(TimeSeriesCommands):
|
|
|
84
84
|
startup_nodes=self.client.nodes_manager.startup_nodes,
|
|
85
85
|
result_callbacks=self.client.result_callbacks,
|
|
86
86
|
cluster_response_callbacks=self.client.cluster_response_callbacks,
|
|
87
|
-
cluster_error_retry_attempts=self.client.
|
|
87
|
+
cluster_error_retry_attempts=self.client.retry.get_retries(),
|
|
88
88
|
read_from_replicas=self.client.read_from_replicas,
|
|
89
89
|
reinitialize_steps=self.client.reinitialize_steps,
|
|
90
90
|
lock=self.client._lock,
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
from redis._parsers.helpers import pairs_to_dict
|
|
4
|
+
from redis.commands.vectorset.utils import (
|
|
5
|
+
parse_vemb_result,
|
|
6
|
+
parse_vlinks_result,
|
|
7
|
+
parse_vsim_result,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
from ..helpers import get_protocol_version
|
|
11
|
+
from .commands import (
|
|
12
|
+
VEMB_CMD,
|
|
13
|
+
VGETATTR_CMD,
|
|
14
|
+
VINFO_CMD,
|
|
15
|
+
VLINKS_CMD,
|
|
16
|
+
VSIM_CMD,
|
|
17
|
+
VectorSetCommands,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class VectorSet(VectorSetCommands):
|
|
22
|
+
def __init__(self, client, **kwargs):
|
|
23
|
+
"""Create a new VectorSet client."""
|
|
24
|
+
# Set the module commands' callbacks
|
|
25
|
+
self._MODULE_CALLBACKS = {
|
|
26
|
+
VEMB_CMD: parse_vemb_result,
|
|
27
|
+
VGETATTR_CMD: lambda r: r and json.loads(r) or None,
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
self._RESP2_MODULE_CALLBACKS = {
|
|
31
|
+
VINFO_CMD: lambda r: r and pairs_to_dict(r) or None,
|
|
32
|
+
VSIM_CMD: parse_vsim_result,
|
|
33
|
+
VLINKS_CMD: parse_vlinks_result,
|
|
34
|
+
}
|
|
35
|
+
self._RESP3_MODULE_CALLBACKS = {}
|
|
36
|
+
|
|
37
|
+
self.client = client
|
|
38
|
+
self.execute_command = client.execute_command
|
|
39
|
+
|
|
40
|
+
if get_protocol_version(self.client) in ["3", 3]:
|
|
41
|
+
self._MODULE_CALLBACKS.update(self._RESP3_MODULE_CALLBACKS)
|
|
42
|
+
else:
|
|
43
|
+
self._MODULE_CALLBACKS.update(self._RESP2_MODULE_CALLBACKS)
|
|
44
|
+
|
|
45
|
+
for k, v in self._MODULE_CALLBACKS.items():
|
|
46
|
+
self.client.set_response_callback(k, v)
|
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from enum import Enum
|
|
3
|
+
from typing import Awaitable, Dict, List, Optional, Union
|
|
4
|
+
|
|
5
|
+
from redis.client import NEVER_DECODE
|
|
6
|
+
from redis.commands.helpers import get_protocol_version
|
|
7
|
+
from redis.exceptions import DataError
|
|
8
|
+
from redis.typing import CommandsProtocol, EncodableT, KeyT, Number
|
|
9
|
+
|
|
10
|
+
VADD_CMD = "VADD"
|
|
11
|
+
VSIM_CMD = "VSIM"
|
|
12
|
+
VREM_CMD = "VREM"
|
|
13
|
+
VDIM_CMD = "VDIM"
|
|
14
|
+
VCARD_CMD = "VCARD"
|
|
15
|
+
VEMB_CMD = "VEMB"
|
|
16
|
+
VLINKS_CMD = "VLINKS"
|
|
17
|
+
VINFO_CMD = "VINFO"
|
|
18
|
+
VSETATTR_CMD = "VSETATTR"
|
|
19
|
+
VGETATTR_CMD = "VGETATTR"
|
|
20
|
+
VRANDMEMBER_CMD = "VRANDMEMBER"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class QuantizationOptions(Enum):
|
|
24
|
+
"""Quantization options for the VADD command."""
|
|
25
|
+
|
|
26
|
+
NOQUANT = "NOQUANT"
|
|
27
|
+
BIN = "BIN"
|
|
28
|
+
Q8 = "Q8"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class CallbacksOptions(Enum):
|
|
32
|
+
"""Options that can be set for the commands callbacks"""
|
|
33
|
+
|
|
34
|
+
RAW = "RAW"
|
|
35
|
+
WITHSCORES = "WITHSCORES"
|
|
36
|
+
ALLOW_DECODING = "ALLOW_DECODING"
|
|
37
|
+
RESP3 = "RESP3"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class VectorSetCommands(CommandsProtocol):
|
|
41
|
+
"""Redis VectorSet commands"""
|
|
42
|
+
|
|
43
|
+
def vadd(
|
|
44
|
+
self,
|
|
45
|
+
key: KeyT,
|
|
46
|
+
vector: Union[List[float], bytes],
|
|
47
|
+
element: str,
|
|
48
|
+
reduce_dim: Optional[int] = None,
|
|
49
|
+
cas: Optional[bool] = False,
|
|
50
|
+
quantization: Optional[QuantizationOptions] = None,
|
|
51
|
+
ef: Optional[Number] = None,
|
|
52
|
+
attributes: Optional[Union[dict, str]] = None,
|
|
53
|
+
numlinks: Optional[int] = None,
|
|
54
|
+
) -> Union[Awaitable[int], int]:
|
|
55
|
+
"""
|
|
56
|
+
Add vector ``vector`` for element ``element`` to a vector set ``key``.
|
|
57
|
+
|
|
58
|
+
``reduce_dim`` sets the dimensions to reduce the vector to.
|
|
59
|
+
If not provided, the vector is not reduced.
|
|
60
|
+
|
|
61
|
+
``cas`` is a boolean flag that indicates whether to use CAS (check-and-set style)
|
|
62
|
+
when adding the vector. If not provided, CAS is not used.
|
|
63
|
+
|
|
64
|
+
``quantization`` sets the quantization type to use.
|
|
65
|
+
If not provided, int8 quantization is used.
|
|
66
|
+
The options are:
|
|
67
|
+
- NOQUANT: No quantization
|
|
68
|
+
- BIN: Binary quantization
|
|
69
|
+
- Q8: Signed 8-bit quantization
|
|
70
|
+
|
|
71
|
+
``ef`` sets the exploration factor to use.
|
|
72
|
+
If not provided, the default exploration factor is used.
|
|
73
|
+
|
|
74
|
+
``attributes`` is a dictionary or json string that contains the attributes to set for the vector.
|
|
75
|
+
If not provided, no attributes are set.
|
|
76
|
+
|
|
77
|
+
``numlinks`` sets the number of links to create for the vector.
|
|
78
|
+
If not provided, the default number of links is used.
|
|
79
|
+
|
|
80
|
+
For more information see https://redis.io/commands/vadd
|
|
81
|
+
"""
|
|
82
|
+
if not vector or not element:
|
|
83
|
+
raise DataError("Both vector and element must be provided")
|
|
84
|
+
|
|
85
|
+
pieces = []
|
|
86
|
+
if reduce_dim:
|
|
87
|
+
pieces.extend(["REDUCE", reduce_dim])
|
|
88
|
+
|
|
89
|
+
values_pieces = []
|
|
90
|
+
if isinstance(vector, bytes):
|
|
91
|
+
values_pieces.extend(["FP32", vector])
|
|
92
|
+
else:
|
|
93
|
+
values_pieces.extend(["VALUES", len(vector)])
|
|
94
|
+
values_pieces.extend(vector)
|
|
95
|
+
pieces.extend(values_pieces)
|
|
96
|
+
|
|
97
|
+
pieces.append(element)
|
|
98
|
+
|
|
99
|
+
if cas:
|
|
100
|
+
pieces.append("CAS")
|
|
101
|
+
|
|
102
|
+
if quantization:
|
|
103
|
+
pieces.append(quantization.value)
|
|
104
|
+
|
|
105
|
+
if ef:
|
|
106
|
+
pieces.extend(["EF", ef])
|
|
107
|
+
|
|
108
|
+
if attributes:
|
|
109
|
+
if isinstance(attributes, dict):
|
|
110
|
+
# transform attributes to json string
|
|
111
|
+
attributes_json = json.dumps(attributes)
|
|
112
|
+
else:
|
|
113
|
+
attributes_json = attributes
|
|
114
|
+
pieces.extend(["SETATTR", attributes_json])
|
|
115
|
+
|
|
116
|
+
if numlinks:
|
|
117
|
+
pieces.extend(["M", numlinks])
|
|
118
|
+
|
|
119
|
+
return self.execute_command(VADD_CMD, key, *pieces)
|
|
120
|
+
|
|
121
|
+
def vsim(
|
|
122
|
+
self,
|
|
123
|
+
key: KeyT,
|
|
124
|
+
input: Union[List[float], bytes, str],
|
|
125
|
+
with_scores: Optional[bool] = False,
|
|
126
|
+
count: Optional[int] = None,
|
|
127
|
+
ef: Optional[Number] = None,
|
|
128
|
+
filter: Optional[str] = None,
|
|
129
|
+
filter_ef: Optional[str] = None,
|
|
130
|
+
truth: Optional[bool] = False,
|
|
131
|
+
no_thread: Optional[bool] = False,
|
|
132
|
+
) -> Union[
|
|
133
|
+
Awaitable[Optional[List[Union[List[EncodableT], Dict[EncodableT, Number]]]]],
|
|
134
|
+
Optional[List[Union[List[EncodableT], Dict[EncodableT, Number]]]],
|
|
135
|
+
]:
|
|
136
|
+
"""
|
|
137
|
+
Compare a vector or element ``input`` with the other vectors in a vector set ``key``.
|
|
138
|
+
|
|
139
|
+
``with_scores`` sets if the results should be returned with the
|
|
140
|
+
similarity scores of the elements in the result.
|
|
141
|
+
|
|
142
|
+
``count`` sets the number of results to return.
|
|
143
|
+
|
|
144
|
+
``ef`` sets the exploration factor.
|
|
145
|
+
|
|
146
|
+
``filter`` sets filter that should be applied for the search.
|
|
147
|
+
|
|
148
|
+
``filter_ef`` sets the max filtering effort.
|
|
149
|
+
|
|
150
|
+
``truth`` when enabled forces the command to perform linear scan.
|
|
151
|
+
|
|
152
|
+
``no_thread`` when enabled forces the command to execute the search
|
|
153
|
+
on the data structure in the main thread.
|
|
154
|
+
|
|
155
|
+
For more information see https://redis.io/commands/vsim
|
|
156
|
+
"""
|
|
157
|
+
|
|
158
|
+
if not input:
|
|
159
|
+
raise DataError("'input' should be provided")
|
|
160
|
+
|
|
161
|
+
pieces = []
|
|
162
|
+
options = {}
|
|
163
|
+
|
|
164
|
+
if isinstance(input, bytes):
|
|
165
|
+
pieces.extend(["FP32", input])
|
|
166
|
+
elif isinstance(input, list):
|
|
167
|
+
pieces.extend(["VALUES", len(input)])
|
|
168
|
+
pieces.extend(input)
|
|
169
|
+
else:
|
|
170
|
+
pieces.extend(["ELE", input])
|
|
171
|
+
|
|
172
|
+
if with_scores:
|
|
173
|
+
pieces.append("WITHSCORES")
|
|
174
|
+
options[CallbacksOptions.WITHSCORES.value] = True
|
|
175
|
+
|
|
176
|
+
if count:
|
|
177
|
+
pieces.extend(["COUNT", count])
|
|
178
|
+
|
|
179
|
+
if ef:
|
|
180
|
+
pieces.extend(["EF", ef])
|
|
181
|
+
|
|
182
|
+
if filter:
|
|
183
|
+
pieces.extend(["FILTER", filter])
|
|
184
|
+
|
|
185
|
+
if filter_ef:
|
|
186
|
+
pieces.extend(["FILTER-EF", filter_ef])
|
|
187
|
+
|
|
188
|
+
if truth:
|
|
189
|
+
pieces.append("TRUTH")
|
|
190
|
+
|
|
191
|
+
if no_thread:
|
|
192
|
+
pieces.append("NOTHREAD")
|
|
193
|
+
|
|
194
|
+
return self.execute_command(VSIM_CMD, key, *pieces, **options)
|
|
195
|
+
|
|
196
|
+
def vdim(self, key: KeyT) -> Union[Awaitable[int], int]:
|
|
197
|
+
"""
|
|
198
|
+
Get the dimension of a vector set.
|
|
199
|
+
|
|
200
|
+
In the case of vectors that were populated using the `REDUCE`
|
|
201
|
+
option, for random projection, the vector set will report the size of
|
|
202
|
+
the projected (reduced) dimension.
|
|
203
|
+
|
|
204
|
+
Raises `redis.exceptions.ResponseError` if the vector set doesn't exist.
|
|
205
|
+
|
|
206
|
+
For more information see https://redis.io/commands/vdim
|
|
207
|
+
"""
|
|
208
|
+
return self.execute_command(VDIM_CMD, key)
|
|
209
|
+
|
|
210
|
+
def vcard(self, key: KeyT) -> Union[Awaitable[int], int]:
|
|
211
|
+
"""
|
|
212
|
+
Get the cardinality(the number of elements) of a vector set with key ``key``.
|
|
213
|
+
|
|
214
|
+
Raises `redis.exceptions.ResponseError` if the vector set doesn't exist.
|
|
215
|
+
|
|
216
|
+
For more information see https://redis.io/commands/vcard
|
|
217
|
+
"""
|
|
218
|
+
return self.execute_command(VCARD_CMD, key)
|
|
219
|
+
|
|
220
|
+
def vrem(self, key: KeyT, element: str) -> Union[Awaitable[int], int]:
|
|
221
|
+
"""
|
|
222
|
+
Remove an element from a vector set.
|
|
223
|
+
|
|
224
|
+
For more information see https://redis.io/commands/vrem
|
|
225
|
+
"""
|
|
226
|
+
return self.execute_command(VREM_CMD, key, element)
|
|
227
|
+
|
|
228
|
+
def vemb(
|
|
229
|
+
self, key: KeyT, element: str, raw: Optional[bool] = False
|
|
230
|
+
) -> Union[
|
|
231
|
+
Awaitable[Optional[Union[List[EncodableT], Dict[str, EncodableT]]]],
|
|
232
|
+
Optional[Union[List[EncodableT], Dict[str, EncodableT]]],
|
|
233
|
+
]:
|
|
234
|
+
"""
|
|
235
|
+
Get the approximated vector of an element ``element`` from vector set ``key``.
|
|
236
|
+
|
|
237
|
+
``raw`` is a boolean flag that indicates whether to return the
|
|
238
|
+
interal representation used by the vector.
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
For more information see https://redis.io/commands/vembed
|
|
242
|
+
"""
|
|
243
|
+
options = {}
|
|
244
|
+
pieces = []
|
|
245
|
+
pieces.extend([key, element])
|
|
246
|
+
|
|
247
|
+
if get_protocol_version(self.client) in ["3", 3]:
|
|
248
|
+
options[CallbacksOptions.RESP3.value] = True
|
|
249
|
+
|
|
250
|
+
if raw:
|
|
251
|
+
pieces.append("RAW")
|
|
252
|
+
|
|
253
|
+
options[NEVER_DECODE] = True
|
|
254
|
+
if (
|
|
255
|
+
hasattr(self.client, "connection_pool")
|
|
256
|
+
and self.client.connection_pool.connection_kwargs["decode_responses"]
|
|
257
|
+
) or (
|
|
258
|
+
hasattr(self.client, "nodes_manager")
|
|
259
|
+
and self.client.nodes_manager.connection_kwargs["decode_responses"]
|
|
260
|
+
):
|
|
261
|
+
# allow decoding in the postprocessing callback
|
|
262
|
+
# if the user set decode_responses=True
|
|
263
|
+
# in the connection pool
|
|
264
|
+
options[CallbacksOptions.ALLOW_DECODING.value] = True
|
|
265
|
+
|
|
266
|
+
options[CallbacksOptions.RAW.value] = True
|
|
267
|
+
|
|
268
|
+
return self.execute_command(VEMB_CMD, *pieces, **options)
|
|
269
|
+
|
|
270
|
+
def vlinks(
|
|
271
|
+
self, key: KeyT, element: str, with_scores: Optional[bool] = False
|
|
272
|
+
) -> Union[
|
|
273
|
+
Awaitable[
|
|
274
|
+
Optional[
|
|
275
|
+
List[Union[List[Union[str, bytes]], Dict[Union[str, bytes], Number]]]
|
|
276
|
+
]
|
|
277
|
+
],
|
|
278
|
+
Optional[List[Union[List[Union[str, bytes]], Dict[Union[str, bytes], Number]]]],
|
|
279
|
+
]:
|
|
280
|
+
"""
|
|
281
|
+
Returns the neighbors for each level the element ``element`` exists in the vector set ``key``.
|
|
282
|
+
|
|
283
|
+
The result is a list of lists, where each list contains the neighbors for one level.
|
|
284
|
+
If the element does not exist, or if the vector set does not exist, None is returned.
|
|
285
|
+
|
|
286
|
+
If the ``WITHSCORES`` option is provided, the result is a list of dicts,
|
|
287
|
+
where each dict contains the neighbors for one level, with the scores as values.
|
|
288
|
+
|
|
289
|
+
For more information see https://redis.io/commands/vlinks
|
|
290
|
+
"""
|
|
291
|
+
options = {}
|
|
292
|
+
pieces = []
|
|
293
|
+
pieces.extend([key, element])
|
|
294
|
+
|
|
295
|
+
if with_scores:
|
|
296
|
+
pieces.append("WITHSCORES")
|
|
297
|
+
options[CallbacksOptions.WITHSCORES.value] = True
|
|
298
|
+
|
|
299
|
+
return self.execute_command(VLINKS_CMD, *pieces, **options)
|
|
300
|
+
|
|
301
|
+
def vinfo(self, key: KeyT) -> Union[Awaitable[dict], dict]:
|
|
302
|
+
"""
|
|
303
|
+
Get information about a vector set.
|
|
304
|
+
|
|
305
|
+
For more information see https://redis.io/commands/vinfo
|
|
306
|
+
"""
|
|
307
|
+
return self.execute_command(VINFO_CMD, key)
|
|
308
|
+
|
|
309
|
+
def vsetattr(
|
|
310
|
+
self, key: KeyT, element: str, attributes: Optional[Union[dict, str]] = None
|
|
311
|
+
) -> Union[Awaitable[int], int]:
|
|
312
|
+
"""
|
|
313
|
+
Associate or remove JSON attributes ``attributes`` of element ``element``
|
|
314
|
+
for vector set ``key``.
|
|
315
|
+
|
|
316
|
+
For more information see https://redis.io/commands/vsetattr
|
|
317
|
+
"""
|
|
318
|
+
if attributes is None:
|
|
319
|
+
attributes_json = "{}"
|
|
320
|
+
elif isinstance(attributes, dict):
|
|
321
|
+
# transform attributes to json string
|
|
322
|
+
attributes_json = json.dumps(attributes)
|
|
323
|
+
else:
|
|
324
|
+
attributes_json = attributes
|
|
325
|
+
|
|
326
|
+
return self.execute_command(VSETATTR_CMD, key, element, attributes_json)
|
|
327
|
+
|
|
328
|
+
def vgetattr(
|
|
329
|
+
self, key: KeyT, element: str
|
|
330
|
+
) -> Union[Optional[Awaitable[dict]], Optional[dict]]:
|
|
331
|
+
"""
|
|
332
|
+
Retrieve the JSON attributes of an element ``elemet`` for vector set ``key``.
|
|
333
|
+
|
|
334
|
+
If the element does not exist, or if the vector set does not exist, None is
|
|
335
|
+
returned.
|
|
336
|
+
|
|
337
|
+
For more information see https://redis.io/commands/vgetattr
|
|
338
|
+
"""
|
|
339
|
+
return self.execute_command(VGETATTR_CMD, key, element)
|
|
340
|
+
|
|
341
|
+
def vrandmember(
|
|
342
|
+
self, key: KeyT, count: Optional[int] = None
|
|
343
|
+
) -> Union[
|
|
344
|
+
Awaitable[Optional[Union[List[str], str]]], Optional[Union[List[str], str]]
|
|
345
|
+
]:
|
|
346
|
+
"""
|
|
347
|
+
Returns random elements from a vector set ``key``.
|
|
348
|
+
|
|
349
|
+
``count`` is the number of elements to return.
|
|
350
|
+
If ``count`` is not provided, a single element is returned as a single string.
|
|
351
|
+
If ``count`` is positive(smaller than the number of elements
|
|
352
|
+
in the vector set), the command returns a list with up to ``count``
|
|
353
|
+
distinct elements from the vector set
|
|
354
|
+
If ``count`` is negative, the command returns a list with ``count`` random elements,
|
|
355
|
+
potentially with duplicates.
|
|
356
|
+
If ``count`` is greater than the number of elements in the vector set,
|
|
357
|
+
only the entire set is returned as a list.
|
|
358
|
+
|
|
359
|
+
If the vector set does not exist, ``None`` is returned.
|
|
360
|
+
|
|
361
|
+
For more information see https://redis.io/commands/vrandmember
|
|
362
|
+
"""
|
|
363
|
+
pieces = []
|
|
364
|
+
pieces.append(key)
|
|
365
|
+
if count is not None:
|
|
366
|
+
pieces.append(count)
|
|
367
|
+
return self.execute_command(VRANDMEMBER_CMD, *pieces)
|