Redis Search
Single source of guidance for Redis Search — the retrieval surface that spans lexical, numeric, geo, JSON-path, and vector queries. Vector fields are part of the same FT.CREATE machinery as TEXT/TAG/NUMERIC fields, and FT.HYBRID blends lexical and vector ranking in one command, so this skill covers them together.
When to apply
- Creating, modifying, or reviewing a Redis Search index (
FT.CREATE, FT.ALTER).
- Writing or optimizing
FT.SEARCH, FT.AGGREGATE, or FT.HYBRID queries.
- Picking between
TEXT, TAG, NUMERIC, GEO, GEOSHAPE, VECTOR, or JSON-path fields.
- Defining a
VECTOR field, choosing HNSW vs FLAT, tuning HNSW parameters.
- Building a retrieval-augmented generation (RAG) pipeline.
- Rolling out a new index schema without downtime.
- Troubleshooting empty results, slow queries, or tokenization issues with
FT.EXPLAIN, FT.PROFILE, FT.INFO.
1. Pick the right command
Three query commands. Reach for the narrowest one that fits.
| Command |
When to use |
Mental model |
Minimum Redis |
| FT.SEARCH |
Document retrieval, ranked or sorted. Best default. |
Returns matching docs directly. |
2.0 (module) / 8.0 (built-in) |
| FT.AGGREGATE |
Faceting, computed fields, custom output shape, analytics. |
Declarative pipeline: LOAD, APPLY, GROUPBY, REDUCE, SORTBY. |
2.0 / 8.0 |
| FT.HYBRID |
Blend lexical (BM25) with vector similarity, with configurable fusion. |
Pipeline with explicit SEARCH + VSIM legs and a COMBINE fusion stage. |
8.4.0 |
# FT.SEARCH — most common
FT.SEARCH idx:products "@category:{electronics} @price:[100 500]" LIMIT 0 20 RETURN 3 name price category
# FT.AGGREGATE — top categories by avg price
FT.AGGREGATE idx:products "*" GROUPBY 1 @category REDUCE AVG 1 @price AS avg_price SORTBY 2 @avg_price DESC
# FT.HYBRID (Redis ≥ 8.4) — lexical + vector fusion
FT.HYBRID idx:docs
SEARCH "@title:transformers" SCORER BM25 YIELD_SCORE_AS lexscore
VSIM embedding $vec KNN count 1 K 50 YIELD_SCORE_AS vecscore
COMBINE RRF 2 CONSTANT 60
PARAMS 2 vec "..."
DIALECT 2
For Redis < 8.4 the lexical+vector blend is approximated with FT.SEARCH pre-filter + =>[KNN ...]. See [references/command-selection.md](references/command-selection.md) and [references/hybrid-search.md](references/hybrid-search.md).
2. Schema basics — FT.CREATE
FT.CREATE indexes Hash or JSON documents matching a PREFIX. Always set PREFIX. Use DIALECT 2 (the default since Redis 8; required for vector queries).
FT.CREATE idx:products ON HASH PREFIX 1 product:
SCHEMA
name TEXT WEIGHT 2.0
category TAG SORTABLE
price NUMERIC SORTABLE
location GEO
embedding VECTOR HNSW 6
TYPE FLOAT32
DIM 1536
DISTANCE_METRIC COSINE
Pick the narrowest field type that supports your access pattern:
| Field type |
Use when |
Notes |
TEXT |
Full-text search |
Tokenized + stemmed; not for exact match |
TAG |
Exact match / filtering |
Add SORTABLE UNF for fastest tag queries |
NUMERIC |
Range queries, sorting |
Prices, counts, timestamps |
GEO |
Lat/long points |
Stores, users |
GEOSHAPE |
Polygon / area queries |
Delivery zones, regions |
VECTOR |
Similarity search |
HNSW or FLAT; see §4 |
JSON $.path AS alias |
Nested JSON fields |
ON JSON; see [references/json-indexing.md](references/json-indexing.md) |
The classic mistake is TEXT for a category or status field "because it's a string" — TAG is roughly 10× faster for exact-match filtering.
See [references/index-creation.md](references/index-creation.md), [references/field-types.md](references/field-types.md), [references/dialect.md](references/dialect.md), [references/ft-create-options.md](references/ft-create-options.md), [references/json-indexing.md](references/json-indexing.md).
3. Common queries
Narrow with filters; return only what you need.
# Tag filter + numeric range, sorted by price
FT.SEARCH idx:products "@category:{electronics} @price:[100 500]"
SORTBY price ASC
LIMIT 0 20
RETURN 3 name price category
# Text + tag filter
FT.SEARCH idx:products "wireless headphones @category:{audio}"
# Negation and OR
FT.SEARCH idx:products "@category:{audio} -@brand:{generic} (@price:[0 100] | @on_sale:{true})"
Operators worth remembering: space = AND, | = OR, - = NOT, ~ = optional (scoring boost), =>{$weight: N} = boost. Escape hyphens and special characters inside TAG values (@sku:{ABC\\-123}). See [references/query-syntax.md](references/query-syntax.md) and [references/search-syntax-primitives.md](references/search-syntax-primitives.md) for the DSL vocabulary.
For tokenization gotchas (stemming, stopwords, language) see [references/text-tokenization.md](references/text-tokenization.md). For result shaping (SORTBY, RETURN, HIGHLIGHT, SUMMARIZE, NOCONTENT) see [references/result-shaping.md](references/result-shaping.md). For performance levers (pre-filters, SORTABLE fields, tight RETURN, FT.PROFILE) see [references/query-optimization.md](references/query-optimization.md).
4. Vector basics
Three vector settings have to match the embedding model exactly:
DIM — output dimensionality (e.g. 1536 for OpenAI text-embedding-3-small). Mismatch produces silent garbage.
DISTANCE_METRIC — COSINE for normalized text embeddings (common case), IP for unnormalized inner-product, L2 for raw Euclidean.
TYPE — usually FLOAT32. Use FLOAT16 or quantized variants only when memory is the binding constraint.
# Index
FT.CREATE idx:docs ON HASH PREFIX 1 doc:
SCHEMA
content TEXT
embedding VECTOR HNSW 6 TYPE FLOAT32 DIM 1536 DISTANCE_METRIC COSINE
# Pure KNN query (top 5 by cosine similarity)
FT.SEARCH idx:docs "*=>[KNN 5 @embedding $vec AS score]"
PARAMS 2 vec "..."
SORTBY score
DIALECT 2
| Algorithm |
Speed |
Accuracy |
Memory |
Use for |
| HNSW |
Fast (approximate) |
~95%+ recall (tunable) |
Higher |
Production: >10k vectors, latency-sensitive |
| FLAT |
Slow (exact) |
100% |
Lower |
Small corpora (<10k), exact-match required |
HNSW tuning levers: M (16–64, connections per node), EFCONSTRUCTION (100–500, build quality), EFRUNTIME (query-time candidate list).
See [references/vector-query.md](references/vector-query.md), [references/algorithm-choice.md](references/algorithm-choice.md).
5. Hybrid retrieval
Two distinct patterns get called "hybrid." Pick by intent.
Filter-then-vector (any Redis version) — apply attribute filters so the engine narrows the search space before the vector comparison.
FT.SEARCH idx:docs "(@category:{tech} @date:[2024 +inf])=>[KNN 10 @embedding $vec AS score]"
PARAMS 2 vec "..."
SORTBY score
DIALECT 2
Lexical + vector fusion (Redis ≥ 8.4) — blend BM25 text scoring with vector similarity, fuse with RRF or LINEAR. Use FT.HYBRID (see §1).
Don't fetch a wide unfiltered result and filter client-side — slower and less accurate. See [references/hybrid-search.md](references/hybrid-search.md).
6. Aggregations and shaping
FT.AGGREGATE is the declarative result-shaping command. Build a pipeline of stages.
# Top 5 categories by total revenue
FT.AGGREGATE idx:orders "@status:{shipped}"
LOAD 2 @category @amount
GROUPBY 1 @category
REDUCE SUM 1 @amount AS revenue
SORTBY 2 @revenue DESC
LIMIT 0 5
Common stages: LOAD, APPLY (computed fields), FILTER (post-query), GROUPBY + REDUCE (SUM, COUNT, AVG, FIRST_VALUE, TOLIST), SORTBY, LIMIT.
For long-running result sets use WITHCURSOR + FT.CURSOR READ to page server-side. See [references/aggregate-pipeline.md](references/aggregate-pipeline.md) and [references/aggregate-cursors.md](references/aggregate-cursors.md).
7. RAG pattern
Standard pipeline: embed the query, vector-search Redis, pass top-K context to the LLM.
Practical tips:
- Match the metric to the embedding model (almost always
COSINE for normalized text models).
- Chunk long documents (200–500-token chunks usually beat indexing whole pages).
- Batch inserts rather than one call per record.
- Pre-filter with attributes (tenant, recency, document type) before the vector search — see §5.
- Re-rank at the top of the funnel if precision matters more than recall.
See [references/rag-pattern.md](references/rag-pattern.md).
8. Operations
Zero-downtime schema changes: keep app queries pointed at an alias and swap the underlying index.
FT.CREATE idx:products_v2 ON HASH PREFIX 1 product: SCHEMA ...
FT.ALIASUPDATE products idx:products_v2
# App queries are stable:
FT.SEARCH products "@category:{electronics}"
Useful management commands: FT.INFO, FT.DROPINDEX, FT._LIST, FT.ALIASADD/UPDATE/DEL. See [references/index-management.md](references/index-management.md).
Debug empty or slow queries with FT.EXPLAIN (shows how the query was parsed) and FT.PROFILE (shows execution stats). See [references/debugging.md](references/debugging.md).
9. Client examples
Inline examples in this SKILL.md are CLI / RESP form — the wire protocol every client serializes to. For idiomatic snippets in a specific client:
- redis-py (Python, raw client): [references/clients/python-redis-py.md](references/clients/python-redis-py.md)
- Jedis (Java): [references/clients/java-jedis.md](references/clients/java-jedis.md)
- RedisVL (Python, higher-level SDK on top of redis-py): [references/clients/python-redisvl.md](references/clients/python-redisvl.md)
Other clients (Lettuce, node-redis, go-redis, NRedisStack, .NET) translate the same CLI form; coverage is tracked as a follow-up.
References