This commit is contained in:
@@ -2,16 +2,13 @@ import itertools
|
||||
import time
|
||||
from typing import Dict, List, Optional, Union
|
||||
|
||||
from redis.client import NEVER_DECODE, Pipeline
|
||||
from redis.client import Pipeline
|
||||
from redis.utils import deprecated_function
|
||||
|
||||
from ..helpers import get_protocol_version
|
||||
from ..helpers import get_protocol_version, parse_to_dict
|
||||
from ._util import to_string
|
||||
from .aggregation import AggregateRequest, AggregateResult, Cursor
|
||||
from .document import Document
|
||||
from .field import Field
|
||||
from .index_definition import IndexDefinition
|
||||
from .profile_information import ProfileInformation
|
||||
from .query import Query
|
||||
from .result import Result
|
||||
from .suggestion import SuggestionParser
|
||||
@@ -23,6 +20,7 @@ ALTER_CMD = "FT.ALTER"
|
||||
SEARCH_CMD = "FT.SEARCH"
|
||||
ADD_CMD = "FT.ADD"
|
||||
ADDHASH_CMD = "FT.ADDHASH"
|
||||
DROP_CMD = "FT.DROP"
|
||||
DROPINDEX_CMD = "FT.DROPINDEX"
|
||||
EXPLAIN_CMD = "FT.EXPLAIN"
|
||||
EXPLAINCLI_CMD = "FT.EXPLAINCLI"
|
||||
@@ -34,6 +32,7 @@ SPELLCHECK_CMD = "FT.SPELLCHECK"
|
||||
DICT_ADD_CMD = "FT.DICTADD"
|
||||
DICT_DEL_CMD = "FT.DICTDEL"
|
||||
DICT_DUMP_CMD = "FT.DICTDUMP"
|
||||
GET_CMD = "FT.GET"
|
||||
MGET_CMD = "FT.MGET"
|
||||
CONFIG_CMD = "FT.CONFIG"
|
||||
TAGVALS_CMD = "FT.TAGVALS"
|
||||
@@ -66,7 +65,7 @@ class SearchCommands:
|
||||
|
||||
def _parse_results(self, cmd, res, **kwargs):
|
||||
if get_protocol_version(self.client) in ["3", 3]:
|
||||
return ProfileInformation(res) if cmd == "FT.PROFILE" else res
|
||||
return res
|
||||
else:
|
||||
return self._RESP2_MODULE_CALLBACKS[cmd](res, **kwargs)
|
||||
|
||||
@@ -81,7 +80,6 @@ class SearchCommands:
|
||||
duration=kwargs["duration"],
|
||||
has_payload=kwargs["query"]._with_payloads,
|
||||
with_scores=kwargs["query"]._with_scores,
|
||||
field_encodings=kwargs["query"]._return_fields_decode_as,
|
||||
)
|
||||
|
||||
def _parse_aggregate(self, res, **kwargs):
|
||||
@@ -100,7 +98,7 @@ class SearchCommands:
|
||||
with_scores=query._with_scores,
|
||||
)
|
||||
|
||||
return result, ProfileInformation(res[1])
|
||||
return result, parse_to_dict(res[1])
|
||||
|
||||
def _parse_spellcheck(self, res, **kwargs):
|
||||
corrections = {}
|
||||
@@ -153,43 +151,44 @@ class SearchCommands:
|
||||
|
||||
def create_index(
|
||||
self,
|
||||
fields: List[Field],
|
||||
no_term_offsets: bool = False,
|
||||
no_field_flags: bool = False,
|
||||
stopwords: Optional[List[str]] = None,
|
||||
definition: Optional[IndexDefinition] = None,
|
||||
fields,
|
||||
no_term_offsets=False,
|
||||
no_field_flags=False,
|
||||
stopwords=None,
|
||||
definition=None,
|
||||
max_text_fields=False,
|
||||
temporary=None,
|
||||
no_highlight: bool = False,
|
||||
no_term_frequencies: bool = False,
|
||||
skip_initial_scan: bool = False,
|
||||
no_highlight=False,
|
||||
no_term_frequencies=False,
|
||||
skip_initial_scan=False,
|
||||
):
|
||||
"""
|
||||
Creates the search index. The index must not already exist.
|
||||
Create the search index. The index must not already exist.
|
||||
|
||||
For more information, see https://redis.io/commands/ft.create/
|
||||
### Parameters:
|
||||
|
||||
Args:
|
||||
fields: A list of Field objects.
|
||||
no_term_offsets: If `true`, term offsets will not be saved in the index.
|
||||
no_field_flags: If true, field flags that allow searching in specific fields
|
||||
will not be saved.
|
||||
stopwords: If provided, the index will be created with this custom stopword
|
||||
list. The list can be empty.
|
||||
definition: If provided, the index will be created with this custom index
|
||||
definition.
|
||||
max_text_fields: If true, indexes will be encoded as if there were more than
|
||||
32 text fields, allowing for additional fields beyond 32.
|
||||
temporary: Creates a lightweight temporary index which will expire after the
|
||||
specified period of inactivity. The internal idle timer is reset
|
||||
whenever the index is searched or added to.
|
||||
no_highlight: If true, disables highlighting support. Also implied by
|
||||
`no_term_offsets`.
|
||||
no_term_frequencies: If true, term frequencies will not be saved in the
|
||||
index.
|
||||
skip_initial_scan: If true, the initial scan and indexing will be skipped.
|
||||
- **fields**: a list of TextField or NumericField objects
|
||||
- **no_term_offsets**: If true, we will not save term offsets in
|
||||
the index
|
||||
- **no_field_flags**: If true, we will not save field flags that
|
||||
allow searching in specific fields
|
||||
- **stopwords**: If not None, we create the index with this custom
|
||||
stopword list. The list can be empty
|
||||
- **max_text_fields**: If true, we will encode indexes as if there
|
||||
were more than 32 text fields which allows you to add additional
|
||||
fields (beyond 32).
|
||||
- **temporary**: Create a lightweight temporary index which will
|
||||
expire after the specified period of inactivity (in seconds). The
|
||||
internal idle timer is reset whenever the index is searched or added to.
|
||||
- **no_highlight**: If true, disabling highlighting support.
|
||||
Also implied by no_term_offsets.
|
||||
- **no_term_frequencies**: If true, we avoid saving the term frequencies
|
||||
in the index.
|
||||
- **skip_initial_scan**: If true, we do not scan and index.
|
||||
|
||||
For more information see `FT.CREATE <https://redis.io/commands/ft.create>`_.
|
||||
""" # noqa
|
||||
|
||||
"""
|
||||
args = [CREATE_CMD, self.index_name]
|
||||
if definition is not None:
|
||||
args += definition.args
|
||||
@@ -253,18 +252,8 @@ class SearchCommands:
|
||||
|
||||
For more information see `FT.DROPINDEX <https://redis.io/commands/ft.dropindex>`_.
|
||||
""" # noqa
|
||||
args = [DROPINDEX_CMD, self.index_name]
|
||||
|
||||
delete_str = (
|
||||
"DD"
|
||||
if isinstance(delete_documents, bool) and delete_documents is True
|
||||
else ""
|
||||
)
|
||||
|
||||
if delete_str:
|
||||
args.append(delete_str)
|
||||
|
||||
return self.execute_command(*args)
|
||||
delete_str = "DD" if delete_documents else ""
|
||||
return self.execute_command(DROPINDEX_CMD, self.index_name, delete_str)
|
||||
|
||||
def _add_document(
|
||||
self,
|
||||
@@ -346,30 +335,30 @@ class SearchCommands:
|
||||
"""
|
||||
Add a single document to the index.
|
||||
|
||||
Args:
|
||||
### Parameters
|
||||
|
||||
doc_id: the id of the saved document.
|
||||
nosave: if set to true, we just index the document, and don't
|
||||
- **doc_id**: the id of the saved document.
|
||||
- **nosave**: if set to true, we just index the document, and don't
|
||||
save a copy of it. This means that searches will just
|
||||
return ids.
|
||||
score: the document ranking, between 0.0 and 1.0
|
||||
payload: optional inner-index payload we can save for fast
|
||||
access in scoring functions
|
||||
replace: if True, and the document already is in the index,
|
||||
we perform an update and reindex the document
|
||||
partial: if True, the fields specified will be added to the
|
||||
- **score**: the document ranking, between 0.0 and 1.0
|
||||
- **payload**: optional inner-index payload we can save for fast
|
||||
i access in scoring functions
|
||||
- **replace**: if True, and the document already is in the index,
|
||||
we perform an update and reindex the document
|
||||
- **partial**: if True, the fields specified will be added to the
|
||||
existing document.
|
||||
This has the added benefit that any fields specified
|
||||
with `no_index`
|
||||
will not be reindexed again. Implies `replace`
|
||||
language: Specify the language used for document tokenization.
|
||||
no_create: if True, the document is only updated and reindexed
|
||||
- **language**: Specify the language used for document tokenization.
|
||||
- **no_create**: if True, the document is only updated and reindexed
|
||||
if it already exists.
|
||||
If the document does not exist, an error will be
|
||||
returned. Implies `replace`
|
||||
fields: kwargs dictionary of the document fields to be saved
|
||||
and/or indexed.
|
||||
NOTE: Geo points shoule be encoded as strings of "lon,lat"
|
||||
- **fields** kwargs dictionary of the document fields to be saved
|
||||
and/or indexed.
|
||||
NOTE: Geo points shoule be encoded as strings of "lon,lat"
|
||||
""" # noqa
|
||||
return self._add_document(
|
||||
doc_id,
|
||||
@@ -404,7 +393,6 @@ class SearchCommands:
|
||||
doc_id, conn=None, score=score, language=language, replace=replace
|
||||
)
|
||||
|
||||
@deprecated_function(version="2.0.0", reason="deprecated since redisearch 2.0")
|
||||
def delete_document(self, doc_id, conn=None, delete_actual_document=False):
|
||||
"""
|
||||
Delete a document from index
|
||||
@@ -439,7 +427,6 @@ class SearchCommands:
|
||||
|
||||
return Document(id=id, **fields)
|
||||
|
||||
@deprecated_function(version="2.0.0", reason="deprecated since redisearch 2.0")
|
||||
def get(self, *ids):
|
||||
"""
|
||||
Returns the full contents of multiple documents.
|
||||
@@ -510,19 +497,14 @@ class SearchCommands:
|
||||
For more information see `FT.SEARCH <https://redis.io/commands/ft.search>`_.
|
||||
""" # noqa
|
||||
args, query = self._mk_query_args(query, query_params=query_params)
|
||||
st = time.monotonic()
|
||||
|
||||
options = {}
|
||||
if get_protocol_version(self.client) not in ["3", 3]:
|
||||
options[NEVER_DECODE] = True
|
||||
|
||||
res = self.execute_command(SEARCH_CMD, *args, **options)
|
||||
st = time.time()
|
||||
res = self.execute_command(SEARCH_CMD, *args)
|
||||
|
||||
if isinstance(res, Pipeline):
|
||||
return res
|
||||
|
||||
return self._parse_results(
|
||||
SEARCH_CMD, res, query=query, duration=(time.monotonic() - st) * 1000.0
|
||||
SEARCH_CMD, res, query=query, duration=(time.time() - st) * 1000.0
|
||||
)
|
||||
|
||||
def explain(
|
||||
@@ -542,7 +524,7 @@ class SearchCommands:
|
||||
|
||||
def aggregate(
|
||||
self,
|
||||
query: Union[AggregateRequest, Cursor],
|
||||
query: Union[str, Query],
|
||||
query_params: Dict[str, Union[str, int, float]] = None,
|
||||
):
|
||||
"""
|
||||
@@ -573,7 +555,7 @@ class SearchCommands:
|
||||
)
|
||||
|
||||
def _get_aggregate_result(
|
||||
self, raw: List, query: Union[AggregateRequest, Cursor], has_cursor: bool
|
||||
self, raw: List, query: Union[str, Query, AggregateRequest], has_cursor: bool
|
||||
):
|
||||
if has_cursor:
|
||||
if isinstance(query, Cursor):
|
||||
@@ -596,7 +578,7 @@ class SearchCommands:
|
||||
|
||||
def profile(
|
||||
self,
|
||||
query: Union[Query, AggregateRequest],
|
||||
query: Union[str, Query, AggregateRequest],
|
||||
limited: bool = False,
|
||||
query_params: Optional[Dict[str, Union[str, int, float]]] = None,
|
||||
):
|
||||
@@ -606,13 +588,13 @@ class SearchCommands:
|
||||
|
||||
### Parameters
|
||||
|
||||
**query**: This can be either an `AggregateRequest` or `Query`.
|
||||
**query**: This can be either an `AggregateRequest`, `Query` or string.
|
||||
**limited**: If set to True, removes details of reader iterator.
|
||||
**query_params**: Define one or more value parameters.
|
||||
Each parameter has a name and a value.
|
||||
|
||||
"""
|
||||
st = time.monotonic()
|
||||
st = time.time()
|
||||
cmd = [PROFILE_CMD, self.index_name, ""]
|
||||
if limited:
|
||||
cmd.append("LIMITED")
|
||||
@@ -631,20 +613,20 @@ class SearchCommands:
|
||||
res = self.execute_command(*cmd)
|
||||
|
||||
return self._parse_results(
|
||||
PROFILE_CMD, res, query=query, duration=(time.monotonic() - st) * 1000.0
|
||||
PROFILE_CMD, res, query=query, duration=(time.time() - st) * 1000.0
|
||||
)
|
||||
|
||||
def spellcheck(self, query, distance=None, include=None, exclude=None):
|
||||
"""
|
||||
Issue a spellcheck query
|
||||
|
||||
Args:
|
||||
### Parameters
|
||||
|
||||
query: search query.
|
||||
distance: the maximal Levenshtein distance for spelling
|
||||
**query**: search query.
|
||||
**distance***: the maximal Levenshtein distance for spelling
|
||||
suggestions (default: 1, max: 4).
|
||||
include: specifies an inclusion custom dictionary.
|
||||
exclude: specifies an exclusion custom dictionary.
|
||||
**include**: specifies an inclusion custom dictionary.
|
||||
**exclude**: specifies an exclusion custom dictionary.
|
||||
|
||||
For more information see `FT.SPELLCHECK <https://redis.io/commands/ft.spellcheck>`_.
|
||||
""" # noqa
|
||||
@@ -702,10 +684,6 @@ class SearchCommands:
|
||||
cmd = [DICT_DUMP_CMD, name]
|
||||
return self.execute_command(*cmd)
|
||||
|
||||
@deprecated_function(
|
||||
version="8.0.0",
|
||||
reason="deprecated since Redis 8.0, call config_set from core module instead",
|
||||
)
|
||||
def config_set(self, option: str, value: str) -> bool:
|
||||
"""Set runtime configuration option.
|
||||
|
||||
@@ -720,10 +698,6 @@ class SearchCommands:
|
||||
raw = self.execute_command(*cmd)
|
||||
return raw == "OK"
|
||||
|
||||
@deprecated_function(
|
||||
version="8.0.0",
|
||||
reason="deprecated since Redis 8.0, call config_get from core module instead",
|
||||
)
|
||||
def config_get(self, option: str) -> str:
|
||||
"""Get runtime configuration option value.
|
||||
|
||||
@@ -950,24 +924,19 @@ class AsyncSearchCommands(SearchCommands):
|
||||
For more information see `FT.SEARCH <https://redis.io/commands/ft.search>`_.
|
||||
""" # noqa
|
||||
args, query = self._mk_query_args(query, query_params=query_params)
|
||||
st = time.monotonic()
|
||||
|
||||
options = {}
|
||||
if get_protocol_version(self.client) not in ["3", 3]:
|
||||
options[NEVER_DECODE] = True
|
||||
|
||||
res = await self.execute_command(SEARCH_CMD, *args, **options)
|
||||
st = time.time()
|
||||
res = await self.execute_command(SEARCH_CMD, *args)
|
||||
|
||||
if isinstance(res, Pipeline):
|
||||
return res
|
||||
|
||||
return self._parse_results(
|
||||
SEARCH_CMD, res, query=query, duration=(time.monotonic() - st) * 1000.0
|
||||
SEARCH_CMD, res, query=query, duration=(time.time() - st) * 1000.0
|
||||
)
|
||||
|
||||
async def aggregate(
|
||||
self,
|
||||
query: Union[AggregateResult, Cursor],
|
||||
query: Union[str, Query],
|
||||
query_params: Dict[str, Union[str, int, float]] = None,
|
||||
):
|
||||
"""
|
||||
@@ -1025,10 +994,6 @@ class AsyncSearchCommands(SearchCommands):
|
||||
|
||||
return self._parse_results(SPELLCHECK_CMD, res)
|
||||
|
||||
@deprecated_function(
|
||||
version="8.0.0",
|
||||
reason="deprecated since Redis 8.0, call config_set from core module instead",
|
||||
)
|
||||
async def config_set(self, option: str, value: str) -> bool:
|
||||
"""Set runtime configuration option.
|
||||
|
||||
@@ -1043,10 +1008,6 @@ class AsyncSearchCommands(SearchCommands):
|
||||
raw = await self.execute_command(*cmd)
|
||||
return raw == "OK"
|
||||
|
||||
@deprecated_function(
|
||||
version="8.0.0",
|
||||
reason="deprecated since Redis 8.0, call config_get from core module instead",
|
||||
)
|
||||
async def config_get(self, option: str) -> str:
|
||||
"""Get runtime configuration option value.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user