Neo4j系列导航:


1.简介

节点矢量搜索索引在Neo4j 5.11中作为公测版本发布,在Neo4j 5.13中作为通用版本发布。
向量索引允许用户从大型数据集查询向量嵌入。嵌入是数据对象(如文本、图像、音频或文档)的数字表示。

例如,文本中的每个单词或标记通常表示为高维向量,其中每个维表示单词含义的某个方面。语义上相似或相关的词通常用向量空间中彼此更接近的向量来表示。这允许像加法和减法这样的数学运算带有语义意义。例如,“国王”减去“男人”加上“女人”的向量表示可能接近于“女王”的向量表示。换句话说,向量嵌入可以说是特定数据对象的数字表示,捕获其语义。

特定数据对象的嵌入可以通过例如Vertex AIOpenAI嵌入生成器生成,它们可以生成维度为256、768、1536和3072的向量嵌入。这些向量嵌入存储为节点上的LIST<INTEGER | FLOAT>属性,其中向量的每个维度组件都是LIST中的一个元素。Neo4j矢量索引可以通过LIST<INTEGER | FLOAT>属性对索引有效来索引节点。

在Neo4j中,矢量索引允许您根据节点属性与查询中指定的节点属性之间的相似性编写匹配节点邻域的查询。
Neo4j矢量索引由Apache Lucene索引和搜索库提供支持。Lucene实现了一个分层可导航的小世界(HNSW)图,在向量域上执行k个近似最近邻(k- ann)查询。

2.向量索引命令和程序

矢量索引通过Cypher®命令和内置程序进行管理,详情请参阅操作手册。向量索引的步骤和命令:

使用

命令/程序

描述

创建节点向量索引

CREATE VECTOR INDEX ...

使用给定的相似度函数,为具有给定向量维数的指定标签和属性创建向量索引,详 情请参照:db.index.vector.createNodeIndex 5.15版引入

创建关系向量索引

CREATE VECTOR INDEX ...

使用给定的相似性函数,为具有给定向量维数的指定关系类型和属性创建关系向量索引。有关详细信息,请参见CREATE INDEX命令。 5.18版引入

创建向量索引

db.index.vector.createNodeIndex

它被CREATE VECTOR INDEX…取代。

使用节点向量索引

db.index.vector.queryNodes

查询给定节点向量索引。返回请求的最近邻节点的近似个数及其相似度分数,按分数排序。

使用关系向量索引

db.index.vector.queryRelationships

查询给定的关系向量索引。返回请求的近似最近邻关系的数目及其相似度分数,按分数排序。5.18版引入

删除向量索引

DROP INDEX index_name

删除指定索引,详情请参照drop index命令

列出所有向量索引

SHOW VECTOR INDEXES

列出所有矢量索引,详情请参照show index命令 5.15版引入

设置节点向量属性

db.create.setNodeVectorProperty

以比直接使用SET命令更节省空间的方式用给定向量更新给定节点属性。取代db.create.setVectorProperty 5.13版引入

设置节点向量属性

db.create.setVectorProperty

db.create.setNodeVectorProperty取代

设置关系向量属性

db.create.setRelationshipVectorProperty

以比直接使用SET更节省空间的方式用给定的向量更新给定的关系属性 5.18版引入

3.创建和配置向量索引

create vector index命令用来创建向量索引

  • 在创建索引时,可以为索引指定一个惟一的名称(或者生成一个名称),用于在查询或删除索引时引用特定的索引。
  • 创建矢量索引需要create index权限。
  • 该命令可以是幂等的。
  • 索引名在索引和约束中必须是唯一的。
  • 在创建索引时为索引指定一个名称,删除和查询索引都需要这个名称。如果索引没有显式命名,它将获得一个自动生成的名称。
  • 从Neo4j 5.16开始,索引名也可以作为参数给出,CREATE VECTOR index $name FOR…
  • CREATE VECTOR INDEX命令接受一个OPTIONS子句。它有两个部分,indexProviderindexConfig。从Neo4j 5.18开始,有两个可用的索引提供程序,vector-2.0(默认)vector-1.0indexConfig是从STRING值到STRINGINTEGER值的MAP,用于设置特定于索引的配置设置(向量维度和相似性函数)。

向量索引是节点的单标签、单属性索引,或者是关系的单关系类型、单属性索引。一个矢量索引需要配置矢量的维度(包括1到4096之间的INTEGER)和两个矢量之间的相似性度量(不区分大小写的STRING)。

创建矢量索引的语法

命令描述CREATE VECTOR INDEX [index_name] [IF NOT EXISTS] FOR (n:LabelName) ON (n.propertyName) OPTIONS "{" option: value[, ...] "}"在节点上创建矢量索引。选项映射是强制性的,因为在创建矢量索引时必须设置矢量维度和相似性函数CREATE VECTOR INDEX [index_name] [IF NOT EXISTS] FOR ()-”[“r:TYPE_NAME”]”-() ON (r.propertyName)OPTIONS "{" option: value[, ...] "}"创建关系的矢量索引。选项映射是强制性的,因为在创建矢量索引时必须设置矢量维度和相似性函数 5.18版引入

索引中的所有向量必须具有相同的维数。相似度的度量由给定的向量相似度函数确定。这通过相似性评分定义了两个向量彼此之间的相似程度,如何解释向量,以及哪些向量对索引有效。

如果满足以下所有条件,节点或关系将被索引: 否则,不为节点或关系建立索引

  • 节点/关系包含配置的标签/关系类型。
  • 节点/关系包含配置的属性键。
  • 对应的属性值类型为LIST<INTEGER | FLOAT>
  • 各自值的size()与配置的维度相同。
  • 该值是配置的相似度函数的有效向量。

3.1.创建节点矢量索引

例如,假设你有一个研究论文的图表,每篇论文都有一个摘要。你想在你熟悉的报纸附近找到报纸。

(:Title)<--(:Paper)-->(:Abstract)

假设对于每个摘要,您已经使用Open AI的text-embedding-ada-002模型生成了摘要文本的1536-dimensional向量embedding,这个模型表明了余弦相似性。有关更多信息,请参阅OpenAI的官方文档。

可以在嵌入属性上创建余弦节点矢量索引:

CREATE VECTOR INDEX `abstract-embeddings`
FOR (n: Abstract) ON (n.embedding)
OPTIONS {indexConfig: {
 `vector.dimensions`: 1536,
 `vector.similarity_function`: 'cosine'
}}

2.1.创建一个关系向量索引(5.18版引入)

假设您有一个员工和他们的经理的图表,他们本身就是员工。经理们定期审查他们的报告,你希望搜索类似主题和细微差别的审查,以找到优秀的员工。

(:Manager)-[:REVIEWED]->(:Employee)

假设对于每个评论,您已经使用Open AI的文本嵌入-3-large模型的缩短生成了评论文本的256维向量嵌入。这个模型表明了余弦相似性。有关更多信息,请参阅OpenAI的官方文档。

可以在嵌入属性上创建余弦关系向量索引:

CREATE VECTOR INDEX `review-embeddings`
FOR ()-[r:REVIEWED]-() ON (r.embedding)
OPTIONS {indexConfig: {
 `vector.dimensions`: 256,
 `vector.similarity_function`: 'cosine'
}}

3.3.显示向量索引

使用show indexes

SHOW VECTOR INDEXES YIELD name, type, entityType, labelsOrTypes, properties, options

结果:

name

type

entityType

labelsOrTypes

properties

options

“abstract-embeddings”

“VECTOR”

“NODE”

[“Abstract”]

[“embedding”]

{indexProvider: “vector-2.0”, indexConfig: {vector.dimensions: 1536, vector.similarity_function: “cosine”}}

“review-embeddings”

“VECTOR”

“RELATIONSHIP”

[“REVIEWED”]

[“embedding”]

{indexProvider: “vector-2.0”, indexConfig: {vector.dimensions: 256, vector.similarity_function: “cosine”}}

3.4.查询向量索引

可以使用db.index.vector.queryNodes或db.index.vector.queryRelationships过程查询向量索引。

// 使用db.index.vector.queryNodes查询节点向量索引
db.index.vector.queryNodes(indexName :: STRING, numberOfNearestNeighbours :: INTEGER, query :: ANY) :: (node :: NODE, score :: FLOAT)
// 使用db.index.vector.queryRelationships查询关系向量索引
db.index.vector.queryRelationships(indexName :: STRING, numberOfNearestNeighbours :: INTEGER, query :: ANY) :: (relationship :: RELATIONSHIP, score :: FLOAT)
  • indexName (一个STRING)是指要查询的矢量索引的唯一名称。
  • numberofnearestneighbors(一个INTEGER)表示要返回的最近邻居的数目。
  • 查找邻域的查询向量(LIST<INTEGER | FLOAT>)。

这些过程返回节点的邻域或关系及其各自的相似度分数,并按这些分数排序。分数在0到1之间,分数越接近1,索引向量与查询向量越相似

查询节点向量索引:

// 本例以描述向量索引实现的HNSW[2]图结构的论文为例,并尝试查找类似的论文。首先使用MATCH来查找论文,
// 然后在abstract-embeddings索引中查询与查询内容相近的10个摘要。最后,匹配邻居各自的头衔。
MATCH (title:Title)<--(:Paper)-->(abstract:Abstract)
WHERE toLower(title.text) = 'efficient and robust approximate nearest neighbor search using
  hierarchical navigable small world graphs'

CALL db.index.vector.queryNodes('abstract-embeddings', 10, abstract.embedding)
YIELD node AS similarAbstract, score

MATCH (similarAbstract)<--(:Paper)-->(similarTitle:Title)
RETURN similarTitle.text AS title, score

title

score

“Efficient and robust approximate nearest neighbor search using Hierarchical Navigable Small World graphs”

1.0

“Accelerating Large-Scale Graph-based Nearest Neighbor Search on a Computational Storage Platform”

0.9437285661697388

“Nearest Neighbor Search Under Uncertainty”

0.9322342872619629

“Neighbor selection and hitting probability in small-world graphs”

0.9316230416297913

“Towards Similarity Graphs Constructed by Deep Reinforcement Learning”

0.9301378726959229

“A novel approach to study realistic navigations on networks”

0.928106427192688

“Intentional Walks on Scale Free Small Worlds”

0.9274556636810303

“FINGER: Fast Inference for Graph-based Approximate Nearest Neighbor Search”

0.9267876148223877

“Learning to Route in Similarity Graphs”

0.9263730049133301

结果是意料之中的,论文讨论了基于图的最近邻搜索。

与此结果最相似的是查询向量本身,这在使用索引属性查询索引时是可以预料到的。如果查询向量本身不需要,则可以使用WHERE score < 1删除查询向量的等效向量。

查询关系向量索引:

// 这个例子使用一个查询向量来描述评论中的特定主题和细微差别。这个查询向量可以通过使用GenAI集成插件对
// 主题进行编码来获得。然后,您查询评论嵌入索引,查找包含与查询相似主题和细微差别的10条评论的邻域。最
// 后,匹配社区各自的雇员。
CALL db.index.vector.queryRelationships('review-embeddings', 10, $query)
YIELD relationship AS review, score

MATCH ()-[review]->(employee:Employee)
RETURN employee.name AS name, score

4.删除向量索引

命令:DROP INDEX

DROP INDEX `abstract-embeddings`

5.设置向量属性

用于索引的有效向量必须具有IEEE 7541单精度中有限可表示的分量。它们被表示为类型为LIST<INTEGER | FLOAT>的节点上的属性。从Neo4j 5.13开始,您可以使用db.create.setNodeVectorProperty过程在节点上设置矢量属性。它验证输入并将属性设置为IEEE 754单精度值的数组。这个测试过程取代了db.create.setVectorProperty。从Neo4j 5.18开始,您可以使用db.create.setRelationshipVectorProperty过程在关系上设置矢量属性。

db.create.setNodeVectorProperty(node :: NODE, key :: STRING, vector :: ANY)
// 后面废弃
db.create.setVectorProperty(node :: NODE, key :: STRING, vector :: ANY) :: (node :: NODE)

db.create.setRelationshipVectorProperty(relationship :: RELATIONSHIP, key :: STRING, vector :: ANY)

通过匹配节点并使用db.create.setNodeVectorProperty设置其向量属性:

MATCH (n:Node {id: $id})
CALL db.create.setNodeVectorProperty(n, 'propertyKey', $vector)
RETURN n

匹配一个关系并使用db.create.setRelationshipVectorProperty设置它的向量属性:

MATCH ()-[r:Relationship {id: $id}]->()
CALL db.create.setRelationshipVectorProperty(r, 'propertyKey', $vector)
RETURN r

使用set命令在节点上设置向量属性:

MATCH (node:Node {id: $id})
SET node.propertyKey = $vector
RETURN node

Cypher强制并存储提供的LIST<INTEGER | FLOAT>作为IEEE 754双精度值的原始数组。与使用db.create.setNodeVectorProperty过程的替代方法相比,这几乎占用了两倍的空间。因此,不建议对向量索引使用SET。

为了减少存储空间,您可以使用db.create.setNodeVectorProperty重置现有属性。然而,这伴随着事务日志大小增加的成本,直到它们被旋转掉。

6.支持的相似度函数

相似函数的选择影响到哪些索引向量被认为是相似的,哪些是有效的。向量的语义本身可以决定选择哪个相似函数。

名称

不区分大小写参数

关键相似性特征

Euclidean(欧几里得)

“euclidean”

distance

Cosine(余弦)

“cosine”

angle

6.1.Euclidean(欧几里得)相似

  • 当两个向量之间的距离决定了两个向量的相似度时,欧几里得相似度是有用的。
  • 欧几里得向量索引的有效向量是当所有向量分量在IEEE 754单精度中可以有限表示时。
  • 欧几里得用笛卡尔坐标来解释向量。这个度量与欧几里得距离有关,即两点之间的距离。然而,这个距离是无界的,作为相似度评分的用处不大。欧几里得相似边界即欧几里得距离的平方。

6.2.Cosine(余弦)相似度

当两个向量之间的夹角决定了两个向量的相似度时,使用余弦相似度。

余弦向量索引的有效向量是:

  • 在IEEE 754双精度中,所有向量分量都可以有限地表示。
  • 它的12范数是非零的,在IEEE 754[3]双精度中可以有限地表示。
  • 在IEEE 754单精度中,每个矢量分量与其12范数的比值可以有限地表示。

余弦相似度解释了笛卡尔坐标中的向量。度量与两个向量之间的夹角有关。然而,一个角度可以用许多单位、符号约定和句号来描述。这个角的三角余弦与前面提到的角度约定无关,而且有界。余弦相似度反弹三角余弦。

neo4j 给关系添加索引_搜索


在上面的方程中,三角余弦由两个单位向量的标量积给出。

7.矢量索引提供程序的兼容性

从Neo4j 5.18开始,默认和首选的矢量索引提供程序是vector-2.0。之前创建的vector-1.0索引将继续发挥作用。如果指定,仍然可以使用vector-1.0索引提供程序创建新索引

Supported

vector-1.0

vector-2.0

索引模式

节点的单标签、单属性索引。

没有关系支持

节点的单标签、单属性索引

关系的单一类型、单一属性索引

索引属性值类型

LIST<FLOAT>

LIST<INTEGER/FLOAT>

索引向量维数

1到2048之间的整数

1到4096之间的整数

余弦相似向量有效性

在IEEE 754中,所有矢量分量都可以用单精度有限表示;

它的e^2范数是非零的,在IEEE 754单精度中可以有限地表示

在IEEE 754双精度中,所有向量分量都可以有限地表示;

它的e^2范数是非零的,在IEEE 754双精度中可以有限地表示;

在IEEE 754单精度中,每个矢量分量与其e^2范数的比值可以有限地表示

8.局限性和特质

  • 该查询是近似最近邻搜索。请求的k个最近邻可能不是确切的k个最近邻,而是在相同的更宽的邻域中接近,例如找到一个局部极值与真正的极值。
  • 对于大型请求的最近邻k,接近索引向量的总数,搜索可能检索到少于k个结果。
  • 一个模式上只能有一个向量索引。例如,同一个标签属性键对上不能有一个欧几里德矢量索引和一个余弦矢量索引。
  • 没有提供调优索引的设置或选项。
  • 在同一事务中所做的更改对索引不可见。

9.已知的问题

从Neo4j 5.13开始,矢量搜索索引不再是一个测试版功能。
已知问题和测试的版本详见:官方问题及测试修复文档

10.建议

向量索引可以利用孵化的Java 20矢量API来显著提高速度。如果你使用的是兼容的Java版本,你可以在你的配置设置中添加以下设置:

server.jvm.additional=--add-modules jdk.incubator.vector

  1. IEEE浮点运算标准 ↩︎