SEARCH

SEARCH 子句本身不是一个独立的子句,而是用于 MATCHOPTIONAL MATCH 子句内的子句,用于基于近似最近邻 (ANN) 向量搜索为其模式添加约束。要使用 SEARCH 子句,必须首先创建向量索引

SEARCH 子句语法

SEARCH 子句具有以下语法:

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

SEARCH 子句通过仅返回由 SEARCH 子句描述的 ANN 向量搜索结果中包含的节点或关系,来约束外层 MATCHOPTIONAL MATCH 中的 pattern(模式)。下面简要介绍了语法中的不同部分:

  • binding_variable(绑定变量)必须是来自外层 MATCHOPTIONAL MATCH 子句的 pattern 中的节点或关系变量。

  • index_name(索引名称)必须是一个标识符,与 Neo4j 数据库中现有向量索引的名称相匹配。如果 binding_variable 引用的是节点,则向量索引必须是节点向量索引;如果 binding_variable 引用的是关系,则必须是关系向量索引。

  • query_vector(查询向量)可以是任何计算结果为 VECTORLIST<INTEGER NOT NULL | FLOAT NOT NULL> 的表达式,例如字面量、参数或属性。SEARCH 子句根据 query_vector 与这些节点或关系的相应属性之间的相似性,返回节点或关系的邻域。

  • 可选的 WHERE 子句将过滤器应用于向量索引,它是标准 Cypher® WHERE 子句的受限版本。有关更多信息,请参阅带过滤器的向量搜索谓词

  • LIMIT 子句设置由 SEARCH 子句返回的近似最近邻节点或关系的数量。top_k 必须是 INTEGER NOT NULL 类型,且在区间 0 <= top_k <= 2147483647[1]

  • 可选的 SCORE 子句使得 SEARCH 子句除了返回节点或关系本身外,还返回每个节点或关系的相似度得分。在结果中,相似度得分列将命名为 score_alias

  • SEARCH 子句对外层 MATCHOPTIONAL MATCH 子句允许的 pattern 施加了一些限制。有关更多信息,请参阅SEARCH 子句的限制

示例图和向量索引

以下图表用于下方的示例

要重建该图,请在空的 Neo4j 数据库中运行以下查询

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})

示例图中的每个节点都代表一部电影,并具有标题、发行日期和评分属性。大多数节点还具有一个名为 embeddingVECTOR 属性,它是电影情节的向量表示。在现实世界的示例中,这些向量嵌入通常由专有或开源的嵌入生成器生成,并具有例如 768 或 1536 的维度,但为简单起见,此示例数据集使用 3 维的向量嵌入。

这些示例在 embedding 属性上使用名为 moviePlots 的向量索引,并将 releaseDaterating 作为附加过滤属性。此类向量索引可以通过以下 Cypher 查询创建:

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
  }
}

有关创建向量索引的更多信息,请参阅创建向量索引

查找最相似的节点

在我们的示例数据集中,标题为 Snow White 的电影具有嵌入 vector([1, 2, 3], 3, INTEGER)。要查找与 Snow White 最相似的 4 部电影,您可以运行几个不同的带有 SEARCH 子句的 Cypher 查询。

示例 1. 使用向量字面量作为查询向量
查询
MATCH (movie:Movie)
  SEARCH movie IN (
    VECTOR INDEX moviePlots
    FOR vector([1, 2, 3], 3, INTEGER)
    LIMIT 4
  )
RETURN movie.title AS title
结果
标题

"Snow White"

"Cinderella"

"Frozen"

"Mulan"

行:4

示例 2. 使用列表字面量作为查询向量
查询
MATCH (movie:Movie)
  SEARCH movie IN (
    VECTOR INDEX moviePlots
    FOR [1, 2, 3]
    LIMIT 4
  )
RETURN movie.title AS title
结果
标题

"Snow White"

"Cinderella"

"Frozen"

"Mulan"

行:4

示例 3. 使用向量参数作为查询向量
参数
{
  snowWhiteEmbedding: vector([1, 2, 3], 3, INTEGER)
}
查询
MATCH (movie:Movie)
  SEARCH movie IN (
    VECTOR INDEX moviePlots
    FOR $snowWhiteEmbedding
    LIMIT 4
  )
RETURN movie.title AS title
结果
标题

"Snow White"

"Cinderella"

"Frozen"

"Mulan"

行:4

示例 4. 使用属性作为查询向量
查询
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
结果
标题

"Snow White"

"Cinderella"

"Frozen"

"Mulan"

行:4

上述所有四个查询返回相同的结果。电影节点按相似度递减的顺序返回。Snow White 与其自身最相似,而 Mulan 是与 Snow White 第四相似的电影。电影 Lilo & StitchLion King 不会被返回,因为它们不在最相似的前 4 部电影之列;而电影 Aladdin 没有 embedding 属性,因此向量索引完全不考虑它。

上述 MATCH 模式中的标签谓词 :Movie 并非严格要求。由于向量索引仅包含标签为 :Movie 的节点,SEARCH 子句会隐式添加此谓词。

查找带得分的最相似节点

要返回与 Snow White 最相似的四部电影及其相似度得分,您可以在 SEARCH 子句中包含可选的 SCORE 子句。

示例 5. 将相似度得分添加到输出
查询
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
结果
标题 similarityScore

"Snow White"

1.0

"Cinderella"

0.9979352951049805

"Frozen"

0.9905114769935608

"Mulan"

0.9843324422836304

行:4

相似度得分类型为 FLOAT NOT NULL,范围在 0.01.0 之间。得分越接近 1.0,索引的 embedding 属性与查询向量的相似度就越高。电影 Snow White 的相似度得分为 1.0,因为它的 embedding 属性与查询向量完全一致。

相似度得分是使用创建向量索引时选择的相似度函数计算的,默认为余弦相似度。有关相似度函数的更多信息,请参阅余弦和欧几里得相似度函数

MATCH 模式中的额外谓词

MATCHOPTIONAL MATCH 中的模式可以对带有绑定变量的节点或关系具有标签和属性谓词。

示例 6. 查找带有额外标签谓词的最相似电影
查询
MATCH (movie:Movie&Favorite)
  SEARCH movie IN (
    VECTOR INDEX moviePlots
    FOR vector([1, 2, 3], 3, INTEGER)
    LIMIT 4
  )
RETURN movie.title AS title
结果
标题

"Frozen"

"Mulan"

行:2

标签谓词充当向量搜索的后过滤步骤。即使标题为 Lion King 的电影节点也有 Favorite 标签,但由于它不在与查询向量最相似的前四个节点之列,因此不会被返回。

示例 7. 查找带有额外属性谓词的最相似电影
查询
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
结果
标题

"Frozen"

行:2

带过滤器的向量搜索

MATCHOPTIONAL MATCH 子句既可以有 WHERE 子句,也可以有 SEARCH 子句。无论它们的顺序如何,WHERE 子句都将充当向量搜索的后过滤步骤,进一步筛选结果。

以下任一查询都会先找到与 Snow White 最相似的四部电影,然后将结果筛选为仅 1990 年之后发行的电影。

示例 8. WHERE 和 SEARCH 的顺序不影响结果
WHERE 后面跟着 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 后面跟着 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
结果
标题 year

"Frozen"

2013

"Mulan"

1998

行:2

通常,最好在执行向量搜索的同时进行过滤(即索引内过滤),而不是作为后过滤步骤。这可以通过带过滤器的向量搜索来实现,其中 WHERESEARCH 子句的子句,而不是外层 MATCHOPTIONAL MATCH 子句的子句。

要查找与 Snow White 最相似且于 1990 年后发行的四部电影,请使用以下查询:

示例 9. 带过滤器的向量搜索
查询
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
结果
标题 year

"Frozen"

2013

"Mulan"

1998

"Lilo & Stitch"

2002

"Lion King"

1994

行:4

当使用带过滤器的向量搜索时,向量搜索会持续进行,直到找到符合要求的数量且同时也满足其他谓词的结果。相比之下,在 MATCH 中使用普通的 WHERE 子句可能会导致结果明显减少。因此,您可能需要在 SEARCH 子句中设置更高的 LIMIT,并在 RETURN 中辅以较低的 LIMIT。这种方法称为“过度抓取”(over-fetching)。

结合使用带过滤器的向量搜索和后过滤

可以将带过滤器的向量搜索与普通的 WHERE 子句结合使用。以下查询查找与 Snow White 最相似且于 1990 年后发行的四部电影,然后进行后过滤,丢弃任何评级低于 7.5 的结果。

示例 10. 带过滤器的向量搜索和 WHERE 子句
查询
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
结果
标题 year rating

"Mulan"

1998

7.7

"Lion King"

1994

8.5

行:2

带过滤器的向量搜索的谓词

用于执行带过滤器的向量搜索的可选 WHERE 子句是标准 Cypher WHERE 子句的受限版本,仅允许特定类型的谓词。谓词必须是属性谓词或多个中间用 AND 连接的属性谓词。

示例 11. 在同一属性上使用 AND 谓词的带过滤器的向量搜索
查询
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
结果
标题 year

"Cinderella"

1950

"Mulan"

1998

"Lilo & Stitch"

2002

"Lion King"

1994

行:4

上述查询中的 WHERE 子句也可以写为 WHERE date('1948') < movie.releaseDate < date('2010')

示例 12. 在不同属性上使用 AND 谓词的带过滤器的向量搜索
查询
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
结果
标题 year rating

"Snow White"

1937

7.6

"Mulan"

1998

7.7

"Lion King"

1994

8.5

行:4

如果 SEARCH 子句中的 LIMIT 大于满足谓词的已索引向量的总数,则向量搜索将返回更少的结果。在上面的示例中,尽管 LIMIT 为四,但仅返回了三个节点。由于向量搜索的近似性质,如果 LIMIT 小于但接近满足谓词的已索引向量总数,这种情况也可能发生。

属性谓词中的变量必须与 SEARCH 子句中的绑定变量相同。

示例 13. 不允许 — 属性谓词变量与 SEARCH 子句中的绑定变量不匹配
查询
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
GQLSTATUS 错误链

42I74: 错误: 语法错误或访问规则违规 - 带过滤器的向量搜索变量错误。向量搜索过滤器属性谓词中的变量 m 必须与搜索子句绑定变量 movie 相同。

42001:错误:语法错误或访问规则冲突 - 无效语法

属性谓词中的所有属性都必须在创建向量索引时被添加为用于过滤的附加属性。

示例 14. 不允许 — 属性谓词的属性未在向量索引中定义为附加属性
查询
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
GQLSTATUS 错误链

22ND3: 错误: 数据异常 - 带过滤器的向量搜索属性错误。属性 title 不是向量索引 moviePlots 上用于带过滤器的向量搜索的附加属性。

有关 WHERE 谓词的进一步限制,请参阅WHERE 谓词的限制

使用不同维度的查询向量

如果查询向量的维度与配置的向量索引维度不同,则查询将失败。

示例 15. 不允许 — 当使用三个维度时,查询向量只有两个维度
查询
MATCH (movie:Movie)
  SEARCH movie IN (
    VECTOR INDEX moviePlots
    FOR vector([1, 2], 2, INTEGER)
    LIMIT 4
  )
RETURN movie.title AS title
GQLSTATUS 错误链

51N65: 错误: 系统配置或操作异常 - 向量索引维度不匹配。向量索引 moviePlots 的配置维度为 3,但提供的向量维度为 2。

如果向量索引没有配置维度,则查询成功。但是,如果索引中没有与查询向量维度相同的向量,则查询结果将为空。因此,建议在创建向量索引时配置 vector.dimensions

使用计算结果为 null 的查询向量

如果查询向量的计算结果为 null(例如因为它引用了不存在的属性),则 MATCH 内的 SEARCH 子句不返回任何结果。

示例 16. 计算结果为 null 的查询向量
查询
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
结果
标题

行数:0

如果带有计算结果为 null 的查询向量的 SEARCH 子句位于 OPTIONAL MATCH 子句中,则它根据常规 OPTIONAL MATCH 语义返回 null

示例 17. 根据常规 OPTIONAL MATCH 语义计算结果为 null 的查询向量
查询
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
结果
标题

null

行:1

使用非外层子句的绑定变量

SEARCH 子句中的绑定变量必须是来自外层 MATCHOPTIONAL MATCH 子句模式中的节点或关系变量。尝试引用查询中较早子句的变量或引入新变量将导致查询失败。

示例 18. 不允许 — 来自较早子句的绑定变量
查询
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
GQLSTATUS 错误链

42I69: 错误: 语法错误或访问规则违规 - 无效的搜索变量引用。movie 必须引用同一个 MATCH 语句中的变量。

42001:错误:语法错误或访问规则冲突 - 无效语法

示例 19. 不允许 — 未预先定义的绑定变量
查询
MATCH (movie:Movie)
  SEARCH node IN (
    VECTOR INDEX moviePlots
    FOR vector([1, 2, 3], 3, INTEGER)
    LIMIT 4
  )
RETURN movie.title AS title
GQLSTATUS 错误链

42N62: 错误: 语法错误或访问规则违规 - 变量未定义。变量 node 未定义。

42001:错误:语法错误或访问规则冲突 - 无效语法

SEARCH 子句的限制

下表列出了 SEARCH 子句的一些过去和现在的限制。如果适用,还列出了解除限制的版本。

SEARCH 子句对外层 MATCHOPTIONAL MATCH 子句的模式施加了限制。

MATCH 或 OPTIONAL MATCH 模式的限制
限制 不允许的示例 解除限制版本

模式不能有多个绑定变量。

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

模式不能对绑定变量以外的元素设置谓词。

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

模式长度不能超过一个关系跳数。

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

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

模式不能有多个部分。

MATCH (movie:Movie), ()

模式不能有除 ALL 以外的路径选择器。

MATCH ANY 2 (movie: Movie)

用于执行带过滤器的向量搜索的可选 WHERE 子句是标准 Cypher WHERE 子句的受限版本,仅允许特定类型的属性谓词。

WHERE 谓词的限制
限制 不允许的示例 解除限制版本

谓词中的比较运算符不能是 <>

WHERE movie.rating <> 7.5

谓词不能包含除 AND 以外的其他布尔运算符

WHERE NOT movie.rating > 8 [2]

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

谓词不能包含列表运算符

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

谓词不能包含字符串运算符

WHERE movie.rating STARTS WITH '8'

谓词不能包含类型谓词表达式

WHERE movie.rating IS :: FLOAT

谓词中的表达式不能是 POINT 类型。

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

谓词中的表达式不能是 VECTOR 类型。

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

谓词中的表达式不能是 LIST 类型。

WHERE movie.rating < [8, 8.5]

谓词中的表达式不允许引用绑定变量。

WHERE movie.rating > movie.title

谓词不能在同一方向上对同一属性包含多个属性谓词。

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

谓词不能对同一属性包含多个属性谓词,其中一个是相等性,另一个是范围谓词。

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

2. NOT 允许用于布尔属性。例如,鉴于 seen 在创建向量索引时已被添加为用于过滤的附加属性,WHERE NOT movie.seen 是允许的,并且内部将重写为 WHERE movie.seen = false
SEARCH 子句的其他限制
限制 解除限制版本

与其他索引命令(如 CREATE VECTOR INDEXDROP INDEX)不同,索引名称在 SEARCHVECTOR INDEX 子句中不允许作为参数。

查询向量不允许引用绑定变量。

不允许
MATCH (movie:Movie)
  SEARCH movie IN (
    VECTOR INDEX moviePlots
    FOR movie.embedding
    LIMIT 4
  )
RETURN movie.title AS title
GQLSTATUS 错误链

42I75: 错误: 语法错误或访问规则违规 - 向量搜索中的自引用。搜索子句中的表达式 'movie.embedding' 不得依赖于搜索子句绑定变量 movie

42001:错误:语法错误或访问规则冲突 - 无效语法


1. 2147483647 是来自 Java 的 Integer.MAX_VALUE