0
# RediSearch
1
2
RediSearch provides full-text search, secondary indexing, and query capabilities for Redis. It supports complex queries, aggregations, auto-complete, and geospatial search with high performance indexing.
3
4
## Capabilities
5
6
### Index Management
7
8
Create and manage search indexes for Redis data structures.
9
10
```python { .api }
11
def ft_create(
12
self,
13
index_name: str,
14
schema: Dict[str, Any],
15
definition: Optional[Dict[str, Any]] = None
16
) -> str: ...
17
18
def ft_dropindex(
19
self,
20
index_name: str,
21
delete_documents: bool = False
22
) -> str: ...
23
24
def ft_info(self, index_name: str) -> Dict[str, Any]: ...
25
26
def ft_list(self) -> List[str]: ...
27
28
def ft_alter(
29
self,
30
index_name: str,
31
schema_add: Dict[str, Any]
32
) -> str: ...
33
34
def ft_aliasadd(self, alias: str, index_name: str) -> str: ...
35
36
def ft_aliasdel(self, alias: str) -> str: ...
37
38
def ft_aliasupdate(self, alias: str, index_name: str) -> str: ...
39
```
40
41
### Search Operations
42
43
Perform full-text search and complex queries on indexed data.
44
45
```python { .api }
46
def ft_search(
47
self,
48
index_name: str,
49
query: str,
50
query_params: Optional[Dict[str, Any]] = None
51
) -> Dict[str, Any]: ...
52
53
def ft_aggregate(
54
self,
55
index_name: str,
56
query: str,
57
*args: Any
58
) -> List[Any]: ...
59
60
def ft_explain(
61
self,
62
index_name: str,
63
query: str
64
) -> str: ...
65
66
def ft_explaincli(
67
self,
68
index_name: str,
69
query: str
70
) -> str: ...
71
72
def ft_profile(
73
self,
74
index_name: str,
75
query: str,
76
limited: bool = False
77
) -> List[Any]: ...
78
```
79
80
### Document Operations
81
82
Add, update, and delete documents in search indexes.
83
84
```python { .api }
85
def ft_add(
86
self,
87
index_name: str,
88
doc_id: str,
89
score: float,
90
fields: Dict[str, Any],
91
**kwargs
92
) -> str: ...
93
94
def ft_del(
95
self,
96
index_name: str,
97
doc_id: str,
98
delete_document: bool = False
99
) -> int: ...
100
101
def ft_get(
102
self,
103
index_name: str,
104
*doc_ids: str
105
) -> List[Optional[Dict[str, Any]]]: ...
106
107
def ft_mget(
108
self,
109
index_name: str,
110
*doc_ids: str
111
) -> List[Optional[Dict[str, Any]]]: ...
112
```
113
114
### Suggestion and Auto-complete
115
116
Manage suggestion dictionaries for auto-complete functionality.
117
118
```python { .api }
119
def ft_sugadd(
120
self,
121
key: str,
122
string: str,
123
score: float,
124
incr: bool = False,
125
payload: Optional[str] = None
126
) -> int: ...
127
128
def ft_sugget(
129
self,
130
key: str,
131
prefix: str,
132
fuzzy: bool = False,
133
max_results: int = 5,
134
with_scores: bool = False,
135
with_payloads: bool = False
136
) -> List[Any]: ...
137
138
def ft_sugdel(self, key: str, string: str) -> int: ...
139
140
def ft_suglen(self, key: str) -> int: ...
141
```
142
143
### Dictionary Management
144
145
Manage custom dictionaries for spell checking and synonyms.
146
147
```python { .api }
148
def ft_dictadd(self, dictionary: str, *terms: str) -> int: ...
149
150
def ft_dictdel(self, dictionary: str, *terms: str) -> int: ...
151
152
def ft_dictdump(self, dictionary: str) -> List[str]: ...
153
```
154
155
### Configuration
156
157
Configure RediSearch module settings.
158
159
```python { .api }
160
def ft_config_get(self, option: str) -> Dict[str, Any]: ...
161
162
def ft_config_set(self, option: str, value: Any) -> str: ...
163
```
164
165
## Usage Examples
166
167
### Creating Search Indexes
168
169
```python
170
import redis
171
from redis.commands.search import Search
172
from redis.commands.search.field import TextField, NumericField, TagField, GeoField
173
174
r = redis.Redis(host='localhost', port=6379, decode_responses=True)
175
176
# Create index for product catalog
177
def create_product_index():
178
try:
179
# Define schema for products
180
schema = [
181
TextField("title", weight=5.0),
182
TextField("description", weight=1.0),
183
TagField("category"),
184
TagField("brand"),
185
NumericField("price"),
186
NumericField("rating"),
187
TagField("tags", separator=","),
188
GeoField("location")
189
]
190
191
# Create index
192
result = r.ft("products").create_index(
193
schema,
194
definition={
195
'prefix': ['product:'],
196
'language': 'english'
197
}
198
)
199
print(f"Created index: {result}")
200
201
except Exception as e:
202
print(f"Index creation error: {e}")
203
204
create_product_index()
205
206
# Add sample products
207
products = [
208
{
209
"id": "product:1001",
210
"title": "Gaming Laptop",
211
"description": "High-performance laptop for gaming and professional work",
212
"category": "Electronics",
213
"brand": "TechBrand",
214
"price": 1299.99,
215
"rating": 4.5,
216
"tags": "gaming,laptop,performance",
217
"location": "40.7128,-74.0060" # NYC coordinates
218
},
219
{
220
"id": "product:1002",
221
"title": "Wireless Headphones",
222
"description": "Premium noise-canceling wireless headphones",
223
"category": "Electronics",
224
"brand": "AudioPro",
225
"price": 299.99,
226
"rating": 4.2,
227
"tags": "audio,wireless,headphones",
228
"location": "34.0522,-118.2437" # LA coordinates
229
}
230
]
231
232
for product in products:
233
product_id = product.pop("id")
234
r.hset(product_id, mapping=product)
235
236
print("Added sample products to Redis")
237
```
238
239
### Basic Search Operations
240
241
```python
242
import redis
243
244
r = redis.Redis(host='localhost', port=6379, decode_responses=True)
245
246
# Simple text search
247
def search_products(query):
248
try:
249
result = r.ft("products").search(query)
250
print(f"Search '{query}' found {result.total} results:")
251
252
for doc in result.docs:
253
print(f" ID: {doc.id}")
254
print(f" Title: {doc.title}")
255
print(f" Price: ${doc.price}")
256
print(f" Rating: {doc.rating}")
257
print()
258
259
except Exception as e:
260
print(f"Search error: {e}")
261
262
# Search for gaming products
263
search_products("gaming")
264
265
# Search in specific field
266
search_products("@title:laptop")
267
268
# Search with multiple terms
269
search_products("wireless headphones")
270
271
# Phrase search
272
search_products('"gaming laptop"')
273
```
274
275
### Advanced Search Queries
276
277
```python
278
import redis
279
from redis.commands.search.query import Query
280
281
r = redis.Redis(host='localhost', port=6379, decode_responses=True)
282
283
# Complex search with filters
284
def advanced_product_search():
285
# Price range filter
286
query = Query("@category:Electronics @price:[200 500]").return_fields("title", "price", "rating")
287
result = r.ft("products").search(query)
288
print(f"Electronics $200-$500: {result.total} results")
289
290
# Rating filter with sorting
291
query = Query("@rating:[4.0 5.0]").sort_by("price", asc=True).return_fields("title", "price", "rating")
292
result = r.ft("products").search(query)
293
print(f"High-rated products (sorted by price): {result.total} results")
294
295
# Tag search
296
query = Query("@tags:{gaming}").return_fields("title", "tags")
297
result = r.ft("products").search(query)
298
print(f"Gaming tagged products: {result.total} results")
299
300
# Geospatial search (within 1000km of NYC)
301
query = Query("@location:[40.7128 -74.0060 1000 km]").return_fields("title", "location")
302
result = r.ft("products").search(query)
303
print(f"Products near NYC: {result.total} results")
304
305
# Boolean search
306
query = Query("(@title:laptop) | (@title:headphones)").return_fields("title", "category")
307
result = r.ft("products").search(query)
308
print(f"Laptops OR headphones: {result.total} results")
309
310
advanced_product_search()
311
```
312
313
### Search Aggregations
314
315
```python
316
import redis
317
from redis.commands.search.aggregation import AggregateRequest
318
from redis.commands.search import reducers
319
320
r = redis.Redis(host='localhost', port=6379, decode_responses=True)
321
322
def product_analytics():
323
# Average price by category
324
agg_request = AggregateRequest("*").group_by(
325
"@category",
326
reducers.avg("@price").alias("avg_price"),
327
reducers.count().alias("count")
328
)
329
330
result = r.ft("products").aggregate(agg_request)
331
print("Average price by category:")
332
for row in result.rows:
333
print(f" {row[1]}: ${float(row[3]):.2f} (count: {row[5]})")
334
335
# Top brands by average rating
336
agg_request = AggregateRequest("*").group_by(
337
"@brand",
338
reducers.avg("@rating").alias("avg_rating"),
339
reducers.count().alias("product_count")
340
).sort_by("@avg_rating", desc=True)
341
342
result = r.ft("products").aggregate(agg_request)
343
print("\nTop brands by rating:")
344
for row in result.rows:
345
print(f" {row[1]}: {float(row[3]):.2f} ({row[5]} products)")
346
347
product_analytics()
348
```
349
350
### Auto-complete and Suggestions
351
352
```python
353
import redis
354
355
r = redis.Redis(host='localhost', port=6379, decode_responses=True)
356
357
def setup_autocomplete():
358
# Add product titles to suggestion dictionary
359
suggestions = [
360
("Gaming Laptop", 100, "product:1001"),
361
("Wireless Headphones", 90, "product:1002"),
362
("Gaming Mouse", 80, "product:1003"),
363
("Laptop Stand", 70, "product:1004"),
364
("Wireless Keyboard", 85, "product:1005")
365
]
366
367
for suggestion, score, payload in suggestions:
368
r.ft().sugadd("product_suggestions", suggestion, score, payload=payload)
369
370
print("Added product suggestions")
371
372
def test_autocomplete(prefix):
373
# Get suggestions for prefix
374
suggestions = r.ft().sugget(
375
"product_suggestions",
376
prefix,
377
fuzzy=True,
378
max=5,
379
with_scores=True,
380
with_payloads=True
381
)
382
383
print(f"Suggestions for '{prefix}':")
384
for suggestion in suggestions:
385
if len(suggestion) >= 3:
386
text, score, payload = suggestion[0], suggestion[1], suggestion[2]
387
print(f" {text} (score: {score}, product: {payload})")
388
else:
389
print(f" {suggestion[0]}")
390
391
setup_autocomplete()
392
test_autocomplete("gam")
393
test_autocomplete("lap")
394
test_autocomplete("wire")
395
```
396
397
### Full-Text Search with Highlighting
398
399
```python
400
import redis
401
from redis.commands.search.query import Query
402
403
r = redis.Redis(host='localhost', port=6379, decode_responses=True)
404
405
def search_with_highlighting(search_term):
406
# Search with result highlighting
407
query = Query(search_term).highlight(
408
fields=["title", "description"],
409
tags=["<b>", "</b>"]
410
).return_fields("title", "description", "price")
411
412
result = r.ft("products").search(query)
413
414
print(f"Search results for '{search_term}' with highlighting:")
415
for doc in result.docs:
416
print(f"Title: {doc.title}")
417
print(f"Description: {doc.description}")
418
print(f"Price: ${doc.price}")
419
print("-" * 50)
420
421
search_with_highlighting("gaming laptop")
422
search_with_highlighting("wireless")
423
```
424
425
### Spell Checking and Synonyms
426
427
```python
428
import redis
429
430
r = redis.Redis(host='localhost', port=6379, decode_responses=True)
431
432
def setup_dictionaries():
433
# Add terms to custom dictionary for spell checking
434
tech_terms = ["laptop", "desktop", "smartphone", "tablet", "headphones"]
435
r.ft().dictadd("tech_dict", *tech_terms)
436
437
# Add synonyms
438
synonyms = ["laptop", "notebook", "computer"]
439
r.ft().dictadd("laptop_synonyms", *synonyms)
440
441
print("Added custom dictionaries")
442
443
def spell_check_search(query):
444
# This would typically be implemented with a custom spell checker
445
# using the dictionaries created above
446
try:
447
result = r.ft("products").search(query)
448
if result.total == 0:
449
print(f"No results for '{query}'. Did you mean:")
450
# Implement fuzzy search or suggestion logic here
451
fuzzy_query = Query(query).no_content()
452
fuzzy_result = r.ft("products").search(fuzzy_query)
453
print(f"Found {fuzzy_result.total} potential matches")
454
except Exception as e:
455
print(f"Search error: {e}")
456
457
setup_dictionaries()
458
spell_check_search("laptpo") # Misspelled "laptop"
459
```
460
461
### Index Management and Monitoring
462
463
```python
464
import redis
465
466
r = redis.Redis(host='localhost', port=6379, decode_responses=True)
467
468
def monitor_search_indexes():
469
# List all indexes
470
indexes = r.ft()._list()
471
print(f"Available indexes: {indexes}")
472
473
# Get detailed index information
474
for index_name in indexes:
475
try:
476
info = r.ft(index_name).info()
477
print(f"\nIndex: {index_name}")
478
print(f" Documents: {info.get('num_docs', 'N/A')}")
479
print(f" Terms: {info.get('num_terms', 'N/A')}")
480
print(f" Records: {info.get('num_records', 'N/A')}")
481
print(f" Index size: {info.get('inverted_sz_mb', 'N/A')} MB")
482
483
except Exception as e:
484
print(f"Error getting info for {index_name}: {e}")
485
486
def explain_query(query):
487
# Explain query execution plan
488
try:
489
explanation = r.ft("products").explain(query)
490
print(f"Query execution plan for '{query}':")
491
print(explanation)
492
except Exception as e:
493
print(f"Error explaining query: {e}")
494
495
monitor_search_indexes()
496
explain_query("@title:gaming @price:[1000 2000]")
497
```
498
499
### Search Performance Profiling
500
501
```python
502
import redis
503
from redis.commands.search.query import Query
504
505
r = redis.Redis(host='localhost', port=6379, decode_responses=True)
506
507
def profile_search_performance():
508
queries = [
509
"gaming",
510
"@title:laptop",
511
"@price:[200 500]",
512
"(@title:gaming) | (@category:Electronics)"
513
]
514
515
for query in queries:
516
try:
517
# Profile query performance
518
profile_result = r.ft("products").profile(Query(query))
519
520
print(f"\nQuery: {query}")
521
print(f"Profile results: {profile_result}")
522
523
except Exception as e:
524
print(f"Error profiling query '{query}': {e}")
525
526
profile_search_performance()
527
```
528
529
### Batch Document Operations
530
531
```python
532
import redis
533
534
r = redis.Redis(host='localhost', port=6379, decode_responses=True)
535
536
def batch_document_operations():
537
# Batch add documents to index
538
documents = [
539
{
540
"id": "product:2001",
541
"title": "Gaming Mouse",
542
"description": "RGB gaming mouse with programmable buttons",
543
"category": "Electronics",
544
"brand": "GamePro",
545
"price": 79.99,
546
"rating": 4.3
547
},
548
{
549
"id": "product:2002",
550
"title": "Mechanical Keyboard",
551
"description": "Cherry MX switches mechanical keyboard",
552
"category": "Electronics",
553
"brand": "KeyMaster",
554
"price": 149.99,
555
"rating": 4.7
556
}
557
]
558
559
# Use pipeline for batch operations
560
pipe = r.pipeline()
561
562
for doc in documents:
563
doc_id = doc.pop("id")
564
pipe.hset(doc_id, mapping=doc)
565
566
results = pipe.execute()
567
print(f"Batch added {len(results)} documents")
568
569
# Batch retrieve documents
570
doc_ids = ["product:2001", "product:2002"]
571
retrieved_docs = r.ft("products").mget(*doc_ids)
572
573
print("Retrieved documents:")
574
for doc in retrieved_docs:
575
if doc:
576
print(f" {doc.get('title', 'N/A')} - ${doc.get('price', 'N/A')}")
577
578
batch_document_operations()
579
```