title: FT.HYBRID

summary: Performs hybrid search combining text search and vector similarity search

title: Overview

text:
Performs hybrid search combining text search and vector similarity with configurable fusion methods.

`FT.HYBRID` provides a unified interface for combining traditional full-text and vector-based search within a single query. It supports hybrid retrieval use cases such as semantic search, Retrieval-Augmented Generation (RAG), and intelligent agent applications. The command builds on the familiar query syntax of `FT.SEARCH` and `FT.AGGREGATE`, simplifying hybrid query construction while enabling flexible post-processing through aggregation capabilities.

This command will only return document IDs (`keyid`) and scores to which the user has read access.
To retrieve entire documents, use projections with `LOAD *` or `LOAD <count> field...`.

[Examples](#examples)

title: Required arguments

text:
index

is the name of the index. You must first create the index using [`FT.CREATE`]().

SEARCH "search-expression"

defines the text search component of the hybrid query. The search expression uses the same syntax as [`FT.SEARCH`]() queries, supporting all text search capabilities including field-specific searches, boolean operations, and phrase matching.

VSIM @vector_field "vector-data"

defines the vector similarity component of the hybrid query. The `@vector_field` specifies which vector field in the index to search against (for example, `$vector`), and `"vector-data"` contains the query vector for similarity comparison (for example, `PARAMS 2 $vector <vector-blob>`).

title: Optional arguments

text:
SCORER algorithm params...

specifies the scoring algorithm and parameters for the text search component. Supports aliasing and follows the parameter count convention where the first number indicates the total count of following parameters.

Example: `SCORER 4 BM25 1.2 0.75` uses BM25 algorithm with parameters 1.2 and 0.75.

YIELD_SCORE_AS alias-search-score

assigns an alias to the search score for use in post-processing operations like `APPLY` or `SORTBY`.

KNN count K top-k [EF_RUNTIME ef-value] [YIELD_SCORE_AS name]

configures K-nearest neighbors search for vector similarity. The `count` parameter indicates the number of following parameters. `K` specifies the number of nearest neighbors to find. `EF_RUNTIME` controls the search accuracy vs. speed tradeoff. `YIELD_SCORE_AS` assigns an alias to the score value.

RANGE count RADIUS radius-value [EPSILON epsilon-value] [YIELD_SCORE_AS name]

configures range-based vector search within a specified radius. The `count` parameter indicates the number of following parameters. `RADIUS` defines the maximum distance for matches. `EPSILON` provides additional precision control.

FILTER "filter-expression"

applies pre-filtering to vector search results or post-filtering when used after the `COMBINE` step as post-processing. This filter affects which documents are considered for vector similarity but doesn't impact scoring. In contrast, the `SEARCH` component affects both filtering and scoring. The `FILTER` syntax uses a search expression with the same syntax as [`FT.SEARCH`](), supporting all text search capabilities including field-specific searches, boolean operations, and phrase matching

POLICY [ADHOC_BF|BATCHES] [BATCH_SIZE batch-size-value]

controls the pre-filtering policy for vector queries. `ADHOC_BF` processes filters on-demand and `BATCHES` processes in configurable batch sizes. See the [pre-filtering policy]() for more information.

COMBINE method params...

specifies how to fuse the text search and vector similarity results. Supports multiple fusion methods:

- **RRF (Reciprocal Rank Fusion)**: Default method. Parameters include `WINDOW` (default 20) and `CONSTANT` (default 60).
- **LINEAR**: Linear combination with `ALPHA` and `BETA` weights.
- **FUNCTION**: Custom fusion function (future support).

Example: `COMBINE RRF 4 WINDOW 40 CONSTANT 1.5`

YIELD_SCORE_AS alias-combined-score

assigns an alias to the combined fusion score for use in post-processing operations.

LOAD count field...

specifies which fields to return in the results. The `count` parameter indicates the number of fields that follow.

Example: `LOAD 3 @category @brand @price`

GROUPBY count field... REDUCE function...

groups results by specified fields and applies reduction functions. Follows the parameter count convention. The `count` parameter indicates the number of fields that follow.

Example: `GROUPBY 4 category brand REDUCE 2 COUNT 0`

APPLY expression AS field

applies transformations to create new fields. Can reference aliased scores and distances.

Example: `APPLY "@vector_distance+@score" AS final_score`

SORTBY count field [ASC|DESC]

sorts the final results by the specified field in ascending or descending order. The `count` parameter indicates the number of fields that follow.

LIMIT offset num

limits the final results. Default limit is 10 when not specified. The `offset` parameter is zero-indexed.

PARAMS count key value...

defines parameter substitution for the query. Parameters can be referenced in search expressions using `$parameter_name`.

Example: `PARAMS 4 min_price 50 max_price 200`

TIMEOUT timeout

sets a runtime timeout for the query execution in milliseconds.

title: Default values and behaviors

text:
FT.HYBRID provides sensible defaults to ease onboarding:

- **Query count**: 2 (one SEARCH and one VSIM component required)
- **Default LIMIT**: 10 results
- **Default SCORER**: BM25STD for text search
- **Default KNN K**: 10 neighbors
- **Default RRF WINDOW**: 20
- **Default RRF CONSTANT**: 60
- **Default EF_RUNTIME**: 10 (as vector KNN [default](https://redis.io/docs/latest/develop/ai/search-and-query/vectors/#hnsw-index))
- **Default EPSILON**: 0.01 (as the vector RANGE [default]())

title: Parameter count convention

text:
All multi-parameter options use a count prefix that contains ALL tokens that follow:

- `KNN 4 K 10 EF_RUNTIME 100` - 2 key-value pairs
- `PARAMS 4 min_price 50 max_price 200` - 2 key-value pairs
- `COMBINE RRF 4 WINDOW 40 CONSTANT 1.5` - RRF method with 2 key-value pairs

The only exception is alias usage with `AS`, which is not counted:
- `APPLY "@vector_distance+@score" AS final_score`
- `LOAD 3 @category AS cat @brand AS brd @price AS prc`

title: Reserved fields

text:
The following fields are reserved for internal use:

- `@__key` - reserved for loading key IDs when required
- `@__score` - reserved for the combined score (can be aliased)
- `@vector_distance` - yields the vector distance (can be aliased)
- `@__combined_score` - fused score from the COMBINE step

title: Examples

text:
Basic hybrid search

Perform a simple hybrid search combining text search for "laptop" with vector similarity:

127.0.0.1:6379> FT.HYBRID products-idx
  SEARCH "laptop"
  VSIM @description_vector $query_vec
  KNN 2 K 10
  PARAMS 2 query_vec <vector_blob>

Hybrid search with custom scoring and fusion

Search for electronics with custom BM25 parameters and RRF fusion:

127.0.0.1:6379> FT.HYBRID products-idx
  SEARCH "@category:electronics"
  SCORER 4 BM25 1.5 0.8
  YIELD_SCORE_AS text_score
  VSIM @features_vector $query_vec
  KNN 4 K 20 EF_RUNTIME 200
  YIELD_SCORE_AS vector_score
  COMBINE RRF 4 WINDOW 50 CONSTANT 80
  YIELD_SCORE_AS hybrid_score
  SORTBY 2 hybrid_score DESC
  LIMIT 0 20
  PARAMS 2 query_vec <vector_blob>

Hybrid search with pre-filtering

Search with vector pre-filtering and post-processing:

127.0.0.1:6379> FT.HYBRID products-idx
  SEARCH "smartphone"
  VSIM @image_vector $query_vec
  KNN 2 K 15
  FILTER "@price:[100 500]"
  COMBINE LINEAR 4 ALPHA 0.7 BETA 0.3
  LOAD 4 @title @price @category @rating
  APPLY "@price * 0.9" AS discounted_price
  SORTBY 2 rating DESC
  PARAMS 2 query_vec <vector_blob>

Hybrid search with parameters

Use parameter substitution for dynamic queries:

127.0.0.1:6379> FT.HYBRID products-idx
  SEARCH "@brand:$brand_name"
  VSIM @content_vector $query_vector
  RANGE 4 RADIUS 0.8 EPSILON 0.1
  FILTER "@availability:$stock_status"
  PARAMS 6 brand_name "Apple" query_vector <vector_blob> stock_status "in_stock"

title: Complexity

text:
FT.HYBRID complexity depends on both the text search and vector similarity components:
- Text search: O(n) for simple term searches, where n is the number of matching documents. In multi-term queries with INTERSECT or UNION, or when using fuzzy or prefix matches, the complexity increases proportionally to the total number of entries scanned across all participating terms.
- Vector search: O(log n) for KNN with HNSW index, O(n) for range queries
- Fusion: O(k) where k is the number of results to combine
- Overall complexity is typically dominated by the more expensive component

text:
| Redis
Software | Redis
Cloud | Notes |
|:----------------------|:-----------------|:------|
| ✅ Standard
<nobr>✅ Active-Active</nobr> | ✅ Standard
<nobr>✅ Active-Active</nobr> |  |

title: Return information

text:
**RESP2:**

One of the following:
* [Array]() with the first element being the total number of results, followed by document IDs and their field-value pairs as [arrays]().
* [Simple error reply]() in these cases: no such index, syntax error in query.

**RESP3:**

One of the following:
* [Map]() with the following fields:
    - `total_results`: [Integer]() - total number of results
    - `execution_time`: [double]() containing hybrid query execution time
    - `warnings`: [Array]() of warning messages indicating partial results due to index errors or `MAXPREFIXEXPANSIONS`, out-of-memory conditions, and `TIMEOUT` reached
    - `results`: [Array]() of [maps]() containing document information
* [Simple error reply]() in these cases: no such index, syntax error in query.

title: See also

text: [`FT.CREATE`]() | [`FT.SEARCH`]() | [`FT.AGGREGATE`]()

title: Related topics

text:
- [Vector search concepts]()
- [Combined search]()


title: FT.INFO

summary: Returns information and statistics on the index

page_type: content

title: Overview

role: overview

text: Returns information and statistics about a given index.

title: Required arguments

role: content

text:
`index`
<br />
is the name of the given index. You must first create the index using [`FT.CREATE`](). You can also use an alias of `index` created using [`FT.ALIASADD`]() or [`FT.ALIASUPDATE`]().

title: Returned values

role: returns

title: General

text:
| Return field name | Definition |
|:---               |:---        |
| `index_name` | The index name that was defined when index was created. |
| `index_options` | The index options selected during `FT.CREATE` such as `FILTER {filter}`, `LANGUAGE {default_lang}`, etc. |
| `index_definition` | Includes `key_type`, hash or JSON; `prefixes`, if any; and `default_score`. |
| `attributes` | The index schema field names, types, and attributes. |
| `num_docs` | The number of documents. |
| `max_doc_id` | The maximum document ID. |
| `num_terms` | The number of distinct terms. |
| `num_records` | The total number of records. |

title: Various size statistics

text:
| Statistic | Definition |
|:---       |:---        |
| `inverted_sz_mb` | The memory used by the inverted index, which is the core data structure used for searching in RediSearch. The size is given in megabytes. |
| `vector_index_sz_mb` | The memory used by the vector index, which stores any vectors associated with each document. |
| `total_inverted_index_blocks` | The total number of blocks in the inverted index. |
| `offset_vectors_sz_mb` | The memory used by the offset vectors, which store positional information for terms in documents. |
| `doc_table_size_mb` | The memory used by the document table, which contains metadata about each document in the index. |
| `sortable_values_size_mb` | The memory used by sortable values, which are values associated with documents and used for sorting purposes. |
| `key_table_size_mb` | The memory used by the key table, which stores the mapping between document IDs and Redis keys. |
| `geoshapes_sz_mb` | The memory used by GEO-related fields. |
| `records_per_doc_avg` | The average number of records (including deletions) per document. |
| `bytes_per_record_avg` | The average size of each record in bytes. |
| `offsets_per_term_avg` | The average number of offsets (position information) per term. |
| `offset_bits_per_record_avg` | The average number of bits used for offsets per record. |
| `tag_overhead_sz_mb` | The size of the TAG index structures used for optimising performance. |
| `text_overhead_sz_mb` | The size of the TEXT index structures used for optimising performance. |
| `total_index_memory_sz_mb` | The total memory consumed by all indexes in the DB. |

title: Indexing-related statistics

text:
| Statistic | Definition |
|:---       |:---        |
| `hash_indexing_failures` | The number of failures encountered during indexing. |
| `total_indexing_time` | The cumulative wall-clock time spent indexing documents in ms. |
| `indexing` | Indicates whether the index is currently being generated. |
| `percent_indexed` | The percentage of the index that has been successfully generated (1 means 100%). |
| `number_of_uses` | The number of times the index has been used. |
| `cleaning` | The index deletion flag. A value of `1` indicates index deletion is in progress. |

title: Garbage collection statistics

text:
| Statistic | Definition |
|:---       |:---        |
| `bytes_collected` | The number of bytes collected during garbage collection. |
| `total_ms_run` | The total time in milliseconds spent on garbage collection. |
| `total_cycles` | The total number of garbage collection cycles. |
| `average_cycle_time_ms` | The average time in milliseconds for each garbage collection cycle. The value `nan` indicates that the average cycle time is not available. |
| `last_run_time_ms` | The time in milliseconds taken by the last garbage collection run. |

The next two GC-related fields are relevant in scenarios where simultaneous changes occurred in the same memory area for both the parent process and the child process, resulting in the parent discarding these changes.

| Statistic | Definition |
|:---       |:---        |
| `gc_numeric_trees_missed` | The number of numeric tree nodes whose changes were discarded due to splitting by the parent process during garbage collection. |
| `gc_blocks_denied` | The number of blocks whose changes were discarded (skipped) because they were modified by the parent process during the garbage collection. Notably, as inverted index blocks are append-only, only the last block of an inverted index can be skipped. |

title: Cursor statistics

text:
| Statistic | Definition |
|:---       |:---        |
| `global_idle` | The number of idle cursors in the system. |
| `global_total` | The total number of cursors in the system. |
| `index_capacity` | The maximum number of cursors allowed per index. |
| `index_total` | The total number of cursors open on the index. |

title: Other statistics

text:
- Dialect statistics: the number of times the index was searched using each DIALECT, 1 - 4.
- Index error statistics, including `indexing failures`, `last indexing error`, and `last indexing error key`.
- Field statistics, including `indexing failures`, `last indexing error`, and `last indexing error key` for each schema field.

title: Example

role: example

text:
Return statistics about an index

127.0.0.1:6379> ft.info idx:bicycle
 1) index_name
 2) idx:bicycle
 3) index_options
 4) (empty array)
 5) index_definition
 6) 1) key_type
    2) JSON
    3) prefixes
    4) 1) bicycle:
    5) default_score
    6) "1"
 7) attributes
 8) 1) 1) identifier
       2) $.pickup_zone
       3) attribute
       4) pickup_zone
       5) type
       6) GEOSHAPE
       7) coord_system
       8) SPHERICAL
    2) 1) identifier
       2) $.store_location
       3) attribute
       4) store_location
       5) type
       6) GEO
    3) 1) identifier
       2) $.brand
       3) attribute
       4) brand
       5) type
       6) TEXT
       7) WEIGHT
       8) "1"
    4) 1) identifier
       2) $.model
       3) attribute
       4) model
       5) type
       6) TEXT
       7) WEIGHT
       8) "1"
    5) 1) identifier
       2) $.description
       3) attribute
       4) description
       5) type
       6) TEXT
       7) WEIGHT
       8) "1"
    6) 1) identifier
       2) $.price
       3) attribute
       4) price
       5) type
       6) NUMERIC
    7) 1) identifier
       2) $.condition
       3) attribute
       4) condition
       5) type
       6) TAG
       7) SEPARATOR
       8) ,
 9) num_docs
10) "10"
11) max_doc_id
12) "10"
13) num_terms
14) "546"
15) num_records
16) "692"
17) inverted_sz_mb
18) "0.003993034362792969"
19) vector_index_sz_mb
20) "0"
21) total_inverted_index_blocks
22) "551"
23) offset_vectors_sz_mb
24) "7.047653198242188e-4"
25) doc_table_size_mb
26) "7.152557373046875e-4"
27) sortable_values_size_mb
28) "0"
29) key_table_size_mb
30) "3.0422210693359375e-4"
31) geoshapes_sz_mb
32) "0.00426483154296875"
33) records_per_doc_avg
34) "69.19999694824219"
35) bytes_per_record_avg
36) "6.0505781173706055"
37) offsets_per_term_avg
38) "1.0679190158843994"
39) offset_bits_per_record_avg
40) "8"
41) hash_indexing_failures
42) "0"
43) total_indexing_time
44) "4.539999961853027"
45) indexing
46) "0"
47) percent_indexed
48) "1"
49) number_of_uses
50) (integer) 1
51) cleaning
52) (integer) 0
53) gc_stats
54)  1) bytes_collected
     2) "0"
     3) total_ms_run
     4) "0"
     5) total_cycles
     6) "0"
     7) average_cycle_time_ms
     8) "nan"
     9) last_run_time_ms
    10) "0"
    11) gc_numeric_trees_missed
    12) "0"
    13) gc_blocks_denied
    14) "0"
55) cursor_stats
56) 1) global_idle
    2) (integer) 0
    3) global_total
    4) (integer) 0
    5) index_capacity
    6) (integer) 128
    7) index_total
    8) (integer) 0
57) dialect_stats
58) 1) dialect_1
    2) (integer) 0
    3) dialect_2
    4) (integer) 0
    5) dialect_3
    6) (integer) 0
    7) dialect_4
    8) (integer) 0
59) Index Errors
60) 1) indexing failures
    2) (integer) 0
    3) last indexing error
    4) N/A
    5) last indexing error key
    6) "N/A"
61) field statistics
62) 1) 1) identifier
       2) $.pickup_zone
       3) attribute
       4) pickup_zone
       5) Index Errors
       6) 1) indexing failures
          2) (integer) 0
          3) last indexing error
          4) N/A
          5) last indexing error key
          6) "N/A"
    2) 1) identifier
       2) $.store_location
       3) attribute
       4) store_location
       5) Index Errors
       6) 1) indexing failures
          2) (integer) 0
          3) last indexing error
          4) N/A
          5) last indexing error key
          6) "N/A"
    3) 1) identifier
       2) $.brand
       3) attribute
       4) brand
       5) Index Errors
       6) 1) indexing failures
          2) (integer) 0
          3) last indexing error
          4) N/A
          5) last indexing error key
          6) "N/A"
    4) 1) identifier
       2) $.model
       3) attribute
       4) model
       5) Index Errors
       6) 1) indexing failures
          2) (integer) 0
          3) last indexing error
          4) N/A
          5) last indexing error key
          6) "N/A"
    5) 1) identifier
       2) $.description
       3) attribute
       4) description
       5) Index Errors
       6) 1) indexing failures
          2) (integer) 0
          3) last indexing error
          4) N/A
          5) last indexing error key
          6) "N/A"
    6) 1) identifier
       2) $.price
       3) attribute
       4) price
       5) Index Errors
       6) 1) indexing failures
          2) (integer) 0
          3) last indexing error
          4) N/A
          5) last indexing error key
          6) "N/A"
    7) 1) identifier
       2) $.condition
       3) attribute
       4) condition
       5) Index Errors
       6) 1) indexing failures
          2) (integer) 0
          3) last indexing error
          4) N/A
          5) last indexing error key
          6) "N/A"

title: Redis Software and Redis Cloud compatibility

text:
| Redis
Software | Redis Cloud
Flexible & Annual | Redis Cloud
Free & Fixed | Notes |
|:----------------------|:-----------------|:-----------------|:------|
| ✅ Supported | ✅ Supported | ✅ Supported</nobr> |  |

title: Return information

text:
**RESP2:**

One of the following:
* [Array]() of key-value pairs containing index information and statistics.
* [Simple error reply]() in these cases: no such index.

**RESP3:**

One of the following:
* [Map]() containing index information and statistics as key-value pairs.
* [Simple error reply]() in these cases: no such index.

title: See also

role: related

text: [`FT.CREATE`]() | [`FT.SEARCH`]() | [`FT.ALIASADD`]() | [`FT.ALIASUPDATE`]()

title: Related topics

text: [RediSearch]()


title: FT.PROFILE

summary: Performs a `FT.SEARCH` or `FT.AGGREGATE` command and collects performance information

title: Overview

text: Apply [`FT.SEARCH`]() or [`FT.AGGREGATE`]() command to collect performance details. For usage, see [Examples](#examples).

title: Required arguments

text:
index

is the name of an index created using [`FT.CREATE`]().

SEARCH | AGGREGATE

represents the profile type, either [`FT.SEARCH`]() or [`FT.AGGREGATE`]().

LIMITED

removes details of any `reader` iterators.

QUERY {query}

is the query string, sent to `FT.SEARCH` or `FT.AGGREGATE`.

<note>Note: To reduce the size of the output, use `NOCONTENT` or `LIMIT 0 0` to reduce the number of reply results, or `LIMITED` to not reply with details of `reader iterators` inside built-in unions, such as `fuzzy` or `prefix` iterators.</note>

title: Return

text:
This page contains the up-to-date profile output as of RediSearch v2.8.33, v2.10.26, v8.2.7, and v8.4.3.
The output format itself may differ between RediSearch versions, and RESP protocol versions.

`FT.PROFILE` returns a two-element array reply. The first element contains the results of the provided `FT.SEARCH` or `FT.AGGREGATE` command.
The second element contains information about query creation, iterator profiles, and result processor profiles.
Details of the second element follow in the sections below.

title: Per-shard profiles

text:
This section contains query execution details for each shard.
When more than one shard is in play, the shards will be labeled `Shard #1`, `Shard #2`, etc.
If there's only one shard, the label will be omitted.

| Returned field name      | Definition                                                                                |
|:--                       |:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `Shard ID`               | String containing the unique shard ID. In Redis Open Source, this identifier is denoted as the node ID, and is received from the `RedisModule_GetMyClusterID()` API. (Available as of RediSearch v8.4.3)                               |
| `Total` `profile` `time`     | The total run time (ms) of the query. Normally just a few ms.                                                                                |
| `Parsing` `time`           | The time (ms) spent parsing the query and its parameters into a query plan. Normally just a few ms.                                                                                |
| `Pipeline` `creation` `time` | The creation time (ms) of the execution plan, including iterators, result processors, and reducers creation. Normally just a few ms for `FT.SEARCH` queries, but expect a larger number for `FT.AGGREGATE` queries.   |
| `Total` `GIL` `time` | In multi-threaded deployments, the total time (ms) the query spent holding and waiting for the Redis Global Lock (referred to as GIL) during execution. Note: this value is only valid in the shards profile section. |
| `Warning`                | Errors that occurred during query execution.                                                                                |
| `Internal` `cursor` `reads` | The number of times the coordinator fetched result batches from a given shard during a distributed `AGGREGATE` query in cluster mode. Includes the initial request plus any subsequent batch fetches.                 |

title: Iterator profiles

text:
This section contains index iterator information, including `Type`, `Query Type`, `Term` (when applicable), `Time` (ms), `Number of reading operations`, `Child iterator`, and `Estimated number of matches` information.
Each iterator represents an executor for each part of the query plan, nested per the execution plan. The operation types mentioned below (for example, `UNION`) should match up with the provided query.

Inverted-index iterators also include the number of elements they contain. Vector iterators include additional profiling information. See [Notes on Vector iterator profile](#notes-onvector-iterator-profile) below.

Iterator types include:

* `INTERSECT` (and) with `Child iterator`
* `UNION` (or) with `Child iterator`
* `NOT` (`-`) with `Child iterator`
* `Child iterator` - details of a sub-query component of a compound query.
* `TEXT` with `Term`
* `TAG` with `Term`
* `NUMERIC` with `Term`
* `VECTOR`
* `METRIC - VECTOR DISTANCE`
* `GEO` with `Term`
* `EMPTY`
* `WILDCARD`
* `OPTIONAL`
* `OPTIMIZER` with `Optimizer mode` - Query optimization wrapper for `FT.SEARCH` queries sorted by a numeric field. Enabled by default in [DIALECT 4]() or explicitly with `WITHOUTCOUNT`.
* `ID-LIST` - Iterator over specific document IDs (appears when using `INKEYS`)

**Notes on `Number of reading operations` and `Estimated number of matches`**

`Number of reading operations` is the number of times an iterator was interacted with. A very high value in comparison to others is a possible warning flag. `NUMERIC` and `Child iterator` types are broken into ranges, and `Number of reading operations` will vary depending on the range. For `UNION`, the sum of the reading operations in child iterators should be equal to or greater than the child iterator's reading operations.

`Estimated number of matches` is the size of the document set. `Number of reading operations` should always be equal to or less than `Estimated number of matches`.

#### Notes on Vector iterator profile {#notes-onvector-iterator-profile}

For vector queries, the iterator profile includes additional information specific to vector search execution.

#### Vector search mode

The `Vector search mode` field indicates the execution strategy used for both `VECTOR` and `METRIC - VECTOR DISTANCE` iterator types:

| Mode | Description |
|:--   |:--          |
| `STANDARD_KNN`              | Pure KNN vector search without filters. |
| `RANGE_QUERY`               | Range-based vector search. Used with `VECTOR_RANGE` queries. |
| `HYBRID_ADHOC_BF`           | Ad-hoc brute force for filtered queries. Iterates through results that pass the filter and calculates distances on-the-fly.  |
| `HYBRID_BATCHES`            | Batch-based filtered search. Retrieves top vectors from the index in batches and checks which ones pass the filter. |
| `HYBRID_BATCHES_TO_ADHOC_BF`| Dynamic mode switching. Starts with batch-based search but switches to ad-hoc brute force if batch iterations yield insufficient results. |

#### Batch execution statistics

For queries using batch modes (`HYBRID_BATCHES` or `HYBRID_BATCHES_TO_ADHOC_BF`), additional batch statistics are included:

| Returned field name | Definition |
|:--                  |:--         |
| `Batches number`    | Total number of batch iterations executed during the search. |
| `Largest batch size`| The maximum batch size used during execution. Batch sizes may vary dynamically based on the ratio of estimated matching documents to total index size. |
| `Largest batch iteration (zero based)` | The iteration number (0-based) when the largest batch occurred. |

title: Result processor profiles

text:
Result processors form a powerful pipeline in Redis Search. They work in stages to gather, filter, score, sort, and return results as efficiently as possible based on complex query needs. Each processor reports `Time` information, which represents the total duration (in milliseconds, or ms) spent by the processor to complete its operation, and `Results processed` information, which indicates the number of times the processor was invoked during the query.

| Type            | Definition |
|:--              |:--         |
| `Metrics` `Applier` | The `Metrics Applier` processor calculates or aggregates specific metrics related to the search results. For example, this might include applying a distance or similarity metric to vector search results, or calculating scores based on relevance or other parameters. |
| `Index`           | The `Index` processor is responsible for the core retrieval of matching documents from the index based on the initial query criteria (e.g., full-text terms, filters, or numeric ranges). |
| `Scorer`          | The `Scorer` processor assigns a relevance score to each document based on the query’s specified scoring function. This function could involve factors like term frequency, inverse document frequency, or other weighted metrics. |
| `Sorter`          | The `Sorter` processor arranges the query results based on a specified sorting criterion. This could be a field value (e.g., sorting by price, date, or another attribute) or by the score assigned during the scoring phase. It operates after documents are fetched and scored, ensuring the results are ordered as required by the query (e.g., ascending or descending order). `Scorer` results will always be present in `FT.SEARCH` profiles. |
| `Loader`          | The `Loader` processor retrieves the document contents after the results have been sorted and filtered. It ensures that only the fields specified by the query are loaded, which improves efficiency, especially when dealing with large documents where only a few fields are needed. |
| `Threadsafe-Loader` | The `Threadsafe-Loader` processor safely loads document contents when the query runs in a background thread (relevant for multi-threaded deployments). It acquires the Redis Global Lock (referred to as GIL) to access document data. Reports an additional `GIL-Time` field representing the time (ms) spent holding the GIL and waiting to acquire it. |
| `Highlighter`     | The `Highlighter` processor is used to highlight matching terms in the search results. This is especially useful for full-text search applications, where relevant terms are often emphasized in the UI. |
| `Pager/Limiter`       | The `Pager/Limiter` processor is responsible for handling pagination by limiting the results to a specific range (e.g., LIMIT 0 10).It trims down the set of results to fit the required pagination window, ensuring efficient memory usage when dealing with large result sets. |
| `Counter`         | The `Counter` processor counts the total number of matching results. Used when running queries with `LIMIT 0 0` to return only the count. |
| `Grouper`         | The `Grouper` processor groups results by field values. Used with `GROUPBY` in `FT.AGGREGATE` queries. |
| `Projector`       | The `Projector` processor applies field transformations. Used with `APPLY` in `FT.AGGREGATE` queries. |
| `Network` | Collects and merges results from shards. Appears as the root processor in the coordinator's result processor chain for `FT.AGGREGATE` in cluster mode. |

title: Coordinator

text:
This section is only present when run in a multi-shard environment.

| Returned field name | Definition |
|:--                  |:--         |
| `Total coordinator time` | Time measured from the beginning of query execution until all shards have completed query execution. (ms) |
| `Post-processing time`   | The time spent generating the FT.PROFILE output (overhead) (ms). |

title: Examples

text:
Collect performance information about a simple JSON index.

Imagine you have (1) a dataset consisting of 10 JSON documents, each with the following structure;

[code example]

And (2) a corresponding index:

[code example]

Here's an example of running the `FT.PROFILE` command for a compound query.

127.0.0.1:6379> ft.profile idx:bicycle search query "@description:(kids | small) @condition:{new | used}"
1) 1) (integer) 3
   2) "bicycle:0"
   3) 1) "$"
      2) "{\"pickup_zone\":\"POLYGON((-74.0610 40.7578, -73.9510 40.7578, -73.9510 40.6678, -74.0610 40.6678, -74.0610 40.7578))\",\"store_location\":\"-74.0060,40.7128\",\"brand\":\"Velorim\",\"model\":\"Jigger\",\"price\":270,\"description\":\"Small and powerful, the Jigger is the best ride for the smallest of tikes! This is the tiniest kids\xe2\x80\x99 pedal bike on the market available without a coaster brake, the Jigger is the vehicle of choice for the rare tenacious little rider raring to go.\",\"condition\":\"new\"}"
   4) "bicycle:1"
   5) 1) "$"
      2) "{\"pickup_zone\":\"POLYGON((-118.2887 34.0972, -118.1987 34.0972, -118.1987 33.9872, -118.2887 33.9872, -118.2887 34.0972))\",\"store_location\":\"-118.2437,34.0522\",\"brand\":\"Bicyk\",\"model\":\"Hillcraft\",\"price\":1200,\"description\":\"Kids want to ride with as little weight as possible. Especially on an incline! They may be at the age when a 27.5\\\" wheel bike is just too clumsy coming off a 24\\\" bike. The Hillcraft 26 is just the solution they need!\",\"condition\":\"used\"}"
   6) "bicycle:2"
   7) 1) "$"
      2) "{\"pickup_zone\":\"POLYGON((-87.6848 41.9331, -87.5748 41.9331, -87.5748 41.8231, -87.6848 41.8231, -87.6848 41.9331))\",\"store_location\":\"-87.6298,41.8781\",\"brand\":\"Nord\",\"model\":\"Chook air 5\",\"price\":815,\"description\":\"The Chook Air 5  gives kids aged six years and older a durable and uberlight mountain bike for their first experience on tracks and easy cruising through forests and fields. The lower  top tube makes it easy to mount and dismount in any situation, giving your kids greater safety on the trails.\",\"condition\":\"used\"}"
2) 1) 1) Total profile time
      2) "0"
   2) 1) Parsing time
      2) "0"
   3) 1) Pipeline creation time
      2) "0"
   4) 1) Warning
   5) 1) Iterators profile
      2) 1) Type
         2) INTERSECT
         3) Time
         4) "0"
         5) Number of reading operations
         6) (integer) 6
         7) Child iterators
         8)  1) Type
             2) UNION
             3) Query type
             4) UNION
             5) Time
             6) "0"
             7) Number of reading operations
             8) (integer) 6
             9) Child iterators
            10)  1) Type
                 2) UNION
                 3) Query type
                 4) UNION
                 5) Time
                 6) "0"
                 7) Number of reading operations
                 8) (integer) 4
                 9) Child iterators
                10)  1) Type
                     2) TEXT
                     3) Term
                     4) kids
                     5) Time
                     6) "0"
                     7) Number of reading operations
                     8) (integer) 4
                     9) Estimated number of matches
                    10) (integer) 4
                11)  1) Type
                     2) TEXT
                     3) Term
                     4) +kid
                     5) Time
                     6) "0"
                     7) Number of reading operations
                     8) (integer) 4
                     9) Estimated number of matches
                    10) (integer) 4
            11)  1) Type
                 2) TEXT
                 3) Term
                 4) small
                 5) Time
                 6) "0"
                 7) Number of reading operations
                 8) (integer) 2
                 9) Estimated number of matches
                10) (integer) 2
         9)  1) Type
             2) UNION
             3) Query type
             4) TAG
             5) Time
             6) "0"
             7) Number of reading operations
             8) (integer) 6
             9) Child iterators
            10)  1) Type
                 2) TAG
                 3) Term
                 4) new
                 5) Time
                 6) "0"
                 7) Number of reading operations
                 8) (integer) 4
                 9) Estimated number of matches
                10) (integer) 10
            11)  1) Type
                 2) TAG
                 3) Term
                 4) used
                 5) Time
                 6) "0"
                 7) Number of reading operations
                 8) (integer) 4
                 9) Estimated number of matches
                10) (integer) 8
   6) 1) Result processors profile
      2) 1) Type
         2) Index
         3) Time
         4) "0"
         5) Results processed
         6) (integer) 3
      3) 1) Type
         2) Scorer
         3) Time
         4) "0"
         5) Results processed
         6) (integer) 3
      4) 1) Type
         2) Sorter
         3) Time
         4) "0"
         5) Results processed
         6) (integer) 3
      5) 1) Type
         2) Loader
         3) Time
         4) "0"
         5) Results processed
         6) (integer) 3

Collect performance information about a JSON index that includes vector data.

For this example, you'll create a very simple vector database and index.

Index:

[code example]

Database:

[code example]

Here's an example of running the `FT.PROFILE` command for a vector query.

127.0.0.1:6379> ft.profile vss_idx search query "*=>[KNN 3 @vector $query_vec]" PARAMS 2 query_vec "\x00\x00\x00@\x00\x00\x00@\x00\x00@@\x00\x00@@" SORTBY __vector_score DIALECT 2
1) 1) (integer) 3
   2) "vec:2"
   3) 1) "__vector_score"
      2) "2"
      3) "$"
      4) "{\"vector\":[2,2,2,2]}"
   4) "vec:3"
   5) 1) "__vector_score"
      2) "2"
      3) "$"
      4) "{\"vector\":[3,3,3,3]}"
   6) "vec:1"
   7) 1) "__vector_score"
      2) "10"
      3) "$"
      4) "{\"vector\":[1,1,1,1]}"
2) 1) 1) Total profile time
      2) "0"
   2) 1) Parsing time
      2) "0"
   3) 1) Pipeline creation time
      2) "0"
   4) 1) Warning
   5) 1) Iterators profile
      2) 1) Type
         2) VECTOR
         3) Time
         4) "0"
         5) Number of reading operations
         6) (integer) 3
   6) 1) Result processors profile
      2) 1) Type
         2) Index
         3) Time
         4) "0"
         5) Results processed
         6) (integer) 3
      3) 1) Type
         2) Metrics Applier
         3) Time
         4) "0"
         5) Results processed
         6) (integer) 3
      4) 1) Type
         2) Sorter
         3) Time
         4) "0"
         5) Results processed
         6) (integer) 3
      5) 1) Type
         2) Loader
         3) Time
         4) "0"
         5) Results processed
         6) (integer) 3

title: Return information

text:
**RESP2:**

One of the following:
* [Array]() with two elements: search results and profiling information.
* [Simple error reply]() in these cases: no such index, syntax error in query.

**RESP3:**

One of the following:
* [Map]() with two keys: `Results` containing search results and `Profile` containing profiling information.
* [Simple error reply]() in these cases: no such index, syntax error in query.

title: See also

text: [`FT.SEARCH`]() | [`FT.AGGREGATE`]()

title: Related topics

text: [RediSearch]()

brand: Velorim

model: Jigger

description: Small and powerful, the Jigger is the best ride for the smallest of tikes! This is the tiniest kids’ pedal bike on the market available without a coaster brake, the Jigger is the vehicle of choice for the rare tenacious little rider raring to go.

condition: new

section_id: examples

code: FT.CREATE idx:bicycle ON JSON PREFIX 1 bicycle: SCORE 1.0 SCHEMA $.pickup_zone AS pickup_zone GEOSHAPE $.store_location AS store_location GEO $.brand AS brand TEXT WEIGHT 1.0 $.model AS model TEXT WEIGHT 1.0 $.description AS description TEXT WEIGHT 1.0 $.price AS price NUMERIC $.condition AS condition TAG SEPARATOR ,

code: FT.CREATE vss_idx ON JSON PREFIX 1 vec: SCHEMA $.vector AS vector VECTOR FLAT 6 TYPE FLOAT32 DIM 4 DISTANCE_METRIC L2


title: FT.SEARCH

summary: Searches the index with a textual query, returning either documents or just ids

title: Overview

text:
Search the index with a textual query, returning either documents or just ids.

This command will only return keys to which the user has read access.

[Examples](#examples)

title: Required arguments

text:
index

is index name. You must first create the index using [`FT.CREATE`]().

query

is text query to search. If it's more than a single word, put it in quotes. Refer to [Query syntax]() for more details.

title: Optional arguments

role: parameters

text:
NOCONTENT

returns the document ids and not the content. This is useful if RediSearch is only an index on an external document collection.

VERBATIM

does not try to use stemming for query expansion but searches the query terms verbatim.

NOSTOPWORDS (deprecated)

ignores any defined stop words in full text searches. Note: this option is deprecated as of Redis 8.0.

WITHSCORES

also returns the relative internal score of each document. This can be used to merge results from multiple instances.

WITHPAYLOADS

retrieves optional document payloads. See [`FT.CREATE`](). The payloads follow the document id and, if `WITHSCORES` is set, the scores.

WITHSORTKEYS

returns the value of the sorting key, right after the id and score and/or payload, if requested. This is usually not needed, and exists for distributed search coordination purposes. This option is relevant only if used in conjunction with `SORTBY`.

FILTER numeric_attribute min max

limits results to those having numeric values ranging between `min` and `max`, if numeric_attribute is defined as a numeric attribute in [`FT.CREATE`]().
  `min` and `max` follow [`ZRANGE`]() syntax, and can be `-inf`, `+inf`, and use `(` for exclusive ranges. Multiple numeric filters for different attributes are supported in one query.
**Deprecated since v2.10**: [Query dialect 2]() explains the query syntax for numeric fields that replaces this argument.

GEOFILTER {geo_attribute} {lon} {lat} {radius} m|km|mi|ft

filter the results to a given `radius` from `lon` and `lat`. Radius is given as a number and units. See [`GEORADIUS`]() for more details.
**Deprecated since v2.6**: [Query dialect 3]() explains the query syntax for geospatial fields that replaces this argument.

INKEYS {num} {attribute} ...

limits the result to a given set of keys specified in the list. The first argument must be the length of the list and greater than zero. Non-existent keys are ignored, unless all the keys are non-existent.

INFIELDS {num} {attribute} ...

filters the results to those appearing only in specific attributes of the document, like `title` or `URL`. You must include `num`, which is the number of attributes you're filtering by. For example, if you request `title` and `URL`, then `num` is 2.

RETURN {num} {identifier} AS {property} ...

limits the attributes returned from the document. `num` is the number of attributes following the keyword. If `num` is 0, it acts like `NOCONTENT`.
  `identifier` is either an attribute name (for hashes and JSON) or a JSON Path expression (for JSON).
  `property` is an optional name used in the result. If not provided, the `identifier` is used in the result.

SUMMARIZE ...

returns only the sections of the attribute that contain the matched text. See [Highlighting]() for more information.

HIGHLIGHT ...

formats occurrences of matched text. See [Highlighting]() for more information.

SLOP {slop}

is the number of intermediate terms allowed to appear between the terms of the query.
Suppose you're searching for a phrase _hello world_.
If some terms appear in-between _hello_ and _world_, a `SLOP` greater than `0` allows for these text attributes to match.
By default, there is no `SLOP` constraint.

INORDER

requires the terms in the document to have the same order as the terms in the query, regardless of the offsets between them. Typically used in conjunction with `SLOP`. Default is `false`.

LANGUAGE {language}

use a stemmer for the supplied language during search for query expansion. If querying documents in Chinese, set to `chinese` to
  properly tokenize the query terms. Defaults to English. If an unsupported language is sent, the command returns an error.
  See [`FT.CREATE`]() for the list of languages. If `LANGUAGE` was specified as part of index
  creation, it doesn't need to specified with `FT.SEARCH`.

EXPANDER {expander}

uses a custom query expander instead of the stemmer. See [Extensions]().

SCORER {scorer}

uses a [built-in]() or a [user-provided]() scoring function.

EXPLAINSCORE

returns a textual description of how the scores were calculated. Using this option requires `WITHSCORES`.

PAYLOAD {payload}

adds an arbitrary, binary safe payload that is exposed to custom scoring functions. See [Extensions]().

SORTBY {attribute} [ASC|DESC] [WITHCOUNT]

orders the results by the value of this attribute. This applies to both text and numeric attributes. Attributes needed for `SORTBY` should be declared as `SORTABLE` in the index, in order to be available with very low latency. Note that this adds memory overhead.

**Sorting Optimizations**: performance is optimized for sorting operations on `DIALECT 4` in different scenarios:
  - Skip Sorter - applied when there is no sort of any kind. The query can return after it reaches the `LIMIT` requested results.
  - Partial Range - applied when there is a `SORTBY` clause over a numeric field, with no filter or filter by the same numeric field, the query iterate on a range large enough to satisfy the `LIMIT` requested results.
  - Hybrid - applied when there is a `SORTBY` clause over a numeric field and another non-numeric filter. Some results will get filtered, and the initial range may not be large enough. The iterator is then rewinding with the following ranges, and an additional iteration takes place to collect the `LIMIT` requested results.
  - No optimization - If there is a sort by score or by non-numeric field, there is no other option but to retrieve all results and compare their values.

**Counts behavior**: optional `WITHCOUNT` argument returns accurate counts for the query results with sorting. This operation processes all results in order to get an accurate count, being less performant than the optimized option (default behavior on `DIALECT 4`)

You can also use `WITHOUTCOUNT` in place of `DIALECT 4` when used with either `FT.SEARCH` or `FT.AGGREGATE`.

LIMIT first num

limits the results to the offset and number of results given. Note that the offset is zero-indexed. The default is 0 10, which returns 10 items starting from the first result. You can use `LIMIT 0 0` to count the number of documents in the result set without actually returning them.

**`LIMIT` behavior**:  If you use the `LIMIT` option without sorting, the results returned are non-deterministic, which means that subsequent queries may return duplicated or missing values. Add `SORTBY` with a unique field, or use `FT.AGGREGATE` with the `WITHCURSOR` option to ensure deterministic result set paging.

TIMEOUT {milliseconds}

overrides the timeout parameter of the module.

PARAMS {nargs} {name} {value}

defines one or more value parameters. Each parameter has a name and a value.

You can reference parameters in the `query` by a `$`, followed by the parameter name, for example, `$user`. Each such reference in the search query to a parameter name is substituted by the corresponding parameter value. For example, with parameter definition `PARAMS 4 lon 29.69465 lat 34.95126`, the expression `@loc:[$lon $lat 10 km]` is evaluated to `@loc:[29.69465 34.95126 10 km]`. You cannot reference parameters in the query string where concrete values are not allowed, such as in field names, for example, `@loc`. To use `PARAMS`, set
[`DIALECT`]()
to `2` or greater than `2` (this requires [RediSearch v2.4](https://github.com/RediSearch/RediSearch/releases/tag/v2.4.3) or above).

DIALECT {dialect_version}

selects the dialect version under which to execute the query. If not specified, the query will execute under the default dialect version set during module initial loading or via [`FT.CONFIG SET`]() command. See [Query dialects]() for more information.

title: Return

text:
FT.SEARCH returns an array reply, where the first element is an integer reply of the total number of results, and then array reply pairs of document ids, and array replies of attribute/value pairs.

- If `NOCONTENT` is given, an array is returned where the first element is the total number of results, and the rest of the members are document ids.
- If a relevant key expires or is updated while a query is running, an attempt to load the updated key's value will return a null array. However, the key is still counted in the total number of results.

title: Return multiple values

text:
When the index is defined `ON JSON`, a reply for a single attribute or a single JSONPath may return multiple values when the JSONPath matches multiple values, or when the JSONPath matches an array.

Prior to RediSearch v2.6, only the first of the matched values was returned.
Starting with RediSearch v2.6, all values are returned, wrapped with a top-level array.

In order to maintain backward compatibility, the default behavior with RediSearch v2.6 is to return only the first value.

To return all the values, use `DIALECT` 3 (or greater, when available).

The `DIALECT` can be specified as a parameter in the FT.SEARCH command. If it is not specified, the `DEFAULT_DIALECT` is used, which can be set using [`FT.CONFIG SET`]() or by passing it as an argument to the `redisearch` module when it is loaded.

For example, with the following document and index:

[code example]
Notice the different replies, with and without `DIALECT 3`:

[code example]

title: Complexity

role: performance

text:
FT.SEARCH complexity is O(n) for single word queries. `n` is the number of the results in the result set. Finding all the documents that have a specific term is O(1), however, a scan on all those documents is needed to load the documents data from redis hashes and return them.

The time complexity for more complex queries varies, but in general it's proportional to the number of words, the number of intersection points between them and the number of results in the result set.

title: Examples

text:
Search for a term in every text attribute

Search for the term "wizard" in every TEXT attribute of an index containing book data.

127.0.0.1:6379> FT.SEARCH books-idx "wizard"

Search for a term in title attribute

Search for the term _dogs_ in the `title` attribute.

127.0.0.1:6379> FT.SEARCH books-idx "@title:dogs"

Search for books from specific years

Search for books published in 2020 or 2021.

127.0.0.1:6379> FT.SEARCH books-idx "@published_at:[2020 2021]"

Search for a restaurant by distance from longitude/latitude

Search for Chinese restaurants within 5 kilometers of longitude -122.41, latitude 37.77 (San Francisco).

127.0.0.1:6379> FT.SEARCH restaurants-idx "chinese @location:[-122.41 37.77 5 km]"

Search for a book by terms but boost specific term

Search for the term _dogs_ or _cats_ in the `title` attribute, but give matches of _dogs_ a higher relevance score (also known as _boosting_).

127.0.0.1:6379> FT.SEARCH books-idx "(@title:dogs | @title:cats) | (@title:dogs) => { $weight: 5.0; }"

Search for a book by a term and EXPLAINSCORE

Search for books with _dogs_ in any TEXT attribute in the index and request an explanation of scoring for each result.

127.0.0.1:6379> FT.SEARCH books-idx "dogs" WITHSCORES EXPLAINSCORE

Search for a book by a term and TAG

Search for books with _space_ in the title that have `science` in the TAG attribute `categories`.

127.0.0.1:6379> FT.SEARCH books-idx "@title:space @categories:{science}"

Search for a book by a term but limit the number

Search for books with _Python_ in any `TEXT` attribute, returning 10 results starting with the 11th result in the entire result set (the offset parameter is zero-based), and return only the `title` attribute for each result.

127.0.0.1:6379> FT.SEARCH books-idx "python" LIMIT 10 10 RETURN 1 title

Search for a book by a term and price

Search for books with _Python_ in any `TEXT` attribute, returning the price stored in the original JSON document.

127.0.0.1:6379> FT.SEARCH books-idx "python" RETURN 3 $.book.price AS price

Search for a book by title and distance

Search for books with semantically similar title to _Planet Earth_. Return top 10 results sorted by distance.

127.0.0.1:6379> FT.SEARCH books-idx "*=>[KNN 10 @title_embedding $query_vec AS title_score]" PARAMS 2 query_vec <"Planet Earth" embedding BLOB> SORTBY title_score DIALECT 2

Vector search with cluster optimization

Search for books with titles that are semantically similar to _Planet Earth_ using cluster optimization. Each shard retrieves 60% of the requested results for improved performance in Redis cluster environments. See the [query attributes]() reference page for more information.

127.0.0.1:6379> FT.SEARCH books-idx "*=>[KNN 100 @title_embedding $query_vec]=>{$SHARD_K_RATIO: 0.6; $YIELD_DISTANCE_AS: title_score}" PARAMS 2 query_vec <"Planet Earth" embedding BLOB> SORTBY title_score DIALECT 2

Search for a phrase using SLOP

Search for a phrase _hello world_.
First, create an index.

127.0.0.1:6379> FT.CREATE memes SCHEMA phrase TEXT
OK

Add variations of the phrase _hello world_.

127.0.0.1:6379> HSET s1 phrase "hello world"
(integer) 1
127.0.0.1:6379> HSET s2 phrase "hello simple world"
(integer) 1
127.0.0.1:6379> HSET s3 phrase "hello somewhat less simple world"
(integer) 1
127.0.0.1:6379> HSET s4 phrase "hello complicated yet encouraging problem solving world"
(integer) 1
127.0.0.1:6379> HSET s5 phrase "hello complicated yet amazingly encouraging problem solving world"
(integer) 1

Then, search for the phrase _hello world_. The result returns all documents that contain the phrase.

127.0.0.1:6379> FT.SEARCH memes '@phrase:(hello world)' NOCONTENT
1) (integer) 5
2) "s1"
3) "s2"
4) "s3"
5) "s4"
6) "s5"

Now, return all documents that have one of fewer words between _hello_ and _world_.

127.0.0.1:6379> FT.SEARCH memes '@phrase:(hello world)' NOCONTENT SLOP 1
1) (integer) 2
2) "s1"
3) "s2"

Now, return all documents with three or fewer words between _hello_ and _world_.

127.0.0.1:6379> FT.SEARCH memes '@phrase:(hello world)' NOCONTENT SLOP 3
1) (integer) 3
2) "s1"
3) "s2"
4) "s3"

`s5` needs a higher `SLOP` to match, `SLOP 6` or higher, to be exact. See what happens when you set `SLOP` to `5`.

127.0.0.1:6379> FT.SEARCH memes '@phrase:(hello world)' NOCONTENT SLOP 5
1) (integer) 4
2) "s1"
3) "s2"
4) "s3"
5) "s4"

If you add additional terms (and stemming), you get these results.

127.0.0.1:6379> FT.SEARCH memes '@phrase:(hello amazing world)' NOCONTENT
1) (integer) 1
2) "s5"

127.0.0.1:6379> FT.SEARCH memes '@phrase:(hello encouraged world)' NOCONTENT SLOP 5
1) (integer) 2
2) "s4"
3) "s5"

127.0.0.1:6379> FT.SEARCH memes '@phrase:(hello encouraged world)' NOCONTENT SLOP 4
1) (integer) 1
2) "s4"

If you swap the terms, you can still retrieve the correct phrase.

127.0.0.1:6379> FT.SEARCH memes '@phrase:(amazing hello world)' NOCONTENT
1) (integer) 1
2) "s5"

But, if you use `INORDER`, you get zero results.

127.0.0.1:6379> FT.SEARCH memes '@phrase:(amazing hello world)' NOCONTENT INORDER
1) (integer) 0

Likewise, if you use a query attribute `$inorder` set to `true`, `s5` is not retrieved.

127.0.0.1:6379> FT.SEARCH memes '@phrase:(amazing hello world)=>{$inorder: true;}' NOCONTENT
1) (integer) 0

To sum up, the `INORDER` argument or `$inorder` query attribute require the query terms to match terms with similar ordering.

Polygon Search with WITHIN, CONTAINS, INTERSECTS, and DISJOINT operators

Query for polygons which:

- contain a given geoshape
- are within a given geoshape
- intersect with a given geoshape
- are disjoint (nothing in common) with a given shape

`INTERSECTS` and `DISJOINT` were introduced in v2.10.

First, create an index using `GEOSHAPE` type with a `FLAT` coordinate system:

127.0.0.1:6379> FT.CREATE idx SCHEMA geom GEOSHAPE FLAT
OK

Adding a couple of geometries using [`HSET`]():

127.0.0.1:6379> HSET small geom 'POLYGON((1 1, 1 100, 100 100, 100 1, 1 1))'
(integer) 1
127.0.0.1:6379> HSET large geom 'POLYGON((1 1, 1 200, 200 200, 200 1, 1 1))'
(integer) 1

Query with `WITHIN` operator:

127.0.0.1:6379> FT.SEARCH idx '@geom:[WITHIN $poly]' PARAMS 2 poly 'POLYGON((0 0, 0 150, 150 150, 150 0, 0 0))' DIALECT 3

1) (integer) 1
2) "small"
3) 1) "geom"
   2) "POLYGON((1 1, 1 100, 100 100, 100 1, 1 1))"

Query with `CONTAINS` operator:

127.0.0.1:6379> FT.SEARCH idx '@geom:[CONTAINS $poly]' PARAMS 2 poly 'POLYGON((2 2, 2 50, 50 50, 50 2, 2 2))' DIALECT 3

1) (integer) 2
2) "small"
3) 1) "geom"
   2) "POLYGON((1 1, 1 100, 100 100, 100 1, 1 1))"
4) "large"
5) 1) "geom"
   2) "POLYGON((1 1, 1 200, 200 200, 200 1, 1 1))"

title: Return information

text:
**RESP2:**

One of the following:
* [Array]() with the first element being the total number of results, followed by document IDs and their field-value pairs as [arrays]().
* [Simple error reply]() in these cases: no such index, syntax error in query.

**RESP3:**

One of the following:
* [Map]() with the following fields:
    - `total_results`: [Integer]() - total number of results
    - `results`: [Array]() of [maps]() containing document information
    - `attributes`: [Array]() of attribute names
    - `format`: [Simple string]() - result format
    - `warning`: [Array]() of warning messages
* [Simple error reply]() in these cases: no such index, syntax error in query.

title: See also

text: [`FT.CREATE`]() | [`FT.AGGREGATE`]()

title: Related topics

text:
- [Extensions]()
- [Highlighting]()
- [Key and field expiration behavior]()
- [Query syntax]()
- [RediSearch]()

code:
127.0.0.1:6379> JSON.SET doc:1 $ '[{"arr": [1, 2, 3]}, {"val": "hello"}, {"val": "world"}]'
OK
127.0.0.1:6379> FT.CREATE idx ON JSON PREFIX 1 doc: SCHEMA $..arr AS arr NUMERIC $..val AS val TEXT
OK

section_id: return-multiple-values


title: FT.SPELLCHECK

summary: Performs spelling correction on a query, returning suggestions for misspelled terms

title: Overview

text:
Perform spelling correction on a query, returning suggestions for misspelled terms

[Examples](#examples)

title: Required arguments

text:
index

is index with the indexed terms.

query

is search query.

See [Spellchecking]() for more details.

title: Optional arguments

text:
TERMS

specifies an inclusion (`INCLUDE`) or exclusion (`EXCLUDE`) of a custom dictionary. To learn more about managing custom dictionaries, see [`FT.DICTADD`](), [`FT.DICTDEL`](), and [`FT.DICTDUMP`]().

You can specify multiple inclusion and exclusion `TERMS`.

DISTANCE

is maximum Levenshtein distance for spelling suggestions (default: 1, max: 4).

DIALECT {dialect_version}

selects the dialect version under which to execute the query. If not specified, the query will execute under the default dialect version set during module initial loading or via [`FT.CONFIG SET`]() command.

title: Return

text:
FT.SPELLCHECK returns an array reply, in which each element represents a misspelled term from the query. The misspelled terms are ordered by their order of appearance in the query.
Each misspelled term, in turn, is a 3-element array consisting of the constant string `TERM`, the term itself and an array of suggestions for spelling corrections.
Each element in the spelling corrections array consists of the score of the suggestion and the suggestion itself. The suggestions array, per misspelled term, is ordered in descending order by score.
The score is calculated by dividing the number of documents in which the suggested term exists by the total number of documents in the index. Results can be normalized by dividing scores by the highest score.

title: Examples

text:
Perform spelling correction on a query

127.0.0.1:6379> FT.SPELLCHECK idx held DISTANCE 2
1) 1) "TERM"
   2) "held"
   3) 1) 1) "0.66666666666666663"
         2) "hello"
      2) 1) "0.33333333333333331"
         2) "help"

text:
| Redis
Software | Redis Cloud
Flexible & Annual | Redis Cloud
Free & Fixed | Notes |
|:----------------------|:-----------------|:-----------------|:------|
| ✅ Supported | ✅ Supported | ✅ Supported</nobr> |  |

title: Return information

text:
**RESP2:**

One of the following:
* [Array]() of spell check results for each term.
* [Simple error reply]() in these cases: no such index.

**RESP3:**

One of the following:
* [Map]() with a `results` key containing spell check results for each term.
* [Simple error reply]() in these cases: no such index.

title: See also

text: [`FT.CONFIG SET`]() | [`FT.DICTADD`]() | [`FT.DICTDEL`]() | [`FT.DICTDUMP`]()

title: Related topics

text:
- [Spellchecking]()
- [RediSearch]()


title: FT.SUGADD

summary: Adds a suggestion string to an auto-complete suggestion dictionary

title: Overview

text:
Add a suggestion string to an auto-complete suggestion dictionary

[Examples](#examples)

title: Required arguments

text:
key

is suggestion dictionary key.

string

is suggestion string to index.

score

is floating point number of the suggestion string's weight.

The auto-complete suggestion dictionary is disconnected from the index definitions and leaves creating and updating suggestions dictionaries to the user.

title: Optional arguments

text:
INCR

increments the existing entry of the suggestion by the given score, instead of replacing the score. This is useful for updating the dictionary based on user queries in real time.

PAYLOAD {payload}

saves an extra payload with the suggestion, that can be fetched by adding the `WITHPAYLOADS` argument to [`FT.SUGGET`]().

title: Examples

text:
Add a suggestion string to an auto-complete suggestion dictionary

127.0.0.1:6379> FT.SUGADD sug "hello world" 1
(integer) 3

text:
| Redis
Software | Redis
Cloud | Notes |
|:----------------------|:-----------------|:------|
| ✅ Standard
<nobr>❌ Active-Active</nobr> | ❌ Standard
<nobr>❌ Active-Active</nobr> | Not supported on clustered databases. |

title: Return information

text:
**RESP2:**

[Integer reply](): number of elements added to the suggestion dictionary.

**RESP3:**

[Integer reply](): number of elements added to the suggestion dictionary.

title: See also

text: [`FT.SUGGET`]() | [`FT.SUGDEL`]() | [`FT.SUGLEN`]()

title: Related topics

text: [RediSearch]()


title: FT.SUGDEL

summary: Deletes a string from a suggestion index

title: Overview

text:
Delete a string from a suggestion index

[Examples](#examples)

title: Required arguments

text:
key

is suggestion dictionary key.

string

is suggestion string to index.

title: Examples

text:
Delete a string from a suggestion index

127.0.0.1:6379> FT.SUGDEL sug "hello"
(integer) 1
127.0.0.1:6379> FT.SUGDEL sug "hello"
(integer) 0

title: Return information

text:
**RESP2:**

[Integer reply](): 1 if the suggestion was deleted, 0 if it was not found.

**RESP3:**

[Integer reply](): 1 if the suggestion was deleted, 0 if it was not found.

title: See also

text: [`FT.SUGGET`]() | [`FT.SUGADD`]() | [`FT.SUGLEN`]()

title: Related topics

text: [RediSearch]()


title: FT.SUGGET

summary: Gets completion suggestions for a prefix

title: Overview

text: Get completion suggestions for a prefix

title: Required arguments

text:
key

is suggestion dictionary key.

prefix

is prefix to complete on.

title: Optional arguments

text:
FUZZY

performs a fuzzy prefix search, including prefixes at Levenshtein distance of 1 from the prefix sent.

MAX num

limits the results to a maximum of `num` (default: 5).

WITHSCORES

also returns the score of each suggestion. This can be used to merge results from multiple instances.

WITHPAYLOADS

returns optional payloads saved along with the suggestions. If no payload is present for an entry, it returns a null reply.

title: Return

text: FT.SUGGET returns an array reply, which is a list of the top suggestions matching the prefix, optionally with score after each entry.

title: Example

text:
Get completion suggestions for a prefix

127.0.0.1:6379> FT.SUGGET sug hell FUZZY MAX 3 WITHSCORES
1) "hell"
2) "2147483648"
3) "hello"
4) "0.70710676908493042"

title: Return information

text:
**RESP2:**

[Array]() of the top suggestions matching the prefix, optionally with a score after each entry.

**RESP3:**

[Array]() of the top suggestions matching the prefix, optionally with a score after each entry.

title: See also

text: [`FT.SUGADD`]() | [`FT.SUGDEL`]() | [`FT.SUGLEN`]()

title: Related topics

text: [RediSearch]()


title: FT.SUGLEN

summary: Gets the size of an auto-complete suggestion dictionary

title: Overview

text:
Get the size of an auto-complete suggestion dictionary

[Examples](#examples)

title: Required arguments

text:
key

is suggestion dictionary key.

title: Examples

text:
Get the size of an auto-complete suggestion dictionary

127.0.0.1:6379> FT.SUGLEN sug
(integer) 2

title: Return information

text:
**RESP2:**

[Integer reply](): number of suggestions in the dictionary.

**RESP3:**

[Integer reply](): number of suggestions in the dictionary.

title: See also

text: [`FT.SUGADD`]() | [`FT.SUGDEL`]() | [`FT.SUGGET`]()

title: Related topics

text: [RediSearch]()


title: FT.SYNDUMP

summary: Dumps the contents of a synonym group

title: Overview

text:
Dump the contents of a synonym group

[Examples](#examples)

title: Required arguments

text:
index

is index name.

Use FT.SYNDUMP to dump the synonyms data structure. This command returns a list of synonym terms and their synonym group ids.

title: Examples

text:
Return the contents of a synonym group

127.0.0.1:6379> FT.SYNDUMP idx
1) "shalom"
2) 1) "synonym1"
   2) "synonym2"
3) "hi"
4) 1) "synonym1"
5) "hello"
6) 1) "synonym1"

text:
| Redis
Software | Redis Cloud
Flexible & Annual | Redis Cloud
Free & Fixed | Notes |
|:----------------------|:-----------------|:-----------------|:------|
| ✅ Supported | ✅ Supported | ✅ Supported</nobr> |  |

title: Return information

text:
**RESP2:**

One of the following:
* [Array]() of synonym terms and their associated synonym groups.
* [Simple error reply]() in these cases: no such index.

**RESP3:**

One of the following:
* [Map]() where keys are synonym terms and values are arrays of their associated synonym groups.
* [Simple error reply]() in these cases: no such index.

title: See also

text: [`FT.SYNUPDATE`]()

title: Related topics

text: [RediSearch]()


title: FT.SYNUPDATE

summary: Creates or updates a synonym group with additional terms

title: Overview

text:
Update a synonym group

[Examples](#examples)

title: Required arguments

text:
index

is index name.

synonym_group_id

is synonym group to return.

Use FT.SYNUPDATE to create or update a synonym group with additional terms. The command triggers a scan of all documents.

title: Optional parameters

text:
SKIPINITIALSCAN

does not scan and index, and only documents that are indexed after the update are affected.

title: Examples

text:
Update a synonym group

127.0.0.1:6379> FT.SYNUPDATE idx synonym hello hi shalom
OK

127.0.0.1:6379> FT.SYNUPDATE idx synonym SKIPINITIALSCAN hello hi shalom
OK

title: Return information

text:
**RESP2:**

One of the following:
* [Simple string reply](): `OK` if executed correctly.
* [Simple error reply]() in these cases: no such index.

**RESP3:**

One of the following:
* [Simple string reply](): `OK` if executed correctly.
* [Simple error reply]() in these cases: no such index.

title: See also

text: [`FT.SYNDUMP`]()

title: Related topics

text: [RediSearch]()


title: FT.TAGVALS

summary: Returns the distinct tags indexed in a Tag field

title: Overview

text:
Return a distinct set of values indexed in a Tag field

[Examples](#examples)

title: Required arguments

text:
index

is full-text index name. You must first create the index using [`FT.CREATE`]().

field_name

is name of a Tag file defined in the schema.

Use FT.TAGVALS if your tag indexes things like cities, categories, and so on.

title: Limitations

role: limits

text:
FT.TAGVALS provides no paging or sorting, and the tags are not alphabetically sorted. FT.TAGVALS only operates on [tag fields]().
The returned strings are lowercase with whitespaces removed, but otherwise unchanged.

title: Examples

text:
Return a set of values indexed in a Tag field

127.0.0.1:6379> FT.TAGVALS idx myTag
1) "Hello"
2) "World"

title: Return information

text:
**RESP2:**

One of the following:
* [Array]() of distinct tag values as [bulk strings]().
* [Simple error reply]() in these cases: no such index, not a tag field.

**RESP3:**

One of the following:
* [Set]() of distinct tag values as [bulk strings]().
* [Simple error reply]() in these cases: no such index, not a tag field.

title: See also

text: [`FT.CREATE`]()

title: Related topics

text:
- [Tag fields]()
- [RediSearch]()


title: FUNCTION

summary: A container for function commands.

title: Content

text:
This is a container command for function commands.

To see the list of available commands you can call [`FUNCTION HELP`]().


title: FUNCTION DELETE

summary: Deletes a library and its functions.

title: Overview

text:
Delete a library and all its functions.

This command deletes the library called _library-name_ and all functions in it.
If the library doesn't exist, the server returns an error.

For more information please refer to [Introduction to Redis Functions]().

title: Examples

text: [code example]

text:
| Redis
Software | Redis
Cloud | Notes |
|:----------------------|:-----------------|:------|
| ✅ Standard
<nobr>✅ Active-Active</nobr> | ✅ Standard
<nobr>✅ Active-Active</nobr> |  |

title: Return information

text:
**RESP2:**

[Simple string reply](../../develop/reference/protocol-spec#simple-strings): `OK`.

**RESP3:**

[Simple string reply](../../develop/reference/protocol-spec#simple-strings): `OK`.

code:
redis> FUNCTION LOAD "#!lua name=mylib \n redis.register_function('myfunc', function(keys, args) return 'hello' end)"
"mylib"
redis> FCALL myfunc 0
"hello"
redis> FUNCTION DELETE mylib
OK
redis> FCALL myfunc 0
(error) ERR Function not found


title: FUNCTION DUMP

summary: Dumps all libraries into a serialized binary payload.

title: Overview

text:
Return the serialized payload of loaded libraries.
You can restore the serialized payload later with the [`FUNCTION RESTORE`]() command.

For more information please refer to [Introduction to Redis Functions]().

title: Examples

text:
The following example shows how to dump loaded libraries using `FUNCTION DUMP` and then it calls [`FUNCTION FLUSH`]() deletes all the libraries.
Then, it restores the original libraries from the serialized payload with [`FUNCTION RESTORE`]().

[code example]

title: Return information

text:
**RESP2:**

[Bulk string reply](../../develop/reference/protocol-spec#bulk-strings): the serialized payload

**RESP3:**

[Bulk string reply](../../develop/reference/protocol-spec#bulk-strings): the serialized payload

code:
redis> FUNCTION LOAD "#!lua name=mylib \n redis.register_function('myfunc', function(keys, args) return args[1] end)"
"mylib"
redis> FUNCTION DUMP
"\xf5\xc3@X@]\x1f#!lua name=mylib \n redis.registe\rr_function('my@\x0b\x02', @\x06`\x12\nkeys, args) 6\x03turn`\x0c\a[1] end)\x0c\x00\xba\x98\xc2\xa2\x13\x0e$\a"
redis> FUNCTION FLUSH
OK
redis> FUNCTION RESTORE "\xf5\xc3@X@]\x1f#!lua name=mylib \n redis.registe\rr_function('my@\x0b\x02', @\x06`\x12\nkeys, args) 6\x03turn`\x0c\a[1] end)\x0c\x00\xba\x98\xc2\xa2\x13\x0e$\a"
OK
redis> FUNCTION LIST
1) 1) "library_name"
   2) "mylib"
   3) "engine"
   4) "LUA"
   5) "functions"
   6) 1) 1) "name"
         2) "myfunc"
         3) "description"
         4) (nil)
         5) "flags"
         6) (empty array)


title: FUNCTION FLUSH

summary: Deletes all libraries and functions.

title: Overview

text:
Deletes all the libraries.

Unless called with the optional mode argument, the `lazyfree-lazy-user-flush` configuration directive sets the effective behavior. Valid modes are:

* `ASYNC`: Asynchronously flush the libraries.
* `SYNC`: Synchronously flush the libraries.

For more information please refer to [Introduction to Redis Functions]().

title: Return information


title: FUNCTION HELP

summary: Returns helpful text about the different subcommands.

title: Overview

text: The `FUNCTION HELP` command returns a helpful text describing the different subcommands.

title: Return information

text:
**RESP2:**

[Array reply](../../develop/reference/protocol-spec#arrays): a list of sub-commands and their descriptions

**RESP3:**

[Array reply](../../develop/reference/protocol-spec#arrays): a list of sub-commands and their descriptions.


title: FUNCTION KILL

summary: Terminates a function during execution.

title: Overview

text:
Kill a function that is currently executing.

The `FUNCTION KILL` command can be used only on functions that did not modify the dataset during their execution (since stopping a read-only function does not violate the scripting engine's guaranteed atomicity).

For more information please refer to [Introduction to Redis Functions]().

title: Return information


title: FUNCTION LIST

summary: Returns information about all libraries.

title: Overview

text:
Return information about the functions and libraries.

You can use the optional `LIBRARYNAME` argument to specify a pattern for matching library names.
The optional `WITHCODE` modifier will cause the server to include the libraries source implementation in the reply.

The following information is provided for each of the libraries in the response:

* **library_name:** the name of the library.
* **engine:** the engine of the library.
* **functions:** the list of functions in the library.
  Each function has the following fields:
  * **name:** the name of the function.
  * **description:** the function's description.
  * **flags:** an array of [function flags]().
* **library_code:** the library's source code (when given the `WITHCODE` modifier).

For more information please refer to [Introduction to Redis Functions]().

title: Return information

text:
**RESP2:**

[Array reply](../../develop/reference/protocol-spec#arrays): information about functions and libraries.

**RESP3:**

[Array reply](../../develop/reference/protocol-spec#arrays): information about functions and libraries.


title: FUNCTION LOAD

summary: Creates a library.

title: Overview

text:
Load a library to Redis.

The command's gets a single mandatory parameter which is the source code that implements the library.
The library payload must start with Shebang statement that provides a metadata about the library (like the engine to use and the library name).
Shebang format: `#!<engine name> name=<library name>`. Currently engine name must be `lua`.

For the Lua engine, the implementation should declare one or more entry points to the library with the [`redis.register_function()` API]().
Once loaded, you can call the functions in the library with the [`FCALL`]() (or [`FCALL_RO`]() when applicable) command.

When attempting to load a library with a name that already exists, the Redis server returns an error.
The `REPLACE` modifier changes this behavior and overwrites the existing library with the new contents.

The command will return an error in the following circumstances:

* An invalid _engine-name_ was provided.
* The library's name already exists without the `REPLACE` modifier.
* A function in the library is created with a name that already exists in another library (even when `REPLACE` is specified).
* The engine failed in creating the library's functions (due to a compilation error, for example).
* No functions were declared by the library.

For more information please refer to [Introduction to Redis Functions]().

title: Examples

text:
The following example will create a library named `mylib` with a single function, `myfunc`, that returns the first argument it gets.

[code example]

title: Return information

text:
**RESP2:**

[Bulk string reply](../../develop/reference/protocol-spec#bulk-strings): the library name that was loaded.

**RESP3:**

[Bulk string reply](../../develop/reference/protocol-spec#bulk-strings): the library name that was loaded.

code:
redis> FUNCTION LOAD "#!lua name=mylib \n redis.register_function('myfunc', function(keys, args) return args[1] end)"
mylib
redis> FCALL myfunc 0 hello
"hello"


title: FUNCTION RESTORE

summary: Restores all libraries from a payload.

title: Overview

text:
Restore libraries from the serialized payload.

You can use the optional _policy_ argument to provide a policy for handling existing libraries.
The following policies are allowed:

* **APPEND:** appends the restored libraries to the existing libraries and aborts on collision.
  This is the default policy.
* **FLUSH:** deletes all existing libraries before restoring the payload.
* **REPLACE:** appends the restored libraries to the existing libraries, replacing any existing ones in case of name collisions. Note that this policy doesn't prevent function name collisions, only libraries.

For more information please refer to [Introduction to Redis Functions]().

title: Return information


title: FUNCTION STATS

summary: Returns information about a function during execution.

title: Overview

text:
Return information about the function that's currently running and information about the available execution engines.

The reply is map with two keys:

1. `running_script`: information about the running script.
  If there's no in-flight function, the server replies with a _nil_.
  Otherwise, this is a map with the following keys:
  * **name:** the name of the function.
  * **command:** the command and arguments used for invoking the function.
  * **duration_ms:** the function's runtime duration in milliseconds.
2. `engines`: this is a map of maps. Each entry in the map represent a single engine.
   Engine map contains statistics about the engine like number of functions and number of libraries.

You can use this command to inspect the invocation of a long-running function and decide whether kill it with the [`FUNCTION KILL`]() command.

For more information please refer to [Introduction to Redis Functions]().

title: Return information

text:
**RESP2:**

[Array reply](../../develop/reference/protocol-spec#arrays): information about the function that's currently running and information about the available execution engines.

**RESP3:**

[Map reply](../../develop/reference/protocol-spec#maps): information about the function that's currently running and information about the available execution engines.


title: GEOADD

summary: Adds one or more members to a geospatial index. The key is created if it doesn't exist.

title: Overview

text:
Adds the specified geospatial items (longitude, latitude, name) to the specified key. Data is stored into the key as a sorted set, in a way that makes it possible to query the items with the [`GEOSEARCH`]() command.

The command takes arguments in the standard format x,y so the longitude must be specified before the latitude. There are limits to the coordinates that can be indexed: areas very near to the poles are not indexable.

The exact limits, as specified by EPSG:900913 / EPSG:3785 / OSGEO:41001 are the following:

* Valid longitudes are from -180 to 180 degrees.
* Valid latitudes are from -85.05112878 to 85.05112878 degrees.

The command will report an error when the user attempts to index coordinates outside the specified ranges.

**Note:** there is no **GEODEL** command because you can use [`ZREM`]() to remove elements. The Geo index structure is just a sorted set.

title: GEOADD options

text:
`GEOADD` also provides the following options:

* **XX**: Only update elements that already exist. Never add elements.
* **NX**: Don't update already existing elements. Always add new elements.
* **CH**: Modify the return value from the number of new elements added, to the total number of elements changed (CH is an abbreviation of *changed*). Changed elements are **new elements added** and elements already existing for which **the coordinates was updated**. So elements specified in the command line having the same score as they had in the past are not counted. Note: normally, the return value of `GEOADD` only counts the number of new elements added.

Note: The **XX** and **NX** options are mutually exclusive.

How does it work?
---

The way the sorted set is populated is using a technique called
[Geohash](https://en.wikipedia.org/wiki/Geohash). Latitude and Longitude
bits are interleaved to form a unique 52-bit integer. We know
that a sorted set double score can represent a 52-bit integer without losing
precision.

This format allows for bounding box and radius querying by checking the 1+8 areas needed to cover the whole shape and discarding elements outside it. The areas are checked by calculating the range of the box covered, removing enough bits from the less significant part of the sorted set score, and computing the score range to query in the sorted set for each area.

What Earth model does it use?
---

The model assumes that the Earth is a sphere since it uses the Haversine formula to calculate distance. This formula is only an approximation when applied to the Earth, which is not a perfect sphere.
The introduced errors are not an issue when used, for example, by social networks and similar applications requiring this type of querying.
However, in the worst case, the error may be up to 0.5%, so you may want to consider other systems for error-critical applications.

title: Examples

text:
GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
GEODIST Sicily Palermo Catania
GEORADIUS Sicily 15 37 100 km
GEORADIUS Sicily 15 37 200 km

text:
| Redis
Software | Redis
Cloud | Notes |
|:----------------------|:-----------------|:------|
| ✅ Standard
<nobr>✅ Active-Active</nobr> | ✅ Standard
<nobr>✅ Active-Active</nobr> |  |

title: Return information

text:
**RESP2:**

[Integer reply](../../develop/reference/protocol-spec#integers): When used without optional arguments, the number of elements added to the sorted set (excluding score updates).  If the CH option is specified, the number of elements that were changed (added or updated).

**RESP3:**

[Integer reply](../../develop/reference/protocol-spec#integers): When used without optional arguments, the number of elements added to the sorted set (excluding score updates).  If the CH option is specified, the number of elements that were changed (added or updated).


title: GEODIST

summary: Returns the distance between two members of a geospatial index.

title: Overview

text:
Return the distance between two members in the geospatial index represented by the sorted set.

Given a sorted set representing a geospatial index, populated using the [`GEOADD`]() command, the command returns the distance between the two specified members in the specified unit.

If one or both the members are missing, the command returns NULL.

The unit must be one of the following, and defaults to meters:

* **m** for meters.
* **km** for kilometers.
* **mi** for miles.
* **ft** for feet.

The distance is computed assuming that the Earth is a perfect sphere, so errors up to 0.5% are possible in edge cases.

title: Examples

text:
GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
GEODIST Sicily Palermo Catania
GEODIST Sicily Palermo Catania km
GEODIST Sicily Palermo Catania mi
GEODIST Sicily Foo Bar

title: Return information

text:
**RESP2:**

One of the following:
* [Nil reply](../../develop/reference/protocol-spec#bulk-strings): one or both of the elements are missing.
* [Bulk string reply](../../develop/reference/protocol-spec#bulk-strings): distance as a double (represented as a string) in the specified units.

**RESP3:**

One of the following:
* [Null reply](../../develop/reference/protocol-spec#nulls): one or both of the elements are missing.
* [Bulk string reply](../../develop/reference/protocol-spec#bulk-strings): distance as a double (represented as a string) in the specified units.


title: GEOHASH

summary: Returns members from a geospatial index as geohash strings.

title: Overview

text:
Return valid [Geohash](https://en.wikipedia.org/wiki/Geohash) strings representing the position of one or more elements in a sorted set value representing a geospatial index (where elements were added using [`GEOADD`]()).

Normally Redis represents positions of elements using a variation of the Geohash
technique where positions are encoded using 52 bit integers. The encoding is
also different compared to the standard because the initial min and max
coordinates used during the encoding and decoding process are different. This
command however **returns a standard Geohash** in the form of a string as
described in the [Wikipedia article](https://en.wikipedia.org/wiki/Geohash) and compatible with the [geohash.org](http://geohash.org) web site.

Geohash string properties
---

The command returns 11 characters Geohash strings, so no precision is lost
compared to the Redis internal 52 bit representation. The returned Geohashes
have the following properties:

1. They can be shortened removing characters from the right. It will lose precision but will still point to the same area.
2. It is possible to use them in `geohash.org` URLs such as `http://geohash.org/<geohash-string>`. This is an [example of such URL](http://geohash.org/sqdtr74hyu0).
3. Strings with a similar prefix are nearby, but the contrary is not true, it is possible that strings with different prefixes are nearby too.

title: Examples

text:
GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
GEOHASH Sicily Palermo Catania

title: Return information

text:
**RESP2:**

[Array reply](../../develop/reference/protocol-spec#arrays): an array where each element is the Geohash corresponding to each member name passed as an argument to the command.

**RESP3:**

[Array reply](../../develop/reference/protocol-spec#arrays): An array where each element is the Geohash corresponding to each member name passed as an argument to the command.


title: GEOPOS

summary: Returns the longitude and latitude of members from a geospatial index.

title: Overview

text:
Return the positions (longitude,latitude) of all the specified members of the geospatial index represented by the sorted set at *key*.

Given a sorted set representing a geospatial index, populated using the [`GEOADD`]() command, it is often useful to obtain back the coordinates of specified members. When the geospatial index is populated via [`GEOADD`]() the coordinates are converted into a 52 bit geohash, so the coordinates returned may not be exactly the ones used in order to add the elements, but small errors may be introduced.

The command can accept a variable number of arguments so it always returns an array of positions even when a single element is specified.

title: Examples

text:
GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
GEOPOS Sicily Palermo Catania NonExisting

title: Return information

text:
**RESP2:**

[Array reply](../../develop/reference/protocol-spec#arrays): An array where each element is a two elements array representing longitude and latitude (x,y) of each member name passed as argument to the command. Non-existing elements are reported as [Nil reply](../../develop/reference/protocol-spec#bulk-strings) elements of the array.

**RESP3:**

[Array reply](../../develop/reference/protocol-spec#arrays): An array where each element is a two elements array representing longitude and latitude (x,y) of each member name passed as argument to the command. Non-existing elements are reported as [Null reply](../../develop/reference/protocol-spec#nulls) elements of the array.


title: GEORADIUS

summary: Queries a geospatial index for members within a distance from a coordinate, optionally stores the result.

title: Overview

text:
This command's behavior varies in clustered Redis environments. See the [multi-key operations]() page for more information.

Return the members of a sorted set populated with geospatial information using [`GEOADD`](), which are within the borders of the area specified with the center location and the maximum distance from the center (the radius).

This manual page also covers the [`GEORADIUS_RO`]() and [`GEORADIUSBYMEMBER_RO`]() variants (see the section below for more information).

The common use case for this command is to retrieve geospatial items near a specified point not farther than a given amount of meters (or other units). This allows, for example, to suggest mobile users of an application nearby places.

The radius is specified in one of the following units:

* **m** for meters.
* **km** for kilometers.
* **mi** for miles.
* **ft** for feet.

The command optionally returns additional information using the following options:

* `WITHDIST`: Also return the distance of the returned items from the specified center. The distance is returned in the same unit as the unit specified as the radius argument of the command.
* `WITHCOORD`: Also return the longitude,latitude coordinates of the matching items.
* `WITHHASH`: Also return the raw geohash-encoded sorted set score of the item, in the form of a 52 bit unsigned integer. This is only useful for low level hacks or debugging and is otherwise of little interest for the general user.

The command default is to return unsorted items. Two different sorting methods can be invoked using the following two options:

* `ASC`: Sort returned items from the nearest to the farthest, relative to the center.
* `DESC`: Sort returned items from the farthest to the nearest, relative to the center.

By default all the matching items are returned. It is possible to limit the results to the first N matching items by using the **COUNT `<count>`** option.
When `ANY` is provided the command will return as soon as enough matches are found,
so the results may not be the ones closest to the specified point, but on the other hand, the effort invested by the server is significantly lower.
When `ANY` is not provided, the command will perform an effort that is proportional to the number of items matching the specified area and sort them,
so to query very large areas with a very small `COUNT` option may be slow even if just a few results are returned.

By default the command returns the items to the client. It is possible to store the results with one of these options:

* `STORE`: Store the items in a sorted set populated with their geospatial information.
* `STOREDIST`: Store the items in a sorted set populated with their distance from the center as a floating point number, in the same unit specified in the radius.

title: Read-only variants

text:
Since `GEORADIUS` and [`GEORADIUSBYMEMBER`]() have a `STORE` and `STOREDIST` option they are technically flagged as writing commands in the Redis command table. For this reason read-only replicas will flag them, and Redis Cluster replicas will redirect them to the master instance even if the connection is in read-only mode (see the [`READONLY`]() command of Redis Cluster).

Breaking the compatibility with the past was considered but rejected, at least for Redis 4.0, so instead two read-only variants of the commands were added. They are exactly like the original commands but refuse the `STORE` and `STOREDIST` options. The two variants are called [`GEORADIUS_RO`]() and [`GEORADIUSBYMEMBER_RO`](), and can safely be used in replicas.

title: Examples

text:
GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
GEORADIUS Sicily 15 37 200 km WITHDIST
GEORADIUS Sicily 15 37 200 km WITHCOORD
GEORADIUS Sicily 15 37 200 km WITHDIST WITHCOORD

text:
| Redis
Software | Redis
Cloud | Notes |
|:----------------------|:-----------------|:------|
| ✅ Standard
<nobr>✅ Active-Active</nobr> | ✅ Standard
<nobr>✅ Active-Active</nobr> | Deprecated as of Redis v6.2.0. |

title: Return information

text:
**RESP2:**

One of the following:
* If no `WITH*` option is specified, an [Array reply](../../develop/reference/protocol-spec#arrays) of matched member names
* If `WITHCOORD`, `WITHDIST`, or `WITHHASH` options are specified, the command returns an [Array reply](../../develop/reference/protocol-spec#arrays) of arrays, where each sub-array represents a single item:
    1. The distance from the center as a floating point number, in the same unit specified in the radius.
    1. The Geohash integer.
    1. The coordinates as a two items x,y array (longitude,latitude).
For example, the command `GEORADIUS Sicily 15 37 200 km WITHCOORD WITHDIST` will return each item in the following way:
`["Palermo","190.4424",["13.361389338970184","38.115556395496299"]]`

**RESP3:**

One of the following:
* If no `WITH*` option is specified, an [Array reply](../../develop/reference/protocol-spec#arrays) of matched member names
* If `WITHCOORD`, `WITHDIST`, or `WITHHASH` options are specified, the command returns an [Array reply](../../develop/reference/protocol-spec#arrays) of arrays, where each sub-array represents a single item:
    1. The distance from the center as a floating point number, in the same unit specified in the radius.
    1. The Geohash integer.
    1. The coordinates as a two items x,y array (longitude,latitude).
For example, the command `GEORADIUS Sicily 15 37 200 km WITHCOORD WITHDIST` will return each item in the following way:
`["Palermo","190.4424",["13.361389338970184","38.115556395496299"]]`


title: GEORADIUS_RO

summary: Returns members from a geospatial index that are within a distance from a coordinate.

title: Overview

text:
Read-only variant of the [`GEORADIUS`]() command.

This command is identical to the [`GEORADIUS`]() command, except that it doesn't support the optional `STORE` and `STOREDIST` parameters.

title: Return information

text:
**RESP2:**

One of the following:
* If no `WITH*` option is specified, an [Array reply](../../develop/reference/protocol-spec#arrays) of matched member names
* If `WITHCOORD`, `WITHDIST`, or `WITHHASH` options are specified, the command returns an [Array reply](../../develop/reference/protocol-spec#arrays) of arrays, where each sub-array represents a single item:
    * The distance from the center as a floating point number, in the same unit specified in the radius.
    * The Geohash integer.
    * The coordinates as a two items x,y array (longitude,latitude).

**RESP3:**

One of the following:
* If no `WITH*` option is specified, an [Array reply](../../develop/reference/protocol-spec#arrays) of matched member names
* If `WITHCOORD`, `WITHDIST`, or `WITHHASH` options are specified, the command returns an [Array reply](../../develop/reference/protocol-spec#arrays) of arrays, where each sub-array represents a single item:
    * The distance from the center as a floating point number, in the same unit specified in the radius.
    * The Geohash integer.
    * The coordinates as a two items x,y array (longitude,latitude).


title: GEORADIUSBYMEMBER

summary: Queries a geospatial index for members within a distance from a member, optionally stores the result.

title: Overview

text:
This command's behavior varies in clustered Redis environments. See the [multi-key operations]() page for more information.

This command is exactly like [`GEORADIUS`]() with the sole difference that instead
of taking, as the center of the area to query, a longitude and latitude value, it takes the name of a member already existing inside the geospatial index represented by the sorted set.

The position of the specified member is used as the center of the query.

Please check the example below and the [`GEORADIUS`]() documentation for more information about the command and its options.

Note that [`GEORADIUSBYMEMBER_RO`]() is also available since Redis 3.2.10 and Redis 4.0.0 in order to provide a read-only command that can be used in replicas. See the [`GEORADIUS`]() page for more information.

title: Examples

text:
GEOADD Sicily 13.583333 37.316667 "Agrigento"
GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
GEORADIUSBYMEMBER Sicily Agrigento 100 km

title: Return information


title: GEORADIUSBYMEMBER_RO

summary: Returns members from a geospatial index that are within a distance from a member.

title: Overview

text:
Read-only variant of the [`GEORADIUSBYMEMBER`]() command.

This command is identical to the [`GEORADIUSBYMEMBER`]() command, except that it doesn't support the optional `STORE` and `STOREDIST` parameters.

title: Return information