Skip to content

Commit

Permalink
Python: Add FT.SEARCH command (#2470)
Browse files Browse the repository at this point in the history
* Python: Add FT.SEARCH command
---------

Signed-off-by: Prateek Kumar <[email protected]>
Signed-off-by: prateek-kumar-improving <[email protected]>
  • Loading branch information
prateek-kumar-improving authored Oct 22, 2024
1 parent ee0f86f commit 9073eb0
Show file tree
Hide file tree
Showing 6 changed files with 349 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#### Changes
* Python: Add FT.SEARCH command([#2470](https://github.com/valkey-io/valkey-glide/pull/2470))
* Python: Add commands FT.ALIASADD, FT.ALIASDEL, FT.ALIASUPDATE([#2471](https://github.com/valkey-io/valkey-glide/pull/2471))
* Python: Python FT.DROPINDEX command ([#2437](https://github.com/valkey-io/valkey-glide/pull/2437))
* Python: Python: Added FT.CREATE command([#2413](https://github.com/valkey-io/valkey-glide/pull/2413))
Expand Down
8 changes: 8 additions & 0 deletions python/python/glide/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@
VectorFieldAttributesHnsw,
VectorType,
)
from glide.async_commands.server_modules.ft_options.ft_search_options import (
FtSeachOptions,
FtSearchLimit,
ReturnField,
)
from glide.async_commands.sorted_set import (
AggregationType,
GeoSearchByBox,
Expand Down Expand Up @@ -265,4 +270,7 @@
"VectorFieldAttributesFlat",
"VectorFieldAttributesHnsw",
"VectorType",
"FtSearchLimit",
"ReturnField",
"FtSeachOptions",
]
41 changes: 40 additions & 1 deletion python/python/glide/async_commands/server_modules/ft.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
module for `vector search` commands.
"""

from typing import List, Optional, cast
from typing import List, Mapping, Optional, Union, cast

from glide.async_commands.server_modules.ft_options.ft_constants import (
CommandNames,
Expand All @@ -13,6 +13,9 @@
Field,
FtCreateOptions,
)
from glide.async_commands.server_modules.ft_options.ft_search_options import (
FtSeachOptions,
)
from glide.constants import TOK, TEncodable
from glide.glide_client import TGlideClient

Expand Down Expand Up @@ -78,6 +81,42 @@ async def dropindex(client: TGlideClient, indexName: TEncodable) -> TOK:
return cast(TOK, await client.custom_command(args))


async def search(
client: TGlideClient,
indexName: TEncodable,
query: TEncodable,
options: Optional[FtSeachOptions],
) -> List[Union[int, Mapping[TEncodable, Mapping[TEncodable, TEncodable]]]]:
"""
Uses the provided query expression to locate keys within an index. Once located, the count and/or the content of indexed fields within those keys can be returned.
Args:
client (TGlideClient): The client to execute the command.
indexName (TEncodable): The index name to search into.
query (TEncodable): The text query to search.
options (Optional[FtSeachOptions]): The search options. See `FtSearchOptions`.
Returns:
List[Union[int, Mapping[TEncodable, Mapping[TEncodable, TEncodable]]]]: A two element array, where first element is count of documents in result set, and the second element, which has the format Mapping[TEncodable, Mapping[TEncodable, TEncodable]] is a mapping between document names and map of their attributes.
If count(option in `FtSearchOptions`) is set to true or limit(option in `FtSearchOptions`) is set to FtSearchLimit(0, 0), the command returns array with only one element - the count of the documents.
Examples:
For the following example to work the following must already exist:
- An index named "idx", with fields having identifiers as "a" and "b" and prefix as "{json:}"
- A key named {json:}1 with value {"a":1, "b":2}
>>> from glide.async_commands.server_modules import ft
>>> result = await ft.search(glide_client, "idx", "*", options=FtSeachOptions(return_fields=[ReturnField(field_identifier="first"), ReturnField(field_identifier="second")]))
[1, { b'json:1': { b'first': b'42', b'second': b'33' } }] # The first element, 1 is the number of keys returned in the search result. The second element is a map of data queried per key.
"""
args: List[TEncodable] = [CommandNames.FT_SEARCH, indexName, query]
if options:
args.extend(options.toArgs())
return cast(
List[Union[int, Mapping[TEncodable, Mapping[TEncodable, TEncodable]]]],
await client.custom_command(args),
)


async def aliasadd(
client: TGlideClient, alias: TEncodable, indexName: TEncodable
) -> TOK:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ class CommandNames:

FT_CREATE = "FT.CREATE"
FT_DROPINDEX = "FT.DROPINDEX"
FT_SEARCH = "FT.SEARCH"
FT_ALIASADD = "FT.ALIASADD"
FT_ALIASDEL = "FT.ALIASDEL"
FT_ALIASUPDATE = "FT.ALIASUPDATE"


class FtCreateKeywords:
"""
Keywords used in the FT.CREATE command statment.
Keywords used in the FT.CREATE command.
"""

SCHEMA = "SCHEMA"
Expand All @@ -34,3 +35,16 @@ class FtCreateKeywords:
M = "M"
EF_CONSTRUCTION = "EF_CONSTRUCTION"
EF_RUNTIME = "EF_RUNTIME"


class FtSeachKeywords:
"""
Keywords used in the FT.SEARCH command.
"""

RETURN = "RETURN"
TIMEOUT = "TIMEOUT"
PARAMS = "PARAMS"
LIMIT = "LIMIT"
COUNT = "COUNT"
AS = "AS"
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
# Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0

from typing import List, Mapping, Optional

from glide.async_commands.server_modules.ft_options.ft_constants import FtSeachKeywords
from glide.constants import TEncodable


class FtSearchLimit:
"""
This class represents the arguments for the LIMIT option of the FT.SEARCH command.
"""

def __init__(self, offset: int, count: int):
"""
Initialize a new FtSearchLimit instance.
Args:
offset (int): The number of keys to skip before returning the result for the FT.SEARCH command.
count (int): The total number of keys to be returned by FT.SEARCH command.
"""
self.offset = offset
self.count = count

def toArgs(self) -> List[TEncodable]:
"""
Get the arguments for the LIMIT option of FT.SEARCH.
Returns:
List[TEncodable]: A list of LIMIT option arguments.
"""
args: List[TEncodable] = [
FtSeachKeywords.LIMIT,
str(self.offset),
str(self.count),
]
return args


class ReturnField:
"""
This class represents the arguments for the RETURN option of the FT.SEARCH command.
"""

def __init__(
self, field_identifier: TEncodable, alias: Optional[TEncodable] = None
):
"""
Initialize a new ReturnField instance.
Args:
field_identifier (TEncodable): The identifier for the field of the key that has to returned as a result of FT.SEARCH command.
alias (Optional[TEncodable]): The alias to override the name of the field in the FT.SEARCH result.
"""
self.field_identifier = field_identifier
self.alias = alias

def toArgs(self) -> List[TEncodable]:
"""
Get the arguments for the RETURN option of FT.SEARCH.
Returns:
List[TEncodable]: A list of RETURN option arguments.
"""
args: List[TEncodable] = [self.field_identifier]
if self.alias:
args.append(FtSeachKeywords.AS)
args.append(self.alias)
return args


class FtSeachOptions:
"""
This class represents the input options to be used in the FT.SEARCH command.
All fields in this class are optional inputs for FT.SEARCH.
"""

def __init__(
self,
return_fields: Optional[List[ReturnField]] = None,
timeout: Optional[int] = None,
params: Optional[Mapping[TEncodable, TEncodable]] = None,
limit: Optional[FtSearchLimit] = None,
count: Optional[bool] = False,
):
"""
Initialize the FT.SEARCH optional fields.
Args:
return_fields (Optional[List[ReturnField]]): The fields of a key that are returned by FT.SEARCH command. See `ReturnField`.
timeout (Optional[int]): This value overrides the timeout parameter of the module. The unit for the timout is in milliseconds.
params (Optional[Mapping[TEncodable, TEncodable]]): Param key/value pairs that can be referenced from within the query expression.
limit (Optional[FtSearchLimit]): This option provides pagination capability. Only the keys that satisfy the offset and count values are returned. See `FtSearchLimit`.
count (Optional[bool]): This flag option suppresses returning the contents of keys. Only the number of keys is returned.
"""
self.return_fields = return_fields
self.timeout = timeout
self.params = params
self.limit = limit
self.count = count

def toArgs(self) -> List[TEncodable]:
"""
Get the optional arguments for the FT.SEARCH command.
Returns:
List[TEncodable]:
List of FT.SEARCH optional agruments.
"""
args: List[TEncodable] = []
if self.return_fields:
args.append(FtSeachKeywords.RETURN)
return_field_args: List[TEncodable] = []
for return_field in self.return_fields:
return_field_args.extend(return_field.toArgs())
args.append(str(len(return_field_args)))
args.extend(return_field_args)
if self.timeout:
args.append(FtSeachKeywords.TIMEOUT)
args.append(str(self.timeout))
if self.params:
args.append(FtSeachKeywords.PARAMS)
args.append(str(len(self.params)))
for name, value in self.params.items():
args.append(name)
args.append(value)
if self.limit:
args.extend(self.limit.toArgs())
if self.count:
args.append(FtSeachKeywords.COUNT)
return args
Loading

0 comments on commit 9073eb0

Please sign in to comment.