valkey-search-query - Man Page

Valkey Search — Queries

Description

The query of the FT.SEARCH and FT.AGGREGATE commands identifies a subset of the keys in the index to be processed by those commands. The syntax and semantics of the query string is identical for both commands.

A query has three different formats: pure-vector, hybrid-vector and non-vector.

Pure Vector Queries

A pure-vector query performs a K Nearest Neighbors (KNN) query of a single vector field within the index.

*=>[ KNN <K> @<field> $<parameter> [EF_RUNTIME <ef-value>] [AS <name>] ]

Hybrid Vector Queries

A hybrid query adds a filter expression to indicate which keys within the index are candidates for results.

<filter>=>[ KNN <K> @<field> $<parameter> [EF_RUNTIME <ef-value>] [AS <name>] ]

Non-Vector Query

A non-vector query consists solely of a filter:

<filter>

Where:

Filter Expression

A filter identifies a set of keys. Filters can be constructed using individual query operator as well as by combining operators with AND, OR, NEGATE operators.

It is not the case that the of filtering terminology implies an O(N) scan of keys in an index. Valkey search intelligently combines the usage of secondary indexes and simple filtering to efficiently locate the keys that a filter identifies. Determining the computational complexity of a particular filter is difficult, but generally no worse than O(log N) and sometimes as fast as O(1).

The BNF for a filter is:

<filter>        ::= <logical-or>

<logical-or>    ::= <logical-and>
                  | <logical-or> "|" <logical-and>
<logical-and>   ::= <logical-not>
                  | <logical-and> " " <logical-not>
<logical-not>   ::= <matcher>
                  | "-" <logical-not>
<matcher>       ::= <tag-match>
                  | <numeric-match>
                  | <term-match>
                  | <phrase-match>
                  | <fuzzy-match>
                  | "(" <logical-or> ")"

Tag Match

The tag match operator is specified with one or more match strings separated by the | character. Tag match supports both exact match and prefix match. If a match string end with an * then prefix matching is performed, otherwise exact matching is performed. Case insensitive matching can be configured when the field was declared.

@<field-name>:{<tag>}
or
@<field-name>:{<tag1> | <tag2>}
or
@<field-name>:{<tag1> | <tag2> | ...}

For example, the following query will return documents with blue OR black OR green color.

@color:{blue | black | green}

As another example, the following query will return documents containing “hello world” or “hello universe”

@color:{hello world | hello universe}

This example will match black or any word that starts with fred:

@color:{black | fred*}

For more examples see Tag Fields.

Numeric Range Match

Numeric range matcher selects keys based on the value of a numeric field being between a given start and end value. Both inclusive and exclusive range queries are supported. For simple relational comparisons, +inf, -inf can be used with a range query.

The syntax for a range search operator is:

@<field-name>:[ [(] <bound> [(] <bound>]

where  is either a decimal integer, floating-point number or ±inf

Bounds without a leading open paren are inclusive, whereas bounds with the leading open parenthesis are exclusive.

Use the following table as a guide for mapping mathematical expressions to filtering queries:

Desired comparisonNumeric matcher
min ≤ field ≤ max@field:[min max]
min < field ≤ max@field:[(min max]
min ≤ field < max@field:[min (max]
min < field < max@field:[(min (max]
field ≥ min@field:[min +inf]
field > min@field:[(min +inf]
field ≤ max@field:[-inf max]
field < max@field:[-inf (max]
field = val@field:[val val]

Examples of numeric matchers

@price:[10 100]           10 ≤ field ≤ 100
@price:[(10 100.5]        10 < field ≤ 100.5
@price:[-inf (1e2]        price < 100

Text Search Operators

Unlike the other search operators. The text search operators do not require that a field be specified. If a field is not specified for a text search operator, then all text fields within the index are searched. Regardless, if multiple text search operators are combined in an expression, then only keys which have all of the text search operators will satisfy the query.

Prefix Matching

A term with a trailing * matches any word that starts with that term.

hello*                  matches words that start with hello such as hello, hello1, hello_world but not ohello
@t:hello*               matches words that start with hello in the t field (t must be a text field)

Suffix Matching

A term with a leading * matches any word that ends with that term.

Note that suffix searching will only locate words in fields that have WITHSUFFIXTRIE specified, i.e., fields declared with NOSUFFIXTRIE will not be searched. If a field specifier is added to a suffix term search and that particular field was declared with NOSUFFIXTRIE then an error will be issued.

*hello                  matches words that end with hello such as hello, ohello but not hello1
@t:*hello               matches words that end with hello in the t field (t must be a text field with WITHSUFFIXTRIE)

Logical Operators

Logical Negation

Any query can be negated by prepending the - character before each query. Negative queries return all keys that don’t match the query. This also includes keys that don’t have the field.

For example, the negative query -@genre:{comedy} will return all books that are not comedy AND all books that don’t have a genre field.

The following query will return all books with “comedy” genre that are not published between 2015 and 2024, or that have no year field:

@genre: {comedy} \-@year:[2015 2024]

Logical OR

To set a logical OR, use the | character between the predicates.

Example:

query1 | query2 | query3

Logical AND

To specify the AND operation use a space between the predicates. If the INORDER and SLOP options are not provided then the AND operation is done at the key level. This means that any key which satisfies each of the predicates will match.

If either of the INORDER or SLOP options are provided, then the AND operation is extended beyond simple key matching to also include positional matching of the text searching operators. Positional matching requires that each predicate not only match the same key but that the text searching operators (term, prefix, suffix, exact phrase and fuzzy) must also match words that satisfy the requirements of INORDER and SLOP in the same field of the same key.

For example:

query1 query2 query3

Proximity AND

When two or more predicates of an AND operation contain text matchers, it becomes possible to also perform positional matching. Positional matching extends key-based matching to additionally require that matching words meet specified distance and ordering constraints. Positional matching is only applied within a single Text field. There is no positional relationship between terms in different Text fields.

Position matching is enabled when either the SLOP or INORDER clauses are used on the command and applies to all multi-predicate AND operations within the current command.

Referenced By

valkey-search-data-formats(7).

2026-05-19 9.1.0 Valkey Manual