Skip to content

Commit cb19873

Browse files
FT.CREATE - support MAXTEXTFIELDS, TEMPORARY, NOHL, NOFREQS, SKIPINITIALSCAN (#1847)
Co-authored-by: Chayim I. Kirshen <[email protected]>
1 parent 1fbc2d1 commit cb19873

File tree

2 files changed

+124
-20
lines changed

2 files changed

+124
-20
lines changed

redis/commands/search/commands.py

Lines changed: 58 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,12 @@
4444

4545
NOOFFSETS = "NOOFFSETS"
4646
NOFIELDS = "NOFIELDS"
47+
NOHL = "NOHL"
48+
NOFREQS = "NOFREQS"
49+
MAXTEXTFIELDS = "MAXTEXTFIELDS"
50+
TEMPORARY = "TEMPORARY"
4751
STOPWORDS = "STOPWORDS"
52+
SKIPINITIALSCAN = "SKIPINITIALSCAN"
4853
WITHSCORES = "WITHSCORES"
4954
FUZZY = "FUZZY"
5055
WITHPAYLOADS = "WITHPAYLOADS"
@@ -66,27 +71,57 @@ def create_index(
6671
no_field_flags=False,
6772
stopwords=None,
6873
definition=None,
74+
max_text_fields=False,
75+
temporary=None,
76+
no_highlight=False,
77+
no_term_frequencies=False,
78+
skip_initial_scan=False,
6979
):
7080
"""
7181
Create the search index. The index must not already exist.
7282
7383
### Parameters:
7484
7585
- **fields**: a list of TextField or NumericField objects
76-
- **no_term_offsets**: If true, we will not save term offsets in the index
77-
- **no_field_flags**: If true, we will not save field flags that allow searching in specific fields
78-
- **stopwords**: If not None, we create the index with this custom stopword list. The list can be empty
86+
- **no_term_offsets**: If true, we will not save term offsets in
87+
the index
88+
- **no_field_flags**: If true, we will not save field flags that
89+
allow searching in specific fields
90+
- **stopwords**: If not None, we create the index with this custom
91+
stopword list. The list can be empty
92+
- **max_text_fields**: If true, we will encode indexes as if there
93+
were more than 32 text fields which allows you to add additional
94+
fields (beyond 32).
95+
- **temporary**: Create a lightweight temporary index which will
96+
expire after the specified period of inactivity (in seconds). The
97+
internal idle timer is reset whenever the index is searched or added to.
98+
- **no_highlight**: If true, disabling highlighting support.
99+
Also implied by no_term_offsets.
100+
- **no_term_frequencies**: If true, we avoid saving the term frequencies
101+
in the index.
102+
- **skip_initial_scan**: If true, we do not scan and index.
79103
80104
For more information: https://oss.redis.com/redisearch/Commands/#ftcreate
81105
""" # noqa
82106

83107
args = [CREATE_CMD, self.index_name]
84108
if definition is not None:
85109
args += definition.args
110+
if max_text_fields:
111+
args.append(MAXTEXTFIELDS)
112+
if temporary is not None and isinstance(temporary, int):
113+
args.append(TEMPORARY)
114+
args.append(temporary)
86115
if no_term_offsets:
87116
args.append(NOOFFSETS)
117+
if no_highlight:
118+
args.append(NOHL)
88119
if no_field_flags:
89120
args.append(NOFIELDS)
121+
if no_term_frequencies:
122+
args.append(NOFREQS)
123+
if skip_initial_scan:
124+
args.append(SKIPINITIALSCAN)
90125
if stopwords is not None and isinstance(stopwords, (list, tuple, set)):
91126
args += [STOPWORDS, len(stopwords)]
92127
if len(stopwords) > 0:
@@ -129,7 +164,6 @@ def dropindex(self, delete_documents=False):
129164
### Parameters:
130165
131166
- **delete_documents**: If `True`, all documents will be deleted.
132-
133167
For more information: https://oss.redis.com/redisearch/Commands/#ftdropindex
134168
""" # noqa
135169
keep_str = "" if delete_documents else "KEEPDOCS"
@@ -217,23 +251,27 @@ def add_document(
217251
### Parameters
218252
219253
- **doc_id**: the id of the saved document.
220-
- **nosave**: if set to true, we just index the document, and don't \
221-
save a copy of it. This means that searches will just return ids.
222-
- **score**: the document ranking, between 0.0 and 1.0.
223-
- **payload**: optional inner-index payload we can save for fast access in scoring functions
224-
- **replace**: if True, and the document already is in the index, \
254+
- **nosave**: if set to true, we just index the document, and don't
255+
save a copy of it. This means that searches will just
256+
return ids.
257+
- **score**: the document ranking, between 0.0 and 1.0
258+
- **payload**: optional inner-index payload we can save for fast
259+
i access in scoring functions
260+
- **replace**: if True, and the document already is in the index,
225261
we perform an update and reindex the document
226-
- **partial**: if True, the fields specified will be added to the \
227-
existing document. \
228-
This has the added benefit that any fields specified \
229-
with `no_index` will not be reindexed again. Implies `replace`
262+
- **partial**: if True, the fields specified will be added to the
263+
existing document.
264+
This has the added benefit that any fields specified
265+
with `no_index`
266+
will not be reindexed again. Implies `replace`
230267
- **language**: Specify the language used for document tokenization.
231-
- **no_create**: if True, the document is only updated and reindexed \
232-
if it already exists. If the document does not exist, an error will be \
233-
returned. Implies `replace`
234-
- **fields** kwargs dictionary of the document fields to be saved and/or indexed.
235-
236-
NOTE: Geo points shoule be encoded as strings of "lon,lat"
268+
- **no_create**: if True, the document is only updated and reindexed
269+
if it already exists.
270+
If the document does not exist, an error will be
271+
returned. Implies `replace`
272+
- **fields** kwargs dictionary of the document fields to be saved
273+
and/or indexed.
274+
NOTE: Geo points shoule be encoded as strings of "lon,lat"
237275
238276
For more information: https://oss.redis.com/redisearch/Commands/#ftadd
239277
""" # noqa
@@ -481,7 +519,7 @@ def spellcheck(self, query, distance=None, include=None, exclude=None):
481519
482520
**query**: search query.
483521
**distance***: the maximal Levenshtein distance for spelling
484-
suggestions (default: 1, max: 4).
522+
suggestions (default: 1, max: 4).
485523
**include**: specifies an inclusion custom dictionary.
486524
**exclude**: specifies an exclusion custom dictionary.
487525

tests/test_search.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1154,6 +1154,72 @@ def test_index_definition(client):
11541154
createIndex(client.ft(), num_docs=500, definition=definition)
11551155

11561156

1157+
@pytest.mark.redismod
1158+
def testExpire(client):
1159+
client.ft().create_index((TextField("txt", sortable=True),), temporary=4)
1160+
ttl = client.execute_command("ft.debug", "TTL", "idx")
1161+
assert ttl > 2
1162+
1163+
while ttl > 2:
1164+
ttl = client.execute_command("ft.debug", "TTL", "idx")
1165+
time.sleep(0.01)
1166+
1167+
# add document - should reset the ttl
1168+
client.ft().add_document("doc", txt="foo bar", text="this is a simple test")
1169+
ttl = client.execute_command("ft.debug", "TTL", "idx")
1170+
assert ttl > 2
1171+
try:
1172+
while True:
1173+
ttl = client.execute_command("ft.debug", "TTL", "idx")
1174+
time.sleep(0.5)
1175+
except redis.exceptions.ResponseError:
1176+
assert ttl == 0
1177+
1178+
1179+
@pytest.mark.redismod
1180+
def testSkipInitialScan(client):
1181+
client.hset("doc1", "foo", "bar")
1182+
q = Query("@foo:bar")
1183+
1184+
client.ft().create_index((TextField("foo"),), skip_initial_scan=True)
1185+
assert 0 == client.ft().search(q).total
1186+
1187+
1188+
@pytest.mark.redismod
1189+
def testSummarizeDisabled_nooffset(client):
1190+
client.ft().create_index((TextField("txt"),), no_term_offsets=True)
1191+
client.ft().add_document("doc1", txt="foo bar")
1192+
with pytest.raises(Exception):
1193+
client.ft().search(Query("foo").summarize(fields=["txt"]))
1194+
1195+
1196+
@pytest.mark.redismod
1197+
def testSummarizeDisabled_nohl(client):
1198+
client.ft().create_index((TextField("txt"),), no_highlight=True)
1199+
client.ft().add_document("doc1", txt="foo bar")
1200+
with pytest.raises(Exception):
1201+
client.ft().search(Query("foo").summarize(fields=["txt"]))
1202+
1203+
1204+
@pytest.mark.redismod
1205+
def testMaxTextFields(client):
1206+
# Creating the index definition
1207+
client.ft().create_index((TextField("f0"),))
1208+
for x in range(1, 32):
1209+
client.ft().alter_schema_add((TextField(f"f{x}"),))
1210+
1211+
# Should be too many indexes
1212+
with pytest.raises(redis.ResponseError):
1213+
client.ft().alter_schema_add((TextField(f"f{x}"),))
1214+
1215+
client.ft().dropindex("idx")
1216+
# Creating the index definition
1217+
client.ft().create_index((TextField("f0"),), max_text_fields=True)
1218+
# Fill the index with fields
1219+
for x in range(1, 50):
1220+
client.ft().alter_schema_add((TextField(f"f{x}"),))
1221+
1222+
11571223
@pytest.mark.redismod
11581224
@skip_ifmodversion_lt("2.0.0", "search")
11591225
def test_create_client_definition(client):

0 commit comments

Comments
 (0)