SEARCH

Preview Feature

The vector search feature is offered AS-IS as described in your agreement with Neo4j and should only be used for internal development purposes. When this feature becomes generally available, you will need to upgrade to the latest Neo4j version (which may require downtime) to use the feature for non-development purposes.

Vector search is enabled by default, both in Aura and self-managed Neo4j.

During the Preview period, if you have any feedback, comments, or encounter any issues, we welcome them in our public GitHub repository. We will address them to the best of our ability. Please include the term Vector search in the title of your issue so we can identify it more easily.
Customers with active contracts may contact Neo4j Support through the standard support channels. Please note that any cases related to the Preview feature will be classified as Severity 4 by default, in accordance with the Support Terms.

The SEARCH clause is not a clause in its own right — rather, it is a subclause used within MATCH and OPTIONAL MATCH clauses to add constraints on their pattern based on approximate nearest neighbor (ANN) vector search. In order to use the SEARCH clause, you must first have created a vector index.

SEARCH clause syntax

The SEARCH clause has the following syntax

[OPTIONAL] MATCH pattern
  SEARCH binding_variable IN (
    VECTOR INDEX index_name
    FOR query_vector
    [WHERE ...]
    LIMIT top_k
  ) [SCORE AS score_alias]

The SEARCH clause constrains the pattern from the enclosing MATCH or OPTIONAL MATCH, by only returning nodes or relationships included in the results of the ANN vector search as described by the SEARCH clause. Below follows a short description of the different parts of the syntax:

  • The binding_variable must be a node or relationship variable from the pattern of the enclosing MATCH or OPTIONAL MATCH clause.

  • The index_name must be an identifier that matches the name of an existing vector index in the Neo4j database. The vector index must be a node vector index if the binding_variable refers to a node and a relationship vector index if the binding_variable refers to a relationship.

  • The query_vector can be any expression that evaluates to a VECTOR or LIST<INTEGER NOT NULL | FLOAT NOT NULL>, for example a literal, a parameter or a property. The SEARCH clause returns a neighborhood of nodes or relationships based on the similarity between the query_vector the corresponding property of those nodes or relationships.

  • The optional WHERE subclause applies a filter to the vector index, and is a restricted version of the normal Cypher® WHERE clause. For more information, see Predicates for vector search with filters.

  • The LIMIT clause sets the number of approximate nearest neighbor nodes or relationships returned by the SEARCH clause. The top_k must be of type INTEGER NOT NULL and in the interval 0 <= top_k <= 2147483647 [1].

  • The optional SCORE subclause makes the SEARCH clause return the similarity score for each node or relationship in addition to the node or relationship itself. In the result, the column for the similarity scores will be called score_alias.

  • The SEARCH clause puts some restrictions on which pattern the enclosing MATCH or OPTIONAL MATCH clause is allowed to have. For more information, see Limitations of the SEARCH clause.

Example graph and vector index

The following graph is used for the examples below:

To recreate the graph, run the following query in an empty Neo4j database:

CREATE (:Movie {title: 'Aladdin', releaseDate: date('1992-11-08'), rating: 8.0}),
       (:Movie {title: 'Cinderella', embedding: vector([1, 3, 4], 3, INTEGER), releaseDate: date('1950-02-15'), rating: 7.3}),
       (:Movie:Favorite {title: 'Frozen', embedding: [1, 3, 3], releaseDate: date('2013-11-10'), rating: 7.4}),
       (:Movie {title: 'Lilo & Stitch', embedding: vector([1, 1, 3], 3, INTEGER), releaseDate: date('2002-06-16'), rating: 7.4}),
       (:Movie:Favorite {title: 'Lion King', embedding: vector([2, 5, 2], 3, INTEGER), releaseDate: date('1994-06-12'), rating: 8.5}),
       (:Movie:Favorite {title: 'Mulan', embedding: [2, 3, 3], releaseDate: date('1998-06-05'), rating: 7.7}),
       (:Movie {title: 'Snow White', embedding: vector([1, 2, 3], 3, INTEGER), releaseDate: date('1937-12-21'), rating: 7.6})

Each node in the example graph represents a movie with properties for its title, release date and rating. The majority of the nodes also have a VECTOR property called embedding, which is a vector representation of the plot of the movie. In a real-world example, these vector embeddings would typically be generated by a proprietary or open source embedding generator and have a dimension of for example 768 or 1536, but for simplicity this example dataset uses vector embeddings of dimension 3.

The examples use a vector index named moviePlots on the embedding property and releaseDate and rating as additional properties for filtering. Such a vector index can be created with the following Cypher query:

CREATE VECTOR INDEX moviePlots IF NOT EXISTS
FOR (m:Movie) ON m.embedding
WITH [m.releaseDate, m.rating]
OPTIONS {
  indexConfig: {
    `vector.similarity_function`: 'cosine',
    `vector.dimensions`: 3,
    `vector.quantization.enabled`: false
  }
}

For more information about the creation of vector indexes, see Create vector indexes.

Find the most similar nodes

In our example dataset, the movie with the title Snow White has the embedding vector([1, 2, 3], 3, INTEGER). To find the 4 most similar movies to Snow White, you can run several different Cypher queries with the SEARCH clause.

Example 1. Using a vector literal as the query vector
Query
MATCH (movie:Movie)
  SEARCH movie IN (
    VECTOR INDEX moviePlots
    FOR vector([1, 2, 3], 3, INTEGER)
    LIMIT 4
  )
RETURN movie.title AS title
Result
title

"Snow White"

"Cinderella"

"Frozen"

"Mulan"

Rows: 4

Example 2. Using a list literal as the query vector
Query
MATCH (movie:Movie)
  SEARCH movie IN (
    VECTOR INDEX moviePlots
    FOR [1, 2, 3]
    LIMIT 4
  )
RETURN movie.title AS title
Result
title

"Snow White"

"Cinderella"

"Frozen"

"Mulan"

Rows: 4

Example 3. Using a vector parameter as the query vector
Parameters
{
  "snowWhiteEmbedding": vector([1, 2, 3], 3, INTEGER)
}
Query
MATCH (movie:Movie)
  SEARCH movie IN (
    VECTOR INDEX moviePlots
    FOR $snowWhiteEmbedding
    LIMIT 4
  )
RETURN movie.title AS title
Result
title

"Snow White"

"Cinderella"

"Frozen"

"Mulan"

Rows: 4

Example 4. Using a property as the query vector
Query
MATCH (snowWhite:Movie {title: 'Snow White'})
MATCH (movie:Movie)
  SEARCH movie IN (
    VECTOR INDEX moviePlots
    FOR snowWhite.embedding
    LIMIT 4
  )
RETURN movie.title AS title
Result
title

"Snow White"

"Cinderella"

"Frozen"

"Mulan"

Rows: 4

All four queries above return the same result. The movie nodes are returned in decreasing similarity order. Snow White is the most similar movie to itself, while Mulan is the fourth most similar movie to Snow White. The movies Lilo & Stitch and Lion King are not returned as they are not among the top 4 most similar movies, while the movie Aladdin does not have an embedding property and is therefore not considered by the vector index at all.

The label predicate :Movie in the MATCH patterns above is not strictly required. As the vector index only contains nodes with label :Movie, the SEARCH clause adds this predicate implicitly.

Find the most similar nodes with score

To return the four most similar movies to Snow White together with their similarity score, you can include the optional SCORE subclause in the SEARCH clause.

Example 5. Adding the similarity score to the output
Query
MATCH (snowWhite:Movie {title: 'Snow White'})
MATCH (movie:Movie)
  SEARCH movie IN (
    VECTOR INDEX moviePlots
    FOR snowWhite.embedding
    LIMIT 4
  ) SCORE AS similarityScore
RETURN movie.title AS title, similarityScore
Result
title similarityScore

"Snow White"

1.0

"Cinderella"

0.9979352951049805

"Frozen"

0.9905114769935608

"Mulan"

0.9843324422836304

Rows: 4

Similarity scores have type FLOAT NOT NULL and are bounded between 0.0 and 1.0. The closer to 1.0 the score is, the more similar the indexed embedding property is to the query vector. The movie Snow White has a similarity score of 1.0 as its embedding property is identical to the query vector.

Similarity scores are calculated using the similarity function that was chosen when the vector index was created, the default is cosine similarity. For more information on similarity functions, see Cosine and Euclidean similarity functions.

Additional predicates in the MATCH pattern

The pattern in the MATCH or OPTIONAL MATCH can have label and property predicates on the node or relationship with the binding variable.

Example 6. Finding the most similar movies with an extra label predicate
Query
MATCH (movie:Movie&Favorite)
  SEARCH movie IN (
    VECTOR INDEX moviePlots
    FOR vector([1, 2, 3], 3, INTEGER)
    LIMIT 4
  )
RETURN movie.title AS title
Result
title

"Frozen"

"Mulan"

Rows: 2

The label predicate acts as a post-filtering step to the vector search. Even if the movie node with the title Lion King also has the label Favorite, it is not returned as it is not among the four most similar nodes to the query vector.

Example 7. Finding the most similar movies with an extra property predicate
Query
MATCH (movie:Movie {releaseDate: date('2013-11-10')})
  SEARCH movie IN (
    VECTOR INDEX moviePlots
    FOR vector([1, 2, 3], 3, INTEGER)
    LIMIT 4
  )
RETURN movie.title AS title
Result
title

"Frozen"

Rows: 2

Vector search with filters

A MATCH or OPTIONAL MATCH clause can have both a WHERE subclause and SEARCH subclause. Regardless of their order, the WHERE clause will act as a post-filtering step to the vector search, further filtering down the results.

Either of the queries below find the four most similar movies to Snow White and then filter down the result to only movies which were released after 1990.

Example 8. The order of WHERE and SEARCH does not affect the result
WHERE followed by SEARCH
MATCH (movie:Movie)
  WHERE movie.releaseDate > date('1990')
  SEARCH movie IN (
    VECTOR INDEX moviePlots
    FOR vector([1, 2, 3], 3, INTEGER)
    LIMIT 4
  )
RETURN movie.title AS title, movie.releaseDate.year AS year
SEARCH followed by WHERE
MATCH (movie:Movie)
  SEARCH movie IN (
    VECTOR INDEX moviePlots
    FOR vector([1, 2, 3], 3, INTEGER)
    LIMIT 4
  )
  WHERE movie.releaseDate > date('1990')
RETURN movie.title AS title, movie.releaseDate.year AS year
Result
title year

"Frozen"

2013

"Mulan"

1998

Rows: 2

Often, it is preferable to do the filtering while performing the vector search, so called in-index filtering, instead of as a post-filtering step. This can be achieved with vector search with filters, where the WHERE is a subclause to the SEARCH clause instead of a subclause to the enclosing MATCH or OPTIONAL MATCH clause.

To find the four most similar movies to Snow White which were released after 1990 with a vector search with filters, use the following query.

Example 9. Vector search with filter
Query
MATCH (movie:Movie)
  SEARCH movie IN (
    VECTOR INDEX moviePlots
    FOR vector([1, 2, 3], 3, INTEGER)
    WHERE movie.releaseDate > date('1990')
    LIMIT 4
  )
RETURN movie.title AS title, movie.releaseDate.year AS year
Result
title year

"Frozen"

2013

"Mulan"

1998

"Lilo & Stitch"

2002

"Lion King"

1994

Rows: 4

When using vector search with filters, the vector search continues until it has found the requested number of result that also fulfills the other predicates. By contrast, using a normal WHERE clause in the MATCH can lead to significantly fewer results. Because of this, you might want to set a higher LIMIT in the SEARCH clause and complement it with a lower LIMIT in the RETURN. This approach is called over-fetching.

Combining vector search with filters and post-filtering

Vector search with filters and a normal WHERE clause can be combined. The following query finds the four most similar movies to Snow White which were released after 1990, and then does post-filtering to discard any result with a rating worse than 7.5.

Example 10. Vector search with filter and WHERE clause
Query
MATCH (movie:Movie)
  SEARCH movie IN (
    VECTOR INDEX moviePlots
    FOR vector([1, 2, 3], 3, INTEGER)
    WHERE movie.releaseDate > date('1990')
    LIMIT 4
  )
  WHERE movie.rating > 7.5
RETURN movie.title AS title, movie.releaseDate.year AS year, movie.rating AS rating
Result
title year rating

"Mulan"

1998

7.7

"Lion King"

1994

8.5

Rows: 2

Predicates for vector search with filters

The optional WHERE subclause used to do vector search with filters is a restricted version of the normal Cypher WHERE clause and only allows certain types of predicates. The predicate must be a property predicate or several property predicates with AND between them.

Example 11. Vector search with filter with an AND predicate on the same property
Query
MATCH (movie:Movie)
  SEARCH movie IN (
    VECTOR INDEX moviePlots
    FOR vector([1, 2, 3], 3, INTEGER)
    WHERE movie.releaseDate > date('1948') AND date('2010') > movie.releaseDate
    LIMIT 4
  )
RETURN movie.title AS title, movie.releaseDate.year AS year
Result
title year

"Cinderella"

1950

"Mulan"

1998

"Lilo & Stitch"

2002

"Lion King"

1994

Rows: 4

The WHERE subclause in the query above can also be written as WHERE date('1948') < movie.releaseDate < date('2010') .

Example 12. Vector search with filter with an AND predicate on separate properties
Query
MATCH (snowWhite:Movie {title:"Snow White"})
MATCH (movie:Movie)
  SEARCH movie IN (
    VECTOR INDEX moviePlots
    FOR snowWhite.embedding
    WHERE movie.releaseDate < date('2000') AND movie.rating >= snowWhite.rating
    LIMIT 4
  )
RETURN movie.title AS title, movie.releaseDate.year AS year, movie.rating AS rating
Result
title year rating

"Snow White"

1937

7.6

"Mulan"

1998

7.7

"Lion King"

1994

8.5

Rows: 4

If the LIMIT in the SEARCH clause is larger than the total number of indexed vectors fulfilling the predicate, the vector search will return fewer results. In the example above, only three nodes are returned despite the LIMIT being four. Due to the approximate nature of vector search, this can also happen if the LIMIT is smaller than but close to the total number of indexed vectors fulfilling the predicate.

The variable in the property predicate must be the same as the binding variable in the SEARCH clause.

Example 13. Error: mismatch of a property predicate variable and a binding variable in the SEARCH clause
Query
MATCH (m: Movie {name: "Snow White"})
MATCH (movie:Movie)
  SEARCH movie IN (
    VECTOR INDEX moviePlots
    FOR vector([1, 2, 3], 3, INTEGER)
    WHERE m.rating > 8
    LIMIT 4
  )
RETURN movie.title AS title
Error message
The variable `m` in a vector search filter property predicate must be the same as the search clause binding variable `movie`.

All properties in the property predicate must have been added as additional properties for filtering when creating the vector index.

Example 14. Error: a property of the property predicate wasn’t defined as an additional property in the vector index
Query
MATCH (movie:Movie)
  SEARCH movie IN (
    VECTOR INDEX moviePlots
    FOR vector([1, 2, 3], 3, INTEGER)
    WHERE movie.rating > 8 AND movie.title > "L"
    LIMIT 4
  )
RETURN movie.title AS title, movie.rating AS rating
Error message
22ND3: The property `title` has not been added as an additional property for the vector index `moviePlots`.

For further limitations on the WHERE predicate, see Limitations of the WHERE predicate.

Using a query vector with different dimensions

If the query vector has a different dimension than the configured dimension of the vector index, the query will fail.

Example 15. Error: query vector with only two dimensions when three are being used
Query
MATCH (movie:Movie)
  SEARCH movie IN (
    VECTOR INDEX moviePlots
    FOR vector([1, 2], 2, INTEGER)
    LIMIT 4
  )
RETURN movie.title AS title
Error message
Vector index 'moviePlots' has a configured dimensionality of 3, but the provided vector has dimension 2.

If the vector index has no configured dimension, the query succeeds. However, if there are no vectors in the index of the same dimension as the query vector, the result of the query will be empty.

Using a query vector which evaluates to null

If the query vector evaluates to null, for example because it refers to a non-existing property, a SEARCH clause inside a MATCH returns no results.

Example 16. A query vector which evaluates to null
Query
MATCH (snowWhite:Movie {title: 'Snow White'})
MATCH (movie:Movie)
  SEARCH movie IN (
    VECTOR INDEX moviePlots
    FOR snowWhite.prop
    LIMIT 4
  )
RETURN movie.title AS title
Result
title

Rows: 0

If the SEARCH clause with a query vector evaluating to null is instead in an OPTIONAL MATCH clause, it returns null as per regular OPTIONAL MATCH semantics.

Example 17. A query vector which evaluates to null as per regular OPTIONAL MATCH semantics
Query
MATCH (snowWhite:Movie {title: 'Snow White'})
OPTIONAL MATCH (movie:Movie)
  SEARCH movie IN (
    VECTOR INDEX moviePlots
    FOR snowWhite.prop
    LIMIT 4
  )
RETURN movie.title AS title
Result
title

null

Rows: 1

Using a binding variable which is not from the enclosing clause

The binding variable in a SEARCH clause must be a node or relationship variable from the pattern of the enclosing MATCH or OPTIONAL MATCH clause. Trying to refer to a variable from an earlier clause in the query or introducing a new variable will cause the query to fail.

Example 18. Error: binding variable from earlier clause
Query
MATCH (movie:Movie)
MATCH (m: Movie {name: 'Snow White'})
  SEARCH movie IN (
    VECTOR INDEX moviePlots
    FOR m.embedding
    LIMIT 4
  )
RETURN movie.title AS title
Error message
The variable `movie` in SEARCH must reference a variable from the same MATCH statement.
Example 19. Error: binding variable not previously defined
Query
MATCH (movie:Movie)
  SEARCH node IN (
    VECTOR INDEX moviePlots
    FOR vector([1, 2, 3], 3, INTEGER)
    LIMIT 4
  )
RETURN movie.title AS title
Error message
Variable `node` not defined

Limitations of the SEARCH clause

The tables below list some past and current limitations of the SEARCH clause. If applicable, the version which lifted the limitation is also listed.

The SEARCH clause puts restrictions on the pattern of the enclosing MATCH or OPTIONAL MATCH clause.

Limitations of the MATCH or OPTIONAL MATCH pattern
Limitation Disallowed example Lifted in

The pattern cannot have more than one bound variable.

MATCH (movie:Movie)-[r]->()

The pattern cannot have predicates on other elements than the bound variable.

MATCH (:Actor)-[]->(m:Movie)

The pattern cannot have a length longer than one relationship hop.

MATCH ()-[r: KNOWS]->()-[]->()

MATCH (movie:Movie)-[*1..3]->()

The pattern cannot have multiple pattern parts.

MATCH (movie:Movie), ()

The pattern cannot have a path selector other than ALL.

MATCH ANY 2 (movie: Movie)

The optional WHERE subclause used to do vector search with filters is a restricted version of the normal Cypher WHERE clause and only allows certain types of property predicates.

Limitations of the WHERE predicate
Limitation Disallowed example Lifted in

The comparison operator in the predicate cannot be <>.

WHERE movie.rating <> 7.5

The comparison operator in the predicate cannot be IS NOT NULL.

WHERE movie.rating IS NOT NULL

Neo4j 2026.02

The comparison operator in the predicate cannot be IS NULL.

WHERE movie.rating IS NULL

The predicate cannot include other boolean operators than AND.

WHERE NOT movie.rating > 8 [2]

WHERE movie.rating > 8 OR movie.releaseDate <= date("2000")

The predicate cannot include a list operator.

WHERE movie.rating IN [7, 7.5, 8]

The predicate cannot include a string operator.

WHERE movie.rating STARTS WITH '8'

The predicate cannot include a type predicate expression.

WHERE movie.rating IS :: FLOAT

The expression in the predicate cannot be of type POINT.

WHERE movie.rating < point({x:2.3, y:4.5})

The expression in the predicate cannot be of type VECTOR.

WHERE movie.rating < vector([8.2, 8.5], 2, FLOAT)

The expression in the predicate cannot be of type LIST.

WHERE movie.rating < [8, 8.5]

The expression in the predicate is not allowed to reference the binding variable.

WHERE movie.rating > movie.title

The predicate cannot contain multiple property predicates on the same property in the same direction.

WHERE movie.rating > 8.2 AND movie.rating >= 8.5

The predicate cannot contain multiple property predicates on the same property where one is an equality and one is a range predicate.

WHERE movie.rating > 8.2 AND movie.rating = 8.5

2. NOT is allowed for boolean properties. For example, given that seen has been added as an additional property for filtering when the vector index was created, WHERE NOT movie.seen is allowed and will be rewritten to WHERE movie.seen = false internally.
Other limitations of the SEARCH clause
Limitation Lifted in

Unlike in other index commands such as CREATE VECTOR INDEX and DROP INDEX, the index name is not allowed to be a parameter in the VECTOR INDEX subclause of SEARCH.

The query vector is not allowed to reference the binding variable.

MATCH (movie:Movie)
  SEARCH movie IN (
    VECTOR INDEX moviePlots
    FOR movie.embedding
    LIMIT 4
  )
RETURN movie.title AS title
Error message
Vector search embeddings referencing the search variable

1. 2147483647 is the Integer.MAX_VALUE from Java