---
name: redis-search
description: Redis Search guidance covering FT.CREATE schema design, field type selection (TEXT, TAG, NUMERIC, GEO, GEOSHAPE, VECTOR, JSON path), DIALECT 2 query syntax, FT.SEARCH / FT.AGGREGATE / FT.HYBRID command selection, vector similarity with HNSW or FLAT, hybrid retrieval combining lexical and vector ranking, RAG pipelines, zero-downtime index updates via aliases, and debugging with FT.PROFILE and FT.EXPLAIN. Use when defining a search index on Hash or JSON documents, writing FT.SEARCH queries with filters, sorting, aggregation, or vector KNN, tuning HNSW parameters, building a RAG retrieval pipeline, or troubleshooting slow or empty search results.
license: MIT
metadata:
  author: Redis, Inc.
  version: "0.1.0"
---

# 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), `EF_CONSTRUCTION` (100–500, build quality), `EF_RUNTIME` (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

- [Redis: Search and query](https://redis.io/docs/latest/develop/interact/search-and-query/)
- [Redis: Vectors](https://redis.io/docs/latest/develop/ai/search-and-query/vectors/)
- [Redis: Query syntax](https://redis.io/docs/latest/develop/interact/search-and-query/query/)
- [Redis: Query dialects](https://redis.io/docs/latest/develop/interact/search-and-query/advanced-concepts/dialects/)
- [Redis: RAG quickstart](https://redis.io/docs/latest/develop/get-started/rag/)
- [FT.CREATE](https://redis.io/docs/latest/commands/ft.create/) · [FT.SEARCH](https://redis.io/docs/latest/commands/ft.search/) · [FT.AGGREGATE](https://redis.io/docs/latest/commands/ft.aggregate/) · [FT.HYBRID](https://redis.io/docs/latest/commands/ft.hybrid/)
- [RedisVL documentation](https://docs.redisvl.com/en/latest/)
