介绍
该库提供了一些常用的图算法,并内置在cypher过程中。
算法
图算法用于计算图、节点和关系的度量指标。它可以提供图中关联实体(cetralities,ranking)或内在结构(community-detection,graph-partitioning,clustering)等方面的度量。
许多图算法是迭代的方法,通过随机游走、广度优先、深度优先和图匹配遍历图进行计算。由于可能路径随距离增加呈现指数增长,许多方法也具有很高的算法复杂度。幸运的是,利用图形的特定结构,记忆已经存在的部分和并行操作可以对算法进行优化,我们已经对可行的优化加以应用。库中的许多算法在Algorithms章节有详细解释。
图目录
为了尽可能高效地运行这些算法,Neo4j图形数据科学库使用了一种专门的内存图形格式来表示图形数据。因此,有必要将Neo4j数据库中的图形数据加载到内存中的图目录中。加载的数据量可以由所谓的图形投影来控制,它还允许对节点标签和关系类型以及其他选项进行过滤。
版本
The open source Community Edition包含所有算法和特性,但限制在四核cpu上运行。
The Neo4j Graph Data Science library Enterprise Edition:
- 不限制cpu核数量
- 支持基于角色的访问控制系统
- 支持其他各种模型目录功能
- 在模型目录中存储不限数量的模型
- 发布存储模型
- 将存储模型持久化到磁盘
- 支持优化的内存图形实现
安装
Neo4j图形数据科学(GDS)库作为插件提供给Neo4j图形数据库。插件需要安装到数据库中,并在Neo4j配置中列出。实现这一点有两种主要方法,我们将在本章中详细介绍。
支持的Neo4j版本
neo4j-community-4.2.1对应的有效库版本是1.5.x
Neo4j Desktop
安装GDS库最方便的方法是通过Neo4j桌面插件Neo4j Graph Data Science。该插件可以在数据库的“插件”选项卡中找到。
安装程序将下载GDS库并将其安装在数据库的“plugins”目录中。它还会将以下条目添加到设置文件中: dbms.security.procedures.unrestricted=gds.*
这个配置条目是必要的,因为GDS库访问Neo4j的低层组件以最大限度地提高性能。
如果配置了过程白名单,请确保白名单中包括来自GDS库的过程:
dbms.security.procedures.whitelist=gds.*
Neo4j Server
GDS库可在独立的Neo4j服务器上使用。
*不支持在Neo4j因果集群中运行GDS库。
在独立的Neo4j服务器上,需要手动安装和配置库。
1.从Neo4j Download Center下载neo4j-graph-data-science-[version].jar并将其复制到
N
E
O
4
J
H
O
M
E
/
p
l
u
g
i
n
s
目
录
2.
在
NEO4J_HOME/plugins目录 2.在
NEO4JHOME/plugins目录2.在NEO4J_HOME/conf/neo4j.conf 文件中添加配置条件dbms.security.procedures.unrestricted=gds.*
这个配置条目是必要的,因为GDS库访问Neo4j的低层组件以最大限度地提高性能。
3.检查$NEO4J_HOME/conf/neo4j.conf文件中是否启用了过程白名单,必要时添加GDS库:
dbms.security.procedures.whitelist=gds.*
4.重启Neo4j
验证安装
要验证您的安装,可以在Neo4j桌面的浏览器中输入库版本并调用gds.version()功能:
RETURN gds.version()
要列出所有已安装的算法,请运行gds.list()程序:
CALL gds.list()
Enterprise 版本配置
Neo4j Docker
Neo4j Causal Cluster
额外配置选项
为了利用GDS库的某些特性,需要进行额外的配置。在启动DBMS之前,在neo4j.conf配置文件中完成配置。以下功能需要此类附加配置:
- 图形导出
将图形导出到CSV文件需要配置参数gds.export.location 设置为存储导出图形的文件夹的绝对路径。此目录必须由Neo4j进程写入。 - 模型持久性
模型持久性功能需要配置参数gds.model.store_location 设置为存储模型的文件夹的绝对路径。此目录必须由Neo4j进程写入。
系统需求
8.1 主存
GDS库在Neo4j实例中运行,因此受常规Neo4j 存储配置的约束。
8.1.1 堆空间
堆空间用于存储图形目录和算法状态中的图形投影。当将算法结果写回Neo4j时,堆空间也用于处理事务状态(请参阅dbms.tx_state.memory_allocation). 对于纯分析工作负载,一般建议将堆空间设置为可用主内存的90%左右。这可以通过dbms.memory.heap.initial_size 以及dbms.memory.heap.max_size进行设置。
为了更好地估计创建内存图和运行算法所需的堆空间,请使用内存估计功能。该功能使用Neo4j计数存储中有关节点数和关系的信息来估计所有相关数据结构的内存消耗。
8.1.2 页面缓存
页面缓存用于缓存Neo4j数据,有助于避免大量的磁盘访问。
对于使用 native projections的纯分析工作负载,建议减少dbms.memory.pagecache.size 支持以增加堆大小。但是,在创建内存中的图形时,设置最小页缓存大小仍然很重要:
对于native projections,用于创建内存中图形的最小页缓存大小可以粗略估计为8KB100readConcurrency。
对于Cypher projections,需要更高的页缓存,这取决于查询的复杂性。
然而,如果需要将算法结果写回Neo4j,那么写性能在很大程度上取决于存储碎片以及要写的属性和关系的数量。我们建议从大约250MB*writeConcurrency的页缓存开始,评估写性能并相应地进行调整。理想情况下,如果已经使用内存估计功能来找到一个好的堆大小,那么剩余的内存可以用于页缓存和操作系统。
*如果Neo4j实例同时运行操作和分析工作负载,则不建议减少页缓存大小以支持堆大小。请参阅Neo4j memory configuration,了解有关页面缓存大小的一般信息。
8.2 CPU
该库使用多个CPU核进行图形投影、算法计算和结果编写。配置工作负载以充分利用系统中可用的CPU内核对于实现最高性能非常重要。用于投影、计算和写入阶段的并发性是按算法执行配置的,请参阅Common Configuration parameters
可使用的最大并发性是受限的,具体取决于使用库的许可证:
Neo4j社区版库中的最大并发数为4。
Neo4j企业版库中的最大并发数为4。
Neo4j图形数据科学库-企业版库中的并发是无限的。要注册许可证,请联系Neo4jhttps://neo4j.com/contact-us/?ref=graph-analytics.
常见使用模式
本章解释了构成Neo4j图形数据科学库核心的常见使用模式和操作。
GDS库使用模式通常分为两个阶段:development和production。
在development阶段,目标是建立一个有用算法的工作流。为此,必须对系统进行配置,定义图形投影,并选择算法。典型操作是利用库的内存估计特性。这使您能够成功地配置系统以处理要处理的数据量。有两种资源需要记住:内存图和算法数据结构。
在production阶段,将对系统进行适当配置,以成功运行所需的算法。操作的顺序通常是创建一个图,对其运行一个或多个算法,并使用其结果。
下图概述了GDS库的标准操作:
有关每个单独操作的更多详细信息,请参见相应部分:
Graph Catalog
Creating graphs
Running algorithms
在本章中,我们将介绍这些方面,并指导您进行有用的操作。本章分为以下几节:
Memory Estimation
Creating graphs
Running algorithms
内存估计
本节介绍如何估计Neo4j图形数据科学库使用的投影图形模型的内存需求。
图形算法库完全在堆上运行,这意味着我们对Neo4j服务器配置的堆大小应比事务性工作负载所需堆大小更大。下图显示了投影图模型如何使用内存:
模型包含三种类型的数据:
节点ID-最多2的45次方(35万亿)
关系-成对的节点ID。如果不使用orientation:“UNDIRECTED”,关系将存储两次。
权重-以double形式(每个节点8字节)存储在关系旁边的类似数组的数据结构中。
内存配置取决于我们使用的图形投影。
1.估计运行算法所需的内存
在许多用例中,为了确保工作负载可以在可用的硬件上运行,在运行图和算法之前估计所需的内存是很有用的。为了简化此过程,每个算法都支持.estimate模式,该模式返回运行图形算法所需的内存量的估计值。
CALL gds.<ALGO>.<MODE>.estimate(graphNameOrConfig: String|Map, configuration: Map)
YIELD requiredMemory, treeView, mapView, bytesMin, bytesMax, heapPercentageMin, heapPercentageMax, nodeCount, relationshipCount
表1. 参数
名称 | 类型 | 默认 | 是否可选 | 描述 |
---|---|---|---|---|
graphNameOrConfig | String or Map | - | no | 在隐式加载的情况下,投影图的名称或算法配置 |
configuration | Map | {} | yes | 如果第一个参数是投影图的名称,则此参数是算法配置,否则需要为null或空映射 |
表2.结果
名称 | 类型 | 描述 |
---|---|---|
requiredMemory | String | 以可读格式返回的对所需内存的估计 |
treeView | String | 对所需内存的更详细的、可读的表示,包括对不同组成项的估计 |
mapView | String | 对所需内存的更详细的表示,包括对不同组成项的估计 |
bytesMin | Integer | 所需的最小字节数 |
bytesMax | Integer | 所需的最大字节数 |
heapPercentageMin | Float | 所需配置的最大堆的最小百分比 |
heapPercentageMax | Float | 所需配置的最大堆的最大百分比 |
nodeCount | Integer | 图中节点数的估计值 |
relationshipCount | Integer | 图中关系数的估计值 |
2.估计构建图所需的内存
gds.graph.create
过程也支持.estimate
来估计图的内存使用量。这些过程不接受图形名称作为第一个参数,因为它们实际上并不创建图形。
CALL gds.graph.create.estimate(nodeProjection: String|List|Map, relationshipProjection: String|List|Map, configuration: Map})
YIELD requiredMemory, treeView, mapView, bytesMin, bytesMax, heapPercentageMin, heapPercentageMax, nodeCount, relationshipCount
表3. 参数
名称 | 类型 | 默认 | 是否可选 | 描述 |
---|---|---|---|---|
nodeProjection | String or List or Map | - | no | 要估计的节点投影 |
relationshipProjection | String or List or Map | - | no | 要估计的关系投影 |
configuration | Map | {} | yes | 额外的配置,例如并发 |
运行gds.graph.create.estimate 的结果具有与上述算法内存估计结果相同的形式。
通过显式指定虚拟图的节点和关系计数,还可以估计虚拟图的内存。利用这个特性,可以估计任意大小的图的内存消耗。
为此,请使用以下配置选项:
表4. 配置
名称 | 类型 | 默认 | 是否可选 | 描述 |
---|---|---|---|---|
nodeCount | Integer | 0 | yes | 虚拟图中的节点数 |
relationshipCount | Integer | 0 | yes | 虚拟图中的关系数 |
在估计虚拟图时,必须指定语法上有效的nodeProjection和relationshipProjection。但是,建议在虚拟图形情况下为这两个都指定“*”,因为这不会干扰上面指定的值。
下面的查询是一个估计具有100个节点和1000个关系的虚拟图的示例。
CALL gds.graph.create.estimate('*', '*', {
nodeCount: 100,
relationshipCount: 1000,
nodeProperties: 'foo',
relationshipProperties: 'bar'
})
YIELD requiredMemory, treeView, mapView, bytesMin, bytesMax, nodeCount, relationshipCount
表5. 结果
requiredMemory | bytesMin | bytesMax | nodeCount | relationshipCount |
---|---|---|---|---|
“593 KiB” | 607576 | 607576 | 100 | 1000 |
gds.graph.create.cypher
过程必须同时执行nodeQuery和relationshipQuery,以便计算图的节点数和关系数。
CALL gds.graph.create.cypher.estimate(nodeQuery: String, relationshipQuery: String, configuration: Map})
YIELD requiredMemory, treeView, mapView, bytesMin, bytesMax, heapPercentageMin, heapPercentageMax, nodeCount, relationshipCount
名称 | 类型 | 默认 | 是否可选 | 描述 |
---|---|---|---|---|
nodeQuery | String | - | no | 要估计的节点查询语句 |
relationshipProjection | String or List or Map | - | no | 要估计的关系查询语句 |
configuration | Map | {} | yes | 额外的配置,例如并发 |
自动估计和执行阻塞
GDS库中的所有算法过程(包括图形创建)都将在执行开始时进行估计检查。这包括所有执行模式,但不包括估计过程本身。
如果估计检查可以确定当前可用内存量不足以执行该操作,则该操作将被中止并报告错误。误差将包含估计的细节和估计时的可用内存。
这个堆控制逻辑是有限制的,因为它只阻止那些确定不适合内存的执行。它不能保证通过堆控制的执行在不耗尽内存的情况下成功。因此,在对大数据集运行算法或图形创建之前,首先运行估计模式仍然有用,以便查看估计的所有细节。
所考虑的可用内存基于Java运行时系统信息。通过从目录中删除未使用的图,或者在启动Neo4j实例之前增加最大堆大小,可以增加可用内存量。
创建图
本节讨论如何在Neo4j图形数据科学库中创建用于算法计算的命名图和匿名图。
为了运行GDS库中的任何算法,我们必须首先创建一个要在其上运行的图。该图创建为匿名图或命名图。单个算法将创建一个匿名图,并且在其执行完成后将丢失。命名图将被赋予一个名称并存储在图目录中。有关所有图形目录操作的详细指南,请参见图形目录。
创建命名图有几个优点:
- 它可以被多种算法使用
- 创建与算法执行完全分离
- 算法运行时间可以单独测量
- 可从图形目录检索用于创建图形的配置
使用匿名图的优点是单个查询可以用于整个算法计算。在开发阶段,当工作流正在建立并且图形投影正在进行实验时,这可能特别有用。
运行算法
本节介绍算法的常见执行模式:stream, stats, mutate, write.
所有算法都公开为Neo4j程序。它们可以使用Neo4j浏览器、Cypher shell直接从Cypher调用,也可以使用Neo4j驱动程序以您选择的语言从客户机代码调用。
有关运行算法的语法的详细指南,请参阅语法概述部分。简而言之,算法是使用stream、stats、mutate或write执行模式之一运行的,我们将在本章介绍这些模式。
任何算法的执行都可以通过终止正在执行过程调用的Cypher事务来取消。有关如何使用事务的更多信息,请参阅事务处理。
Stream
stream模式将算法计算的结果作为Cypher结果行返回。这类似于标准Cypher读取查询的操作方式。
返回的数据可以是节点ID和节点的计算值(例如Page Rank得分或WCC componentId),或者两个节点ID和节点对的计算值(例如节点相似性得分)。
如果图形非常大,流模式计算的结果也将非常大。在Cypher查询中使用orderby和LIMIT子类对于支持“top N”样式的用例可能很有用。
Stats
stats模式返回算法计算的统计结果,如计数或百分比分布。计算的统计摘要作为单个Cypher结果行返回。当使用stats模式时,该算法的直接结果不可用。此模式构成了mutate和write执行模式的基础,但不会尝试在任何地方进行任何修改或更新。
Mutate
mutate模式将把算法计算的结果写回内存图。请注意,指定的mutateProperty值不能预先存在于内存中的图形中。这样就可以在同一内存图上运行多个算法,而无需在算法执行之间将结果写入Neo4j。
此执行模式在以下三种情况下特别有用:
- 算法可以依赖于以前算法的结果,而无需写入Neo4j。
- 可以一起写入算法结果(请参见write node properties和write
relationships)。 - 算法结果可以通过Cypher查询,而无需写入Neo4j(参见gds.util.nodeProperty).
返回的计算统计摘要类似于stats模式。mutate数据可以是节点属性(如页面排名分数)、新关系(如节点相似性)或关系属性。
Write
write模式将算法计算的结果写回Neo4j数据库。这类似于标准Cypher编写查询的操作方式。返回的计算统计摘要类似于stats模式。这是唯一尝试修改Neo4j数据库的执行模式。
写入的数据可以是节点属性(如页面排名分数)、新关系(如节点相似性)或关系属性。对于算法结果将由单独的查询多次检查的用例,write模式非常有用,因为计算结果完全由库处理。
为了使写入模式计算的结果被另一个算法使用,必须从Neo4j数据库中创建一个新的图形,其中包含更新后的图形。
常用配置参数
所有算法都允许通过一组配置参数来调整它们的运行时特性。尽管有些参数是特定于算法的,但许多参数是在算法和执行模式之间共享的。
要了解有关特定算法参数的更多信息,并了解某个算法是否支持某个参数,请参阅特定算法文档页。
最常用的配置参数列表
concurrency - Integer 并发-整数
控制执行算法的并行性。默认情况下,此值设置为4。有关并发设置和限制的更多详细信息,请参阅系统要求的CPU部分。
relationshipTypes - String[] 关系类型-字符串[]
如果运行算法的图形是使用多个关系类型投影创建的,则此参数只能用于选择投影类型的子集。该算法将只考虑与选定类型的关系。
nodeWeightProperty - String
在支持节点权重的算法中,此参数定义包含权重的节点属性。
relationshipWeightProperty - String
在支持关系权重的算法中,此参数定义包含权重的关系属性。
maxIterations - Integer
对于迭代算法,此参数控制最大迭代次数。
tolerance - Float 公差-浮点数
许多迭代算法都接受公差参数。它控制两次迭代之间的最小增量。如果增量小于公差值,则认为算法收敛并停止。
seedProperty - String
有些算法可以增量计算。这意味着可以考虑以前执行的结果,即使图形已更改。seedProperty参数定义包含种子值的节点属性。种子可以加速计算和写入时间。
writeProperty - String
在写入模式下,此参数设置将结果写入的节点或关系属性的名称。如果属性已存在,则现有值将被覆盖。
writeConcurrency - Integer
在写入模式下,此参数控制写入操作的并行性。默认值是concurrency。
图管理
本章介绍了Neo4j图形数据科学库中的图形目录、不同的图形投影变体和实用函数。
GDS库中的一个中心概念是内存中图形的管理。
图目录
- 在目录中创建图
- 列举目录中的图
2.1. 例子 - 检查目录中是否有图存在
- 从命名图中移除节点属性
- 从命名图中删除关系种类
- 从目录中移除图
- Stream 节点属性
- Stream 关系属性
- 将节点属性写入neo4j
9.1. 语法
9.2. 例子 - 将关系写入neo4j
- 根据命名图创建Neo4j数据库
- 将一个命名图导出为csv
12.1. 导出格式
12.2. 估计
本节详细介绍了可用于管理Neo4j图形数据科学库中的命名图形投影的图形目录操作。
图形算法运行在图形数据模型上,该模型是Neo4j属性图形数据模型的投影。图投影可以看作是存储图上的视图,仅包含分析相关的、潜在聚合的拓扑和属性信息。图形投影使用为拓扑和属性查找操作优化的压缩数据结构并完全存储在内存中。
图形目录是GDS库中的一个概念,它允许按名称管理多个图形投影。使用其名称,创建的图形可以在分析工作流中多次使用。命名图可以使用本机投影或Cypher投影创建。使用后,可以从目录中删除命名图以释放主内存。
也可以在运行算法时创建图形,而不将它们放在目录中。我们把这种图称为匿名图。
只要Neo4j实例正在运行,图表目录就存在。当Neo4j重新启动时,目录中存储的图形将丢失,需要重新创建。
本章介绍可用的图形目录操作。
名称 | 描述 |
---|---|
gds.graph.create | 使用本地投影在目录中创建图 |
gds.graph.create.cypher | 使用Cypher投影在目录中创建图 |
gds.graph.list | 打印目前存储在目录中的图信息 |
gds.graph.exists | 检查某个命名图是否存储在目录中 |
gds.graph.removeNodeProperties | 从一个命名图中移除节点属性 |
gds.graph.deleteRelationships | 根据给定的关系类型从一个命名图中删除关系 |
gds.graph.drop | 从目录中移除一个命名图 |
gds.graph.streamNodeProperty | Streams一个存储在命名图中的节点属性 |
gds.graph.streamNodeProperties | Streams多个存储在命名图中的节点属性 |
gds.graph.streamRelationshipProperty | Streams一个存储在命名图中的关系属性 |
gds.graph.streamRelationshipProperties | Streams多个存储在命名图中的关系属性 |
gds.graph.writeNodeProperties | 将存储在命名图中的节点属性写入Neo4j |
gds.graph.writeRelationship | 将存储在命名图中的关系写入Neo4j |
gds.graph.export | 将命名图导出到新的离线Neo4j数据库 |
gds.beta.graph.export.csv | 将命名图导出到csv文件 |
1.在目录中创建图
投影图形可以以用户定义的名称存储在目录中。使用该名称,库中的任何算法都可以引用该图。这允许多个算法使用同一个图,而不必在每次算法运行时重新创建它。
有两种将图形从Neo4j数据库投影到主内存的方法:
- Native projection 通过读取Neo4j存储文件提供最佳性能。建议在开发和生产阶段使用。
- Cypher projection 更灵活、更富有表现力的方法,对性能的关注较少。建议主要在开发阶段使用。
还有一种生成随机图的方法,有关详细信息,请参阅Graph Generation文档。
在本节中,我们将给出如何使用任一变量创建图的简单示例。有关每个变量配置的详细信息,请参阅专用部分。
在下面的两个示例中,我们将演示如何创建一个名为my native graph的图,其中包含Person节点和LIKES关系。
CALL gds.graph.create(
'my-native-graph',
'Person',
'LIKES'
)
YIELD graphName, nodeCount, relationshipCount, createMillis;
我们还可以使用Cypher来选择要投影到内存图中的节点和关系。
CALL gds.graph.create.cypher(
'my-cypher-graph',
'MATCH (n:Person) RETURN id(n) AS id',
'MATCH (a:Person)-[:LIKES]->(b:Person) RETURN id(a) AS source, id(b) AS target'
)
YIELD graphName, nodeCount, relationshipCount, createMillis;
在目录中创建图之后,我们可以使用它们的名称在算法中引用它们。
CALL gds.pageRank.stream('my-native-graph') YIELD nodeId, score;
2.列举目录中的图
有关目录中图的信息可以使用gds.graph.list()过程。该过程采用可选参数graphName:
- 如果给定了图名称,则仅列出该图形的信息。
- 如果没有给出图名称,则会列出有关所有图形的信息。
- 如果给定了图名称但在目录中找不到,则会引发错误。
CALL gds.graph.list(
graphName: String?
) YIELD
graphName,
database,
nodeProjection,
relationshipProjection,
nodeQuery,
relationshipQuery,
nodeCount,
relationshipCount,
schema,
degreeDistribution,
density,
creationTime,
modificationTime,
sizeInBytes,
memoryUsage;
表1.结果
名称 | 类型 | 描述 |
---|---|---|
graphName | String | 图名称 |
database | String | 创建图的数据库名称 |
nodeProjection | Map | 用于创建图的节点投影 如果使用cypher投影,那么这将是一个派生的关系投影 |
nodeQuery | String | 用于创建图的节点查询 如果使用本地投影,该值应为null |
relationshipQuery | String | 用于创建图的关系查询 如果使用本地投影,该值应为null |
nodeCount | Integer | 图中的节点数量 |
relationshipCount | Integer | 图中的关系数量 |
schema | Map | 内存图中包含的节点标签、关系类型和属性 |
degreeDistribution | Map | 图中度数的直方图 |
density | Float | 图密度 |
creationTime | Datetime | 图创建的时间 |
modificationTime | Datetime | 图最后修改的时间 |
sizeInBytes | Integer | 堆中用于存储图的比特数 |
memoryUsage | String | 对sizeInBytes的可读描述 |
该信息包含有关图形的基本统计信息,例如,节点和关系计数。结果字段creationTime指示在内存中创建图形的时间。结果字段modificationTime指示在mutate模式下运行的算法何时更新图形。
数据库列是指已在其上创建相应图形的数据库的名称。在过程中引用命名图只能在创建它的数据库上使用。
schema包含有关存储在图中的节点和关系的信息。对于每个节点标签,架构将标签映射到其属性键及其相应的属性类型。类似地,模式将关系类型映射到它们的属性键和属性类型。属性类型可以是Integer、Float、List of Integer或List of Float。
对于较大的图,degreedDistribution字段的计算可能相当耗时。它的计算是按图缓存的,因此同一个图的后续列表将很快。为了避免计算度分布,请指定一个省略它的YIELD子句。注意,不指定YIELD子句等同于请求返回所有可能的返回字段。
density是relationshipCount除以具有给定nodeCount的简单图的最大关系数的结果。
2.1. 例子
列出目录中所有图的基本信息:
CALL gds.graph.list()
YIELD graphName, nodeCount, relationshipCount, schema;
列出目录中指定图的详细信息:
CALL gds.graph.list('my-cypher-graph')
YIELD graphName, nodeQuery, relationshipQuery, nodeCount, relationshipCount, schema, creationTime, modificationTime, memoryUsage;
列出目录中指定图的所有信息:
CALL gds.graph.list('my-native-graph')
列出指定图的度分布信息:
CALL gds.graph.list('my-cypher-graph')
YIELD graphName, degreeDistribution;
3.检查目录中是否有图存在
我们可以通过查找图名称来确定它是否存储在目录中。
CALL gds.graph.exists('my-store-graph') YIELD exists;
4.从命名图中移除节点属性
我们可以从目录中的命名图中删除节点属性。这对于释放主内存或删除意外创建的节点属性非常有用。
从命名图中移除多个节点属性:
CALL gds.graph.removeNodeProperties('my-graph', ['pageRank', 'communityId'])
上面的示例要求所有给定的属性至少出现在一个节点投影上,并且这些属性将从所有此类投影中移除。
可以将该过程配置为仅删除某些特定节点投影的属性。在下面的示例中,我们在子图上运行了一个算法,然后删除了新创建的属性。
从特定的节点投影上移除节点属性:
//参数为图名称,节点,关系
CALL gds.graph.create('my-graph', ['A', 'B'], '*')
//使用wcc算法,为A节点创建属性componentId
CALL gds.wcc.mutate('my-graph', {nodeLabels: ['A'], mutateProperty: 'componentId'})
//移除A节点上的属性componentId
CALL gds.graph.removeNodeProperties('my-graph', ['componentId'], ['A'])
当指定了不为的投影列表时,如上例所示,应用不同的验证和执行;要求所有投影都具有所有给定的属性,并且它们将从所有投影中移除。
如果给定的任何投影是’’,则该过程的行为与第一个示例类似。
5.从命名图中删除关系类型
我们可以从目录中的命名图中删除给定类型的所有关系。这对于释放主内存或删除意外创建的关系类型非常有用。
删除命名图中所有T类型的关系:
CALL gds.graph.deleteRelationships('my-graph', 'T')
YIELD graphName, relationshipType, deletedRelationships, deletedProperties
6.从目录中移除图
一旦使用完命名图,我们就可以将其从目录中删除以释放内存。
CALL gds.graph.drop('my-store-graph') YIELD graphName;
如果我们希望该过程在不存在的图上以不报错的方式失败,那么可以将布尔标志设置为false作为第二个参数。对于不存在的图,这将产生一个空结果。
CALL gds.graph.drop('my-fictive-graph', false) YIELD graphName;
7.Stream节点属性
我们可以将存储在内存中的命名图中的节点属性流式传输回用户。如果我们在mutate模式下运行多个算法并希望检索部分或全部结果,那么这将非常有用。这与流执行模式类似,但允许对操作进行更细粒度的控制。
stream多个节点属性:
CALL gds.graph.streamNodeProperties('my-graph', ['componentId', 'pageRank', 'communityId'])
上面的示例要求所有给定的属性至少出现在一个节点投影上,并且这些属性将为所有此类投影stream。
可以将该过程配置为仅stream某些特定节点投影的属性。在下面的示例中,我们在一个子图上运行了一个算法,然后将新创建的属性stream。
在特定节点投影上stream节点属性:
CALL gds.graph.create('my-graph', ['A', 'B'], '*')
CALL gds.wcc.mutate('my-graph', {nodeLabels: ['A'], mutateProperty: 'componentId'})
CALL gds.graph.streamNodeProperties('my-graph', ['componentId'], ['A'])
当指定了非的投影列表时,如上例所示,将应用不同的验证和执行。然后要求所有投影都具有所有给定的属性,并且它们将为所有投影流化。
如果给定的任何投影是’’,则该过程的行为与第一个示例类似。
流式处理多个节点属性时,每个属性的名称都包含在结果中。这会增加一些开销,因为每个属性名称必须对结果中的每个节点重复,但为了区分属性是必需的。对于流式传输单个节点属性,这不是必需的。gds.graph.streamNodeProperty()
从内存中的图形流式处理单个节点属性,并忽略属性名称。结果的格式为nodeId,propertyValue,这是许多算法程序的流模式所熟悉的。
stream一个单独的节点属性:
CALL gds.graph.streamNodeProperty('my-graph', 'componentId')
8.Stream关系属性
我们可以将存储在内存中的命名图中的关系属性stream返回用户。如果我们在mutate模式下运行多个算法并希望检索部分或全部结果,那么这将非常有用。这与stream模式类似,但允许对操作进行更细粒度的控制。
stream多个关系属性:
CALL gds.graph.streamRelationshipProperties('my-graph', ['similarityScore', 'weight'])
可以将该过程配置为仅stream某些特定关系投影的属性。在下面的示例中,我们在一个子图上运行了一个算法,然后将新创建的属性stream。
stream特定关系投影的关系属性
CALL gds.graph.create('my-graph', ['*'], [A', 'B'])
CALL gds.nodeSimiliarity.mutate('my-graph', {relationshipTypes: ['A'], mutateRelationshipType: 'R', mutateProperty: 'similarityScore'})
CALL gds.graph.streamNodeProperties('my-graph', ['similarityScore'], ['R'])
当指定了非的投影列表时,如上例所示,将应用不同的验证和执行。然后要求所有投影都具有所有给定的属性,并且它们将为所有投影stream。
如果给定的任何投影是’’,则该过程的行为与第一个示例类似。
当流式处理多个关系属性时,结果中包括关系类型和每个属性的名称。这增加了一些开销,因为每个类型名和属性名必须为结果中的每个关系重复,但为了区分属性是必需的。对于流式传输单个关系属性,可以省略属性名称。gds.graph.streamNodeProperty()
从内存中的图形流式处理单个关系属性,并忽略属性名称。结果的格式为sourceNodeId、targetNodeId、relationshipType和propertyValue。
stream单个关系属性:
CALL gds.graph.streamRelationshipProperty('my-graph', 'similarityScore')
9.将节点属性写入neo4j
与存储在内存图形中的流属性类似,也可以将这些属性写回Neo4j。这与写执行模式类似,但允许对操作进行更细粒度的控制。
要写入的属性通常是运行算法时使用的mutateProperty值。在创建时添加到已创建图形的属性通常已经存在于Neo4j数据库中。
9.1. 语法
CALL gds.graph.writeNodeProperties(
graphName: String,
nodeProperties: List<String>,
nodeLabels: List<String>,
configuration: Map
) YIELD
graphName: String,
nodeProperties: List<String>,
writeMillis: Integer,
propertiesWritten: Integer
表2. 参数
名称 | 类型 | 默认 | 是否可选 | 描述 |
---|---|---|---|---|
graphName | String | n/a | no | 存储在目录中的图名称 |
nodeProperties | List | n/a | no | 要写入的属性名 |
nodeLabels | List | [’*’] | yes | 要写入属性的节点标签名 |
configuration | Map | {} | yes | 算法细节和/或图形过滤的配置 |
表3. 配置参数
名称 | 类型 | 默认 | 是否可选 | 描述 |
---|---|---|---|---|
concurrency | Integer | 4 | yes | 用于将属性写入Neo4j的并发线程数 |
writeConcurrency | Integer | value of ‘concurrency’ | yes | 用于将属性写入Neo4j的并发线程数。如果同时指定了writeConcurrency和concurrency,则将使用writeConcurrency |
表4. 结果
名称 | 类型 | 描述 |
---|---|---|
graphName | String | 图名称 |
nodeProperties | List | 写入属性名称 |
writeMillis | Integer | 将属性写入Neo4j所需毫秒数 |
propertiesWritten | Integer | 写入的属性数 |
9.2. 例子
要使用8个并发线程为图形“my graph”中的所有节点投影编写属性“componentId”、“pageRank”、“communityId”,请使用以下查询:
将多个节点属性写入Neo4j:
CALL gds.graph.writeNodeProperties(
'my-graph',
['componentId', 'pageRank', 'communityId'],
['*'],
{writeConcurrency: 8}
)
上面的示例要求所有给定的属性至少出现在一个节点投影上,并且将为所有此类投影编写属性。
可以将该过程配置为只写入某些特定节点投影的属性。在下面的示例中,我们在子图上运行一个算法,然后将新创建的属性写入Neo4j。
将特定节点投影中的节点属性写入Neo4j:
CALL gds.graph.create('my-graph', ['A', 'B'], '*')
CALL gds.wcc.mutate('my-graph', {nodeLabels: ['A'], mutateProperty: 'componentId'})
CALL gds.graph.writeNodeProperties('my-graph', ['componentId'], ['A'])
当指定不包括星形投影(’’)的投影列表时,如上面的示例中所示,将应用不同的验证和执行。在这种情况下,要求所有投影都具有所有给定的属性,并将所有投影的属性写入Neo4j。
如果给定的投影中有任何一个是投影,则该过程的行为类似于第一个示例。
10.将关系写入neo4j
我们可以将存储在命名内存图中的关系写回Neo4j。这可用于写入算法结果(例如,来自节点相似性的结果)或在图形创建期间聚合的关系。
要写入的关系由关系类型指定。这可以是在图构造期间关系投影中使用的元素标识符,也可以是创建关系的算法中使用的writeRelationshipType。关系总是使用单个线程编写的。
将关系写入Neo4j:
CALL gds.graph.writeRelationship('my-graph', 'SIMILAR_TO')
默认情况下,不会写入任何关系属性。要编写关系属性,必须显式指定这些属性。
将关系及其属性写入Neo4j:
CALL gds.graph.writeRelationship('my-graph', 'SIMILAR_TO', 'similarityScore')
11. 根据命名图创建Neo4j数据库
我们可以从存储在图形目录中的命名内存图创建新的Neo4j数据库。内存中图形中的所有节点、关系和属性都会写入新的Neo4j数据库。这包括已在投影中的数据gds.graph.create
以及通过在mutate
模式下运行算法添加的数据。新创建的数据库将使用给定的数据库名称存储在Neo4j databases
目录中。
该功能在以下示例性场景中非常有用:
- 通过导出数据而不是回写来避免操作系统上的大量写负载。
- 创建操作系统的分析视图,该视图可用作运行算法的基础。
- 生成分析结果的快照,并将其持久化以供存档和检查。
- 在组织内共享分析结果。
将命名图形导出到Neo4j数据库目录中的新数据库:
CALL gds.graph.export('my-graph', { dbName: 'mydatabase' })
该过程生成有关节点数、关系和写入的属性的信息。
表5. 图导出配置
名称 | 类型 | 默认 | 是否可选 | 描述 |
---|---|---|---|---|
dbName | String | none | No | 导出到的Neo4j数据库名称 |
writeConcurrency | Boolean | 4 | yes | 用于写入数据库的并发线程数 |
enableDebugLog | Boolean | false | yes | 将调试信息打印到Neo4j日志文件 |
batchSize | Integer | 10000 | yes | 一次由一个线程处理的实体数 |
defaultRelationshipType | String | “ALL” | yes | 用于*关系投影的关系类型 |
新数据库通过 databases management commands开始使用
使用导出过程时数据库不存在,需要使用以下命令手动创建。
运行此过程后,我们可以启动一个新数据库并查询导出的图形:
:use system
CREATE DATABASE mydatabase;
:use mydatabase
MATCH (n) RETURN n;
12. 将一个命名图导出为csv
我们可以将存储在图目录中的命名内存图导出为一组CSV文件。将导出内存图中存在的所有节点、关系和属性。这包括用gds.graph.create
投影的数据和通过在mutate
模式下运行算法添加的数据。导出的CSV文件的位置可以通过neo4j.conf中的配置参数gds.export.location
进行配置。所有文件都将使用指定的导出名称存储在子文件夹中。如果已存在具有给定导出名称的文件夹,则导出将失败。
必须为此功能配置gds.export.location
参数。
将命名图导出为csv文件:
CALL gds.beta.graph.export.csv('my-graph', {exportName: 'myExport'})
该过程生成有关节点数、关系和写入的属性的信息。
表6. 图导出配置
名称 | 类型 | 默认 | 是否可选 | 描述 |
---|---|---|---|---|
exportName | String | none | No | CSV文件导出到的文件夹的名称 |
writeConcurrency | Boolean | 4 | yes | 用于写入数据库的并发线程数 |
defaultRelationshipType | String | “ALL” | yes | 用于*关系投影的关系类型 |
12.1. 导出格式
导出的CSV文件的格式基于Neo4j Admin import命令支持的格式。
12.1.1. 节点
将节点导出到按节点标签分组的文件中,即,为图形中存在的每个标签组合创建一组导出文件。导出文件的命名模式为:nodes_LABELS_INDEX.csv
,其中:
- LABELS是由_连接的标签的有序列表。
- INDEX是介于0和并发性之间的数字。
对于每个标签组合,将创建一个或多个数据文件,因为每个导出线程将数据导出到一个单独的文件中。
此外,每个标签组合都会生成一个头文件,其中包含一行描述数据文件中的列。有关头文件的更多信息,请参阅:CSV头文件格式。
例如,节点组合为:A,:B和:A:B的图形可能会创建以下文件
nodes_A_header.csv
nodes_A_0.csv
nodes_B_header.csv
nodes_B_0.csv
nodes_B_2.csv
nodes_A_B_header.csv
nodes_A_B_0.csv
nodes_A_B_1.csv
nodes_A_B_2.csv
12.1.2. 关系
关系文件的格式与节点的格式类似。关系将导出到按关系类型分组的文件中。导出文件的命名模式为:关系relationships_TYPE_INDEX.csv
,其中:
- TYPE是关系类型
- INDEX是介于0和concurrency之间的数字。
对于每个关系类型,将创建一个或多个数据文件,因为每个导出线程导出到一个单独的文件中。
此外,每个关系类型都会生成一个头文件,其中包含一行描述数据文件中列的行。
例如,一个关系类型为:KNOWS, :LIVES_IN的图可能会创建以下文件
relationships_KNOWS_header.csv
relationships_KNOWS_0.csv
relationships_LIVES_IN_header.csv
relationships_LIVES_IN_0.csv
relationships_LIVES_IN_2.csv
12.2.估计
使用gds.graph.export.csv.estimate
过程可以估计导出的csv文件所需的磁盘空间。该过程通过使用抽样来产生更精确的估计。
估计将命名图形导出到CSV文件所需的磁盘空间:
CALL gds.beta.graph.export.csv.estimate('my-graph', {exportName: 'myExport'})
YIELD nodeCount, relationshipCount, bytesMin, bytesMax, requiredMemory;
该过程会生成有关所需磁盘空间的信息。
表7. 图导出估计配置
名称 | 类型 | 默认 | 是否可选 | 描述 |
---|---|---|---|---|
exportName | String | none | No | CSV文件导出到的文件夹的名称 |
samplingFactor | Double | 0.001 | yes | 用于估计的节点和关系的取样比例 |
writeConcurrency | Boolean | 4 | yes | 用于写入数据库的并发线程数 |
defaultRelationshipType | String | “ALL” | yes | 用于*关系投影的关系类型 |
本地投影
本地投影允许我们将Neo4j中的图投影到内存图中。可以根据节点标签、关系类型和属性来指定投影图。节点标签和节点属性使用节点投影进行投影。关系类型和关系属性使用关系投影进行投影。
本地投影的主要好处是它们的性能。相反,从声明的角度来看,Cypher投影更灵活,但性能较差。在大多数情况下,可以用一种能够使用本地投影的方式来构造Neo4j图形模型。
1.语法
原生投影需要三个必需参数:graphName
、nodeProjection
和relationshipProjection
。另外,可选的configuration
参数允许我们进一步配置图形创建。
CALL gds.graph.create(
graphName: String,
nodeProjection: String, List or Map,
relationshipProjection: String, List or Map,
configuration: Map
)
表1. 参数
名称 | 是否可选 | 描述 |
---|---|---|
graphName | no | 图存储在目录中的名称 |
nodeProjection | no | 一个或多个节点投影 |
relationshipProjection | no | 一个或多个关系投影 |
configuration | yes | 配置本地投影的额外参数 |
表2. 配置
名称 | 类型 | 是否可选 | 描述 |
---|---|---|---|
readConcurrency | Integer | 4 | 用于创建图的并发线程数 |
nodeProperties | String, List or Map | empty map | 为所有节点投影加载的节点属性 |
relationshipProperties | String, List or Map | empty map | 为所有关系投影加载的关系属性 |
validateRelationships | Boolean | false | 如果关系包含节点投影中未包含的节点,则是否引发错误 |
2.节点投影
节点投影可将Neo4j节点映射到内存图中。指定节点投影时,可以声明要投影的一个或多个节点标签。
以下类似map的语法显示了定义节点投影的一般方法:
{
<node-label-1>: {
label: <neo4j-label>,
properties: <node-property-mappings>
},
<node-label-2>: {
label: <neo4j-label>,
properties: <node-property-mappings>
},
// ...
<node-label-n>: {
label: <neo4j-label>,
properties: <node-property-mappings>
}
}
- node-label-i表示投影图中使用的节点标签
- neo4j-label表示neo4j图形中的节点标签
- 标签必须存在于Neo4j数据库中
- 如果未指定,neo4j label默认为node-label-i
- node-property-mappings表示Neo4j和内存中属性之间的一组映射
在下面的示例中,我们希望将Person节点投影到内存图中。结果图包含所有具有标签Person的Neo4j节点。
CALL gds.graph.create(
'my-graph', {
Person: { label: 'Person' }
},
'*'
)
YIELD graphName, nodeCount, relationshipCount;
我们可以使用以下简单语法来投影单个节点标签。
CALL gds.graph.create('my-graph', 'Person', '*')
YIELD graphName, nodeCount, relationshipCount;
创建一个表示多个节点标签的内存图通常很有用。让我们假设,数据库包含我们要投影的Person和City节点。
CALL gds.graph.create(
'my-graph', {
Person: { label: 'Person' },
City: { label: 'City' }
},
'*'
)
YIELD graphName, nodeCount, relationshipCount;
以下简单语法可用于投影多个标签。
CALL gds.graph.create('my-graph', ['Person', 'City'], '*')
YIELD graphName, nodeCount, relationshipCount;
投影多个节点标签后使算法只使用其中的一个子集。
// Uses `Person` nodes for computing Page Rank scores between persons
CALL gds.pageRank.stream('my-graph', { nodeLabels: ['Person'] }) YIELD nodeId, score;
要在Neo4j图中投影所有节点,我们可以使用*进行投影。
CALL gds.graph.create('my-graph', '*', '*')
YIELD graphName, nodeCount, relationshipCount;
当图形使用投影时,由于已经包含这些节点,因此不会添加来自命名节点投影的其他节点。这也适用于筛选。例如,如果用标签’A’, ‘B’投影图形,并且带有’’,则包含’‘的任何节点筛选都等同于仅使用’*’。但是,仍然可以对标签为’A’ 或 'B’的节点进行筛选,以便检索仅包含这些节点的子图。
CALL gds.graph.create('my-graph', ['Person', 'City', '*'])
// 使用投影在 'my-graph' 中的全部节点(* projection)
CALL gds.pageRank.stats('my-graph', {nodeLabels: ['*']})
CALL gds.pageRank.stats('my-graph', {nodeLabels: ['Person', 'City', '*']}) // 等价
CALL gds.pageRank.stats('my-graph') // 等价
//只使用 'my-graph'中被投影为 'Person' 的节点
CALL gds.pageRank.stats('my-graph', {nodeLabels: ['Person']})
// 使用 'my-graph'中被投影为 'Person','City' 的节点
CALL gds.pageRank.stats('my-graph', {nodeLabels: ['Person', 'City']})
2.1. 节点属性
节点属性在加载具有多个节点属性的内存图通常很有用。一个典型的场景是在同一个图上运行不同的种子算法,但作为种子的节点属性不同。我们可以使用节点属性映射为每个节点投影加载多个节点属性。节点属性映射将用户定义的属性键映射到Neo4j数据库中的属性键。任何支持节点属性的算法都可以引用这些用户定义的属性键。
{
<node-label>: {
label: <neo4j-label>,
properties: {
<property-key-1>: {
property: <neo-property-key>,
defaultValue: <fallback-value>
},
<property-key-2>: {
property: <neo-property-key>,
defaultValue: <fallback-value>
},
// ...
<property-key-n>: {
property: <neo-property-key>,
defaultValue: <fallback-value>
}
}
}
}
- property-key-i表示投影图中的属性键
- neo-property-key表示Neo4j图中的属性键
- 属性键必须存在于Neo4j数据库中
- 如果未指定,neo property key默认为property-key-i
- 如果节点的属性不存在,则使用fallback-value
- 如果未指定,则fallback-value默认为属性类型的相应回退值。
对于下面的示例,假设每个城市节点存储两个属性:城市人口population和标识城市所在州的可选stateId。我们希望将属性population和stateId都投影到自定义属性键community。
创建具有多个节点属性的图:
CALL gds.graph.create(
'my-graph', {
City: {
properties: {
stateId: {
property: 'stateId'
},
population: {
property: 'population'
}
}
}
},
'*'
)
YIELD graphName, nodeCount, relationshipCount;
如果不需要重命名节点属性键或提供默认值,则可以使用以下简写语法。
CALL gds.graph.create('my-graph', 'City', '*', {
nodeProperties: ['population', 'stateId']
}
)
YIELD graphName, nodeCount, relationshipCount;
也可以在投影期间重命名属性键。在本例中,我们将属性键stateId投影到自定义属性键community。当我们在算法中使用投影图时,我们引用的是自定义属性键。
CALL gds.graph.create('my-graph', 'City', '*', {
nodeProperties: ['population', { community: 'stateId' }]
}
)
YIELD graphName, nodeCount, relationshipCount;
任何使用属性作为输入的算法都可以引用投影属性,例如,Label Propagation。
CALL gds.labelPropagation.stream(
'my-graph', {
seedProperty: 'community'
}
) YIELD nodeId, communityId;
3.关系投影
关系投影定义了如何将Neo4j关系的特定子集投影到内存图中。
以下类似映射的语法显示了定义关系投影的一般方法:
{
<relationship-type-1>: {
type: <neo4j-type>,
orientation: <orientation>,
aggregation: <aggregation-type>,
properties: <relationship-property-mappings>
},
<relationship-type-2>: {
type: <neo4j-type>,
orientation: <orientation>,
aggregation: <aggregation-type>,
properties: <relationship-property-mappings>
},
// ...
<relationship-type-n>: {
type: <neo4j-type>,
orientation: <orientation>,
aggregation: <aggregation-type>,
properties: <relationship-property-mappings>
}
}
- relationship-type-i表示投影图中的关系类型
- neo4j-type表示neo4j图中的关系类型
- 关系类型必须存在于Neo4j数据库中
- 如果未指定,neo4j-type默认为relationship-type-i
- orientation表示Neo4j关系在投影图中的表示方式。允许以下值:
- NATURAL:每个关系的投影方式与存储在Neo4j中的方式相同(默认)
- REVERSE:在图形投影期间,每个关系都是反向的
- UNDIRECTED:每个关系都以自然方向和反向方向投影
- aggregation-type表示如何处理并行关系及其属性。指定的值将应用于未指定聚合的所有属性映射。允许以下值:
- NONE:不聚合并行关系(默认)
- MIN、MAX、SUM:应用于并行关系的数值属性
- SINGLE:一个单一的,任意的平行关系外的关系是投影
- COUNT:统计非空数值属性的数目 如果使用特殊属性名’*’,COUNT将计算并行关系
- relationship-property-mappings表示Neo4j和内存中关系属性之间的一组映射
在下面的示例中,我们希望将City节点以及ROAD和RAIL关系投影到内存图中。
CALL gds.graph.create(
'my-graph',
'City',
{
ROAD: {
type: 'ROAD',
orientation: 'NATURAL'
},
RAIL: {
type: 'RAIL',
orientation: 'NATURAL'
}
}
)
YIELD graphName, nodeCount, relationshipCount;
在上例中,我们使用和Neo4j数据库中相同的关系类型,即默认orientation
。在本例中我们使用以下类似节点投影的简单语法。
CALL gds.graph.create( 'my-graph', 'City', ['ROAD', 'RAIL'])
YIELD graphName, nodeCount, relationshipCount;
映射多种关系类型使算法能够只使用它们的子集。
// Uses `ROAD` relationships for computing Page Rank of cities
CALL gds.pageRank.stream('my-graph', { relationshipTypes: ['ROAD'] }) YIELD nodeId, score;
// Uses `RAIL` relationships for computing Page Rank of cities
CALL gds.pageRank.stream('my-graph', { relationshipTypes: ['RAIL'] }) YIELD nodeId, score;
3.1. 投影方向
默认情况下,关系以其自然表示形式进行投影,即以与存储在Neo4j中相同的方式进行投影。在关系投影定义中使用orientation键,我们可以改变这种行为。有三种可能的值: NATURAL, REVERSE 和 UNDIRECTED,从节点的角度可以最好地描述它们:
NATURAL是默认的,并投影从节点指出的关系。
REVERSE投影指向节点的关系。
UNDIRECTED 同时投影NATURAL和REVERSE的节点关系(同时指入和指出)
考虑下面的图,其中包含通过KNOWS连接的Person节点。一段关系是有方向的,因为一个人可能认识另一个人,反之则未必。
CREATE (alice:Person {name: 'Alice'})
CREATE (bob:Person {name: 'Bob'})
CREATE (eve:Person {name: 'Eve'})
CREATE (alice)-[:KNOWS]->(bob)
CREATE (bob)-[:KNOWS]->(eve)
CREATE (eve)-[:KNOWS]->(bob);
在NATURAL投影中,Alice和Bob有关系(Alice认识Bob),Bob和Eve有关系(Bob认识Eve),Eve也和Bob有关系(Eve认识Bob)。在REVERSE投影中,Alice没有关系,因为没有关系指向Alice。Bob和Eve各有一段关系,因为他们指向对方。在UNDIRECTED投影中,Alice将有一个关系表示指出关系。但是,Bob和Eve将有两种关系,因为指出和指入的关系是独立的。
要创建具有不同投影类型的图形投影,我们使用以下语法:
CALL gds.graph.create(
'my-graph',
'Person',
{
KNOWS: {
type: 'KNOWS',
orientation: 'NATURAL'
},
KNOWN_BY: {
type: 'KNOWS',
orientation: 'REVERSE'
},
FRIEND_OF: {
type: 'KNOWS',
orientation: 'UNDIRECTED'
}
}
)
YIELD graphName, nodeCount, relationshipCount;
在前面的示例中,我们可以在运行算法时引用投影关系的子集。如果我们运行这些示例,我们可以看到各个节点的不同rank。pagerank算法沿着节点的关系均匀地分布rank。在REVERSE的情况下,Alice节点没有关系,这将导致不同的结果。
// Uses `KNOWS` relationships for computing Page Rank of persons
CALL gds.pageRank.stream('my-graph', { relationshipTypes: ['KNOWS'] }) YIELD nodeId, score;
// Uses `KNOWN_BY` relationships for computing Page Rank based on reversed relationships
CALL gds.pageRank.stream('my-graph', { relationshipTypes: ['KNOWN_BY'] }) YIELD nodeId, score;
// Uses `FRIEND_OF` relationships for computing Page Rank based on both projection types
CALL gds.pageRank.stream('my-graph', { relationshipTypes: ['FRIEND_OF'] }) YIELD nodeId, score;
创建投影会消耗额外的内存,因为这些投影存储在单独的内存数据结构中。有时可以合并关系投影,而不是创建新的关系投影。在上面的例子中,投影的FRIEND_OF等价于使用[‘KNOWS’,‘KNOWN_BY’]作为关系类型谓词。如果我们对单个投影使用不同的聚合,这是不可能的。
3.2. 关系属性
与节点属性类似,关系投影支持指定关系属性。我们可以使用关系属性映射为每个关系投影指定多个关系属性。关系属性映射将用户定义的属性键映射到Neo4j数据库中的属性键。该参数使用一个map进行配置,其中每个键都引用一个用户定义的属性键。关系只支持数字属性。
以下类似映射的语法显示了定义关系属性映射的常规方法:
{
<relationship-type-1>: {
type: <neo4j-type>,
orientation: <orientation-type>,
aggregation: <aggregation-type>,
properties: {
<property-key-1>: {
property: <neo4j-property-key>,
defaultValue: <numeric-value>,
aggregation: <aggregation-type>
},
<property-key-2>: {
property: <neo4j-property-key>,
defaultValue: <numeric-value>,
aggregation: <aggregation-type>
},
// ...
<property-key-n>: {
property: <neo4j-property-key>,
defaultValue: <numeric-value>,
aggregation: <aggregation-type>
}
}
}
}
- property-key-i表示投影图中属性的名称
- neo4j-property-key表示neo4j图中属性的名称
- 属性键必须存在于Neo4j数据库中
- neo4j属性键默认为property-key-i
- 特殊属性键“*”允许与count聚合结合使用
- 如果关系的属性不存在,则使用numeric-value
- numeric-vlaue默认为NaN
- aggregation-type是表示如何处理并行关系的属性。指定的值重写为封闭关系投影指定的聚合类型。允许以下值:
- NONE:不聚合并行关系(默认)
- MIN、MAX、SUM:应用于并行关系的数值属性
- SINGLE:一个单一的,任意的平行关系外的关系将被投影
- COUNT:统计非空数值属性的数目
- 如果使用特殊属性名“*”,COUNT将计算并行关系
在下面的例子中,我们将投影City节点和ROAD关系,并投影关系的quality和distance属性。
CALL gds.graph.create(
'my-graph', {
City: {
properties: {
community: {
property: 'stateId'
}
}
}
}, {
ROAD: {
properties: {
quality: {
property: 'condition'
},
distance: {
property: 'length'
}
}
}
}
)
YIELD graphName, nodeCount, relationshipCount;
也可以使用以下简写语句。
CALL gds.graph.create(
'my-graph', 'City', 'ROAD', {
nodeProperties: { community: 'stateId' },
relationshipProperties: [{ quality: 'condition' }, { distance: 'length' }]
}
)
YIELD graphName, nodeCount, relationshipCount;
任何使用属性作为输入的算法都可以引用投影属性,例如Label Progation。
// Option 1: Use the road quality as relationship weight
CALL gds.labelPropagation.stream(
'my-graph', {
seedProperty: 'community',
relationshipWeightProperty: 'quality'
}
) YIELD nodeId, communityId;
// Option 2: Use the distance between cities as relationship weight
CALL gds.labelPropagation.stream(
'my-graph', {
seedProperty: 'community',
relationshipWeightProperty: 'distance'
}
) YIELD nodeId, communityId;
3.3. 关系聚合
关系投影提供了不同的方法来处理给定一对节点之间的多个所谓的“并行”关系。默认值是NONE聚合,它保留所有并行关系并将它们直接投影到内存中的图中。所有其他聚合都将一对节点之间的所有并行关系投影到单个关系中。
在下面的示例中,我们希望将两个城市之间的所有ROAD关系聚合为一个关系。在执行此操作时,我们计算并行关系的最大量,并将其存储在生成的关系上。
使用condition属性的MAX值创建具有聚合并行关系的图:
CALL gds.graph.create(
'my-graph', {
City: {
properties: {
community: {
property: 'stateId'
}
}
}
}, {
ROAD: {
properties: {
maxQuality: {
property: 'condition',
aggregation: 'MAX',
defaultValue: 1.0
}
}
}
}
)
YIELD graphName, nodeCount, relationshipCount;
使用condition属性的COUNT值创建具有聚合并行关系的图:
CALL gds.graph.create(
'my-graph', {
City: {
properties: {
community: {
property: 'stateId'
}
}
}
}, {
ROAD: {
properties: {
roadCount: {
property: 'condition',
aggregation: 'COUNT'
}
}
}
}
)
YIELD graphName, nodeCount, relationshipCount;
如果只有一个节点投影和一个关系投影,我们可以使用以下简写语法。
CALL gds.graph.create(
'my-graph', 'City', 'ROAD', {
nodeProperties: { community: 'stateId' },
relationshipProperties: { maxQuality: { property: 'condition', aggregation: 'MAX', defaultValue: 1.0 }}
}
)
YIELD graphName, nodeCount, relationshipCount;
如前所述,任何使用属性作为输入的算法都可以引用投影属性,例如Label Propagation。
CALL gds.labelPropagation.stream(
'my-graph', {
seedProperty: 'community',
relationshipWeightProperty: 'maxQuality'
}
) YIELD nodeId, communityId;
Cypher投影
如果本地投影的表达能力不足以描述内存中的图,我们可以使用Cypher查询来选择节点和关系。使用Cypher查询的一个好处是可以从数据中形成仅在查询时存在的图。一个常见的用例是将路径简化为路径的开始节点和结束节点之间的单一关系。
以下查询将两跳路径缩减为有效表示共同作者的单个关系:
MATCH (p1:Author)-[:WROTE]->(a:Article)<-[:WROTE]-(p2:Author)
RETURN id(p1) AS source, id(p2) AS target, count(a) AS weight
对于某些Cypher模式,使用Collapse Path算法结合本地投影可以实现相同的行为。
Cypher预测在develop阶段尤其有用。在探索数据和算法以及设计工作流时,它们的灵活性非常方便。但是,从Cypher投影创建图形的速度可能比直接从Neo4j存储文件创建图形慢得多。对于产品,建议调整域模型,使其能够更好利用本地投影加载快速的特点。
在图形创建过程中,GDS默认执行自动内存估计和潜在的执行阻塞。对于Cypher投影,此功能默认为关闭,因为内存消耗可能被高估。
1.语法
Cypher投影需要三个必需参数:graphName
、nodeQuery
和relationshipQuery
。另外,可选的configuration
参数允许我们进一步配置图形创建。
CALL gds.graph.create.cypher(
graphName: String,
nodeQuery: String,
relationshipQuery: String,
configuration: Map
)
表1.参数
名称 | 可选项 | 描述 |
---|---|---|
graphName | no | 存储在目录中的图名称 |
nodeQuery | no | 投影节点的Cypher查询 |
relationshipQuery | no | 投影关系的Cypher查询 |
configuration | yes | 配置Cypher投影的额外参数 |
表2.配置
名称 | 类型 | 默认 | 描述 |
---|---|---|---|
readConcurrency | Integer | 4 | 用于创建图的并发线程数 |
validateRelationships | Boolean | true | 当关系中存在不在nodeQuery中的节点时是否抛出错误 |
parameters | Map | empty map | 传递到节点和关系查询的用户定义查询参数的map |
要获取有关存储的命名图(包括其模式)的信息,可以使用gds.graph.list
。
2.查询限制
节点查询将节点及其属性(可选)投影到内存中的图。查询结果中的每一行表示投影图中的一个节点。
查询结果必须包含名为id的列。该列中的值用于唯一标识节点。
用于Cypher投影的节点查询的简单示例:
MATCH (n) RETURN id(n) AS id
关系查询将关系及其类型和属性(可选)投影到内存图中。查询结果中的每一行表示投影图中的关系。
查询结果必须包含名为source的列和名为target的列。这些列中的值表示关系的源节点id和目标节点id。这些值用于将关系连接到节点查询所选的节点。如果源值或目标值不能映射到节点,则关系将不被投影。
用于Cypher投影的关系查询的简单示例:
MATCH (n)-->(m) RETURN id(n) AS source, id(m) AS target
使用Cypher投影中的两个示例查询,我们可以将整个Neo4j图投影到内存中的图中,并将其存储在目录中:
CALL gds.graph.create.cypher(
'my-cypher-graph',
'MATCH (n) RETURN id(n) AS id',
'MATCH (n)-->(m) RETURN id(n) AS source, id(m) AS target'
)
Cypher投影允许从任意查询结果创建图,而不管这些结果是否映射到Neo4j图中的实际标识符。在写模式下对这样的图执行算法可能会导致Neo4j数据库中发生意外的更改。
3.节点和关系属性
与默认本地投影类似,我们可以使用Cypher投影加载节点和关系属性。
节点和关系查询都必须返回各自的强制列,即id、source和target。如果查询返回其他列,则这些列将分别用作节点和关系属性。
节点属性值可以是任何支持的类型。关系属性值必须是数字类型。如果值为null,则会加载已确定属性类型的默认值。如果要使用不同的默认值,可以使用coalesce函数。有关支持的属性类型的详细信息,请参见Node Properties。
以下Cypher投影加载多个节点和关系属性:
CALL gds.graph.create.cypher(
'my-cypher-graph',
'MATCH (n:City) RETURN id(n) AS id, n.stateId AS community, n.population AS population',
'MATCH (n:City)-[r:ROAD]->(m:City) RETURN id(n) AS source, id(m) AS target, r.distance AS distance, coalesce(r.condition, 1.0) AS quality'
)
任何使用属性作为输入的算法都可以引用投影属性,例如,Label Propagation。
CALL gds.labelPropagation.stream(
'my-cypher-graph', {
seedProperty: 'community',
relationshipWeightProperty: 'quality'
}
)
4.节点标签
本地投影支持指定多个节点标签,这些标签可以在单个算法执行中过滤。Cypher投影可以通过在节点查询中返回节点标签来实现相同的特性。如果节点查询结果中存在一个名为labels
的列,我们将使用该列中的值来区分节点标签。此列应返回字符串列表。
考虑下面的示例,其中Author节点通过WROTE关系连接到Article或Book节点。
使用labels列来区分节点标签:
CALL gds.graph.create.cypher(
'my-cypher-graph',
'MATCH (n) WHERE n:Author OR n:Article OR n:Book RETURN id(n) AS id, labels(n) AS labels',
'MATCH (n:Author)-[r:WROTE]->(m) RETURN id(n) AS source, id(m) AS target'
)
创建的图将由标记为:Book, :Article或:Author的节点组成。这允许我们在算法执行期间应用节点过滤器:
在子图上使用节点过滤器运行算法:
CALL gds.labelPropagation.stream(
'my-cypher-graph', {
nodeLabels: ['Author', 'Book']
}
)
5.关系类型
本地投影支持加载多个关系类型,这些关系类型可以在单个算法执行中过滤。Cypher投影可以通过在查询中返回关系类型来实现相同的特性。如果查询结果中存在type列,则使用该列中的值来区分关系类型。
对于以下例子,假设City节点通过ROAD或RAIL关系连接。
使用type列来区分多种关系类型:
CALL gds.graph.create.cypher(
'my-cypher-graph',
'MATCH (n:City) RETURN id(n) AS id',
'MATCH (n:City)-[r:ROAD|RAIL]->(m:City) RETURN id(n) AS source, id(m) AS target, type(r) AS type'
)
加载的图形将由两种关系类型组成。这允许我们在算法执行期间应用关系过滤器:
在子图上使用关系过滤器运行算法:
CALL gds.labelPropagation.stream(
'my-cypher-graph', {
relationshipTypes: ['ROAD']
}
)
6.关系方向
本地投影支持为每个关系类型指定方向。cypher投影可以通过调整关系查询的MATCH子句来实现相同的功能。
类似orientation NATURAL的关系加载:
//直接使用箭头进行关系的指向性表示
CALL gds.graph.create.cypher(
'my-cypher-graph',
'MATCH (n:City) RETURN id(n) AS id',
'MATCH (n:City)-[r:ROAD|RAIL]->(m:City) RETURN id(n) AS source, id(m) AS target, type(r) AS type'
)
类似orientation UNDIRECTED的关系加载:
CALL gds.graph.create.cypher(
'my-cypher-graph',
'MATCH (n:City) RETURN id(n) AS id',
'MATCH (n:City)-[r:ROAD|RAIL]-(m:City) RETURN id(n) AS source, id(m) AS target, type(r) AS type'
)
类似orientation REVERSE的关系加载:
CALL gds.graph.create.cypher(
'my-cypher-graph',
'MATCH (n:City) RETURN id(n) AS id',
'MATCH (n:City)<-[r:ROAD|RAIL]-(m:City) RETURN id(n) AS source, id(m) AS target, type(r) AS type'
)
REVERSE orientation也可以通过在RESULT子句中交换source 和target来实现。
7.关系聚合
属性图模型支持并行关系,这意味着两个节点可以由相同关系类型的多个关系连接。对于某些算法,我们希望投影图在两个节点之间最多包含一个关系。
实现这一点的最简单方法是在关系查询中使用DISTINCT运算符:
MATCH (n:City)-[r:ROAD]->(m:City)
RETURN DISINCT id(n) AS source, id(m) AS target
如果我们还想加载关系属性,也可以使用Cypher来对平行关系的值进行聚合。
MATCH (n:City)-[r:ROAD]->(m:City)
RETURN
id(n) AS source,
id(m) AS target,
min(r.distance) AS minDistance,
coalesce(max(r.condition), 1.0) AS maxQuality
8.使用查询参数
与Cypher类似,还可以设置查询参数。在下面的示例中,我们提供了一个字符串列表来限制要投影的城市。
CALL gds.graph.create.cypher(
'my-cypher-graph',
'MATCH (n:City) WHERE n.name IN $cities RETURN id(n) AS id',
'MATCH (n:City)-[r:ROAD]->(m:City) WHERE n.name IN $cities AND m.name IN $cities RETURN id(n) AS source, id(m) AS target',
{
parameters: { cities: ["Leipzig", "Malmö"] }
}
)
如果节点标签和关系类型的选择性不足以创建要在其上运行算法的图形投影,则可以使用Cypher查询来投影图形。这也可以用于在虚拟图上运行算法。您可以在手册的Cypher投影部分了解更多信息。
如果相似性列表非常大,则会占用大量内存。对于那些列表包含许多应该跳过的值的情况,可以使用内存占用较少的方法,即使用Cypher语句来投影图形。
Cypher加载器将收到3个字段:
- item-应该包含节点id,我们可以使用
id
函数返回节点id。 - category-应该包含节点id,我们可以使用
id
函数返回节点id。 - weight-应包含一个double值。
匿名图
本章描述了如何为单次运行的算法创建匿名图
使用GDS库时的典型工作流是创建一个图形并将其存储在目录中。这有助于最少化对Neo4j的读取,并可在同一图形投影上运行具有不同设置的算法或多个算法。
但是,如果要快速运行单个算法,可以方便地使用匿名投影。其语法类似于gds.graph.create
的普通语法,同之处在于关系投影不能有多个属性。此外,nodeProjection和relationshipProjection参数被命名并放置在算法的configuration map中:
匿名本地投影语法:
CALL gds.<algo>.<mode>(
{
nodeProjection: String, List or Map,
relationshipProjection: String, List or Map,
nodeProperties: String, List or Map,
relationshipProperties: String, List or Map,
// algorithm and other create configuration
}
)
下面的示例演示如何从Person节点和KNOWS关系创建匿名图。
CALL gds.<algo>.<mode>(
{
nodeProjection: 'Person',
relationshipProjection: 'KNOWS',
nodeProperties: 'age',
relationshipProperties: 'weight',
// algorithm and other create configuration
}
)
上例可以用以下调用代替:
//创建图
CALL gds.graph.create(
{
'new-graph-name',
'Person',
'KNOWS',
{
nodeProperties: 'age',
relationshipProperties: 'weight'
// other create configuration
}
}
);
CALL gds.<algo>.<mode>(
'new-graph-name',
{
// algorithm configuration
}
);
//算法执行完毕后销毁
CALL gds.graph.drop('new-graph-name');
与Cypher投影类似,gds.graph.create.Cypher
的显式创建可以使用nodeQuery和relationshipQuery内联到算法调用中。
匿名cypher投影语法:
CALL gds.<algo>.<mode>(
{
nodeQuery: String,
relationshipQuery: String,
// algorithm and other create configuration
}
)
节点属性
本节介绍当前支持的节点属性。
Neo4j图形数据科学库能够用附加属性扩充节点。创建图形投影时,可以从数据库加载这些属性。许多算法在使用mutate模式运行时,还可以将其结果作为一个或多个节点属性持久化。
1.支持类型
Neo4j图形数据科学库不支持Neo4j数据库支持的所有属性类型。每个支持的类型还将定义一个回退值,用于指示未设置此属性的值。
下表列出了支持的属性类型及其相应的回退值。
- Long - Long.MIN_VALUE
- Double - NaN
- Long Array - null
- Float Array -null
- Double Array - null
2.定义节点属性的类型
创建指定一组节点属性的图形投影时,这些属性的类型将通过加载程序读取的第一个属性值自动确定。所有整数类型都解释为Long值,所有浮点值都解释为Double值。数组值由数组包含的值的类型显式定义,例如,不支持将整数数组转换为长数组。不支持混合内容类型的数组。
3.自动类型转换
大多数能够使用节点属性的算法都需要特定的属性类型。如果所提供属性的类型与所需类型不匹配,库将尝试将属性值转换为所需类型。只有满足以下条件时,才会发生自动转换:
- 给定类型和期望类型都不是数组类型。
- 转换是少损失的
- Long到Double:Long值不超过Double类型支持的范围
- Double到Long:Double值没有任何小数位。
如果任何节点属性值不满足这些条件中的任何一个,算法计算将失败。
自动转换在计算上比较昂贵,因此在性能关键的应用中应该避免。
实用函数
本节提供Neo4j图形数据科学库中每个实用函数的说明和示例。
1.系统函数
名称 | 描述 |
---|---|
gds.version | 返回安装的Neo4j图数据科学库版本 |
RETURN gds.version() AS version
表1. 结果
版本 |
---|
“1.5.2” |
2.数值函数
表2.数值函数
名称 | 描述 |
---|---|
gds.util.NaN | 返回NaN值作为Cypher值 |
gds.util.infinity | 返回infinity作为Cypher值 |
gds.util.isFinite | 如果给定的参数是有限值返回True(not ±Infinity, NaN, or null). |
gds.util.isInfinite | 如果给定的参数不是有限值返回True(not ±Infinity, NaN, or null). |
2.1. 语法
名称 | 参数 |
---|---|
gds.util.NaN() | - |
gds.util.infinity() | - |
gds.util.isFinite(value:NUMBER) | 要检查的是否有限的值 |
gds.util.isInfinite(value:NUMBER) | 要检查的是否无限的值 |
2.2. 例子
gds.util.IsFinite():
UNWIND [1.0, gds.util.NaN(), gds.util.infinity()] AS value
RETURN gds.util.isFinite(value) AS isFinite
表3.结果
isFinite |
---|
true |
false |
false |
gds.util.isInfinite():
UNWIND [1.0, gds.util.NaN(), gds.util.infinity()] AS value
RETURN gds.util.isInfinite(value) AS isInfinite
表4.结果
isInFinite |
---|
false |
true |
true |
实用函数gds.util.NaN
可用作输入参数的默认值,如余弦相似性示例所示。gds.util.IsFinite
和gds.util.IsFinite
的一个常见用法是用于过滤stream结果,如gds.alpha.allShortestPaths
的示例所示。
3.节点和路径函数
表5.节点和路径函数
名称 | 描述 |
---|---|
gds.util.asNode | 返回给定节点id的节点对象,如果不存在则返回null |
gds.util.asNodes | 返回给定节点id的多个节点对象,如果不存在或为空列表则返回null |
3.1. 语法
名称 | 参数 |
---|---|
gds.util.asNode(nodeId: NUMBER) | neo4j图中一个节点的节点Id |
gds.util.asNodes(nodeIds: NUMBER[]) | neo4j图中节点的节点Id列表 |
3.2. 例子
考虑以下Cypher语句创建的图:
CREATE (nAlice:User {name: 'Alice'})
CREATE (nBridget:User {name: 'Bridget'})
CREATE (nCharles:User {name: 'Charles'})
CREATE (nAlice)-[:LINK]->(nBridget)
CREATE (nBridget)-[:LINK]->(nCharles)
gds.util.asNode:
MATCH (u:User{name: 'Alice'})
WITH id(u) AS nodeId
RETURN gds.util.asNode(nodeId).name AS node
表6.结果
节点 |
---|
“Alice” |
gds.util.asNodes:
MATCH (u:User)
WHERE NOT u.name = 'Charles'
WITH collect(id(u)) AS nodeIds
RETURN [x in gds.util.asNodes(nodeIds)| x.name] AS nodes
表7.结果
节点 |
---|
[Alice, Bridget] |
由于许多算法stream模式只返回节点id,因此可以使用gds.util.asNode和gds.util.asNodes从neo4j数据库中检索整个节点。
4.目录函数
目录函数允许直接从Cypher查询访问内存图。
表8.目录函数
名称 | 描述 |
---|---|
gds.util.nodeProperty | 允许访问存储在命名图中的节点属性 |
4.1. 语法
名称 | 描述 |
---|---|
gds.util.nodeProperty(graphName: STRING, nodeId: INTEGER, propertyKey: STRING, nodeLabel: STRING?) | 目录中的命名图、命名图中存在的Neo4j节点id、节点属性键和可选节点标签 |
如果给定了节点标签,则返回相应投影和给定节点的属性值。如果没有给定标签或’*’,则从包含给定属性键的任意投影中检索并返回属性值。如果给定节点缺少属性值,则返回null。
4.2. 例子
在目录中创建图:
CALL gds.graph.create('my-graph', 'User', 'LINK');
运行算法并更新命名图:
CALL gds.pageRank.mutate('my-graph', { mutateProperty: 'score' })
我们可以在未将数据写入Neo4j的情况下获取score。
访问Alice的属性节点属性:
MATCH (alice:User)
WHERE alice.name = 'Alice'
RETURN
alice.name AS name,
gds.util.nodeProperty('my-graph', id(alice), 'score') AS score
表9.结果
名称 | score |
---|---|
“Alice” | 0.15000000000000002 |
如果其他投影也有如下score属性,我们还可以从User投影中具体返回score属性。
从User访问Alice的属性节点属性:
MATCH (alice:User)
WHERE alice.name = 'Alice'
RETURN
alice.name AS name,
gds.util.nodeProperty('my-graph', id(alice), 'score', 'User') AS score
表10.结果
名称 | score |
---|---|
“Alice” | 0.15000000000000002 |
其他
本章详细介绍了Neo4j图形数据科学库中不属于任何其他类别的功能。
1.使用过程
1.1. 进度记录程序
过程,可以显示长期运行的任务或算法的日志条目。
1.1.1. 语法
返回一个正在运行的任务过程:
CALL gds.beta.listProgress()
YIELD
id,
taskName,
message
结果
- id:正在运行的任务的生成标识符。
- taskName:正在运行的任务的名称,即Node2Vec。
- message:进度日志消息,与记录到debug.log文件的消息相同。
1.1.2. 例子
假设我们刚刚启动gds.alpha.node2vec.stream
过程。
CALL gds.beta.listProgress()
YIELD
id,
taskName,
message
表1. 结果
id | taskName | message |
---|---|---|
“d21bb4ca-e1e9-4a31-a487-42ac8c9c1a0d” | “Node2Vec” | “[gds-1] Node2Vec 42%” |
模型目录
本节详细介绍了可用于管理Neo4j图形数据科学库中的命名训练模型的模型目录操作。
一些图算法在计算中使用经过训练的模型。模型通常是表示真实世界或虚拟实体的数学公式。每个需要训练模型的算法都提供了计算该模型的公式和方法(参见GraphSage train syntax)。
模型目录是GDS库中的一个概念,它允许按名称存储和管理多个经过训练的模型。
本章介绍可用的模型目录操作。
名称 | 描述 |
---|---|
gds.beta.model.exists | 检查一个目录中的命名模型是否可用 |
gds.beta.model.list | 打印有关目录中当前可用模型的信息 |
gds.beta.model.drop | 从目录中移除命名模型 |
gds.alpha.model.store | 将目录中的模型名称存储在磁盘上 |
gds.alpha.model.load | 从磁盘加载命名和存储的模型 |
gds.alpha.model.delete | 从磁盘中删除已命名和存储的模型 |
gds.alpha.model.publish | 使模型可供所有用户访问 |
训练模型由相应的算法负责,并由程序模式-train提供。训练、使用、列出和删除命名模型是绑定到Neo4j用户的管理操作。由不同的Neo4j用户训练的模型在任何时候都不可访问。
1.检查模型是否在目录中
我们可以通过查找模型的名称来检查它是否在目录中可用。
检查模型是否在目录中:
CALL gds.beta.model.exists('my-model') YIELD exists;
表1. 结果
exists |
---|
true |
2.列出目录中可用的模型
一旦我们在目录中训练了模型,我们就可以通过名称看到所有模型或任意单个模型的信息。
列举所有模型的详细信息:
CALL gds.beta.model.list()
YIELD
modelInfo,
loaded,
stored,
shared
表2. 结果
modelInfo | loaded | stored | shared |
---|---|---|---|
{modelName=my-model, modelType=example-model-type} | true | false | false |
列举具体模型的详细信息:
CALL gds.beta.model.list('my-model')
YIELD
modelInfo,
loaded,
stored,
shared
表3. 结果
modelInfo | loaded | stored | shared |
---|---|---|---|
{modelName=my-model, modelType=example-model-type} | true | false | false |
此过程返回的完整字段集包括:
- modelInfo:训练模型的详细信息
- modelName:String:保存的模型名。
- modelType:String:模型的类型,即GraphSAGE。
- 还可以包含特定于算法的模型详细信息。
- trainConfig:用于训练模型的配置。
- graphSchema:训练模型的图的模式。
- 存储:如果模型存储在磁盘上,则为True。
- loaded:如果模型加载到内存中的模型目录中,则为True
- creationTime:模型在目录中注册的时间。
- shared:一个布尔标志,指示模型是否已发布。
3.从目录中移除模型
如果我们不再需要一个模型我们可以将它从目录中移除。
CALL gds.beta.model.drop('my-model')
YIELD
modelInfo,
loaded,
stored,
shared
表4. 结果
modelInfo | loaded | stored | shared |
---|---|---|---|
{modelName=my-model, modelType=example-model-type} | true | false | false |
此过程返回的完整字段集包括:
-
modelInfo:训练模型的详细信息
-
modelName:String:保存的模型名。
-
modelType:String:模型的类型,即GraphSAGE。
-
还可以包含特定于算法的模型详细信息。
-
trainConfig:用于训练模型的配置。
-
graphSchema:训练模型的图的模式。
-
stored:如果模型存储在磁盘上,则为True。
-
loaded:如果模型加载到内存中的模型目录中,则为True
-
creationTime:模型在目录中注册的时间。
-
shared:一个布尔标志,指示模型是否已发布。
如果模型名不存在,将会抛出一个错误。
算法
由于时间原因algorithm部分暂时只翻译有Production-quality的常用算法,其他的以后有机会再补
本章描述了Neo4j图形数据科学库中的每个算法,包括算法层、执行模式和通用语法。
Neo4j图形数据科学(GDS)库包含许多图形算法。算法被划分为不同的问题类别。本章列出了这些类别。
算法存在于三个成熟度层次之一:
Production-quality
- 结果表明,该算法在稳定性和可扩展性方面已经过测试。
- 此层中的算法以gds.作为前缀。
Beta
- 表示该算法是Production-quality的候选算法。
- 此层中的算法以gds.beta.作为前缀。
Alpha
- 表示该算法是实验性的,可以随时更改或删除。
- 此层中的算法以gds.alpha.作为前缀。
本章分为以下几节:
- 语法概述
- 中心性算法
- 社区检测算法
- 相似性算法
- 路径发现算法
- 链路预测算法
- 节点嵌入
- 机器学习模型
- 辅助程序
- Pregel API
语法概览
本节介绍在Neo4j图形数据科学库中运行算法的通用语法,包括执行模式和常见配置参数。
通用算法语法有两种变体:
- 命名图变量
- 要操作的图将从图形目录中读取。
- 匿名图变量
- 作为算法执行的一部分,将创建和删除要操作的图。
每个语法变量还提供不同的执行模式。以下是受支持的执行模式: - stream
- 以记录流的形式返回算法的结果。
- stats
- 返回摘要统计信息的单个记录,但不写入Neo4j数据库。
- mutate
- 将算法的结果写入内存中的图,并返回摘要统计信息的单个记录。此模式是为命名图变量设计的,因为效果在匿名图上不可见。
- write
- 将算法的结果写入Neo4j数据库,并返回汇总统计的单个记录。
最后,可以通过向命令附加estimate
来估计执行模式。
只有生产质量层才能保证所有执行模式和估算程序的可用性。
包括上述所有元素,可得出以下语法大纲:
命名图形变量的语法组成:
CALL gds[.<tier>].<algorithm>.<execution-mode>[.<estimate>](
graphName: String,
configuration: Map
)
匿名图变量的语法组成:
CALL gds[.<tier>].<algorithm>.<execution-mode>[.<estimate>](
configuration: Map
)
本章的详细章节包括具体的语法概述和示例。
中心性算法
本章为Neo4j图形数据科学库中的中心性算法提供解释和示例。
中心性算法被用于确定网络中特定节点的重要性。Neo4j GDS库中包含以下中心性算法并根据质量进行了分组。
Production-quality
- Page Rank
- Betweenness Centrality
Alpha - ArticleRank
- Closeness Centrality
- Harmonic Centrality
- Degree Centrality
- Eigenvector Centrality
- HITS
PageRank
本节描述Neo4j GDS库中的PageRank算法。
1.介绍
PageRank算法根据传入关系的数量和相应源节点的重要性来度量图中每个节点的重要性。粗略地说,基本假设是一个页面只和链接到它的页面一样重要。
PageRank在最初的Google论文中是作为一个函数引入的,其数学表达式如下:
在这里,
- 我们假设页面A有指向它的T1到Tn页。
- d是一个阻尼系数,可以设置在[0,1)之间。通常设置为0.85。
- C(A)是指从A页指出的链接数。
运行此算法需要足够的内存可用性。在运行这个算法之前,建议使用Memory Estimation。
2.注意事项
使用PageRank算法时需要注意以下几点:
- 如果页面组内没有指向组外的链接,则该组被视为spider trap。
- 当一个页面网络正在形成一个无限循环时,可能会发生排名下降。
- 当页面没有输出链接时,就会出现Dead-ends。如果一个页面包含指向另一个没有指出链接的页面的链接,则该链接称为 dangling link。
改变阻尼因子(damping factor)的值有助于解决这些问题。它可以被解释为一个web surfer跳转到一个随机页面的概率,因此不会陷入下降。
3.语法
本节介绍用于在每个执行模式中执行PageRank算法的语法。我们将描述语法的命名图变体。要了解有关常规语法变体的更多信息,请参阅语法概述。
例 1. 各个模式下的PageRank 语法
在命名图中运行PageRank算法
stream模式
CALL gds.pageRank.stream(
graphName: String,
configuration: Map
)
YIELD
nodeId: Integer,
score: Float
表1. 参数
名称 | 类型 | 默认 | 是否可选 | 描述 |
---|---|---|---|---|
graphName | String | n/a | no | 目录中存储的图名称 |
configuration | Map | {} | yes | 算法细节和/或图形过滤器的配置 |
表2. 在命名图上执行算法的一般配置
名称 | 类型 | 默认 | 是否可选 | 描述 |
---|---|---|---|---|
nodeLabels | String[] | [’*’] | yes | 通过给定的节点标签过滤命名图 |
relationshipTypes | String[] | [’*’] | yes | 通过给定的关系标签过滤命名图 |
concurrency | Integer | 4 | yes | 用于运行算法的并发线程数 |
表3. 算法特殊配置
名称 | 类型 | 默认 | 是否可选 | 描述 |
---|---|---|---|---|
dampingFactor | Float | 0.85 | yes | PageRank算法的阻尼系数,必须在[0,1)之间 |
maxIterations | Integer | 20 | yes | 运行PageRank的最大迭代次数 |
tolerance | Float | 0.0000001 | yes | 迭代之间score的最小变化。如果所有score的变化小于tolerance,则认为结果是稳定的,返回算法结果 |
sourceNodes | List | [] | yes | 用于计算个性化PageRank的一组节点 |
表4. 结果
名称 | 类型 | 描述 |
---|---|---|
nodeId | Integer | Node ID. |
score | Float | PageRank score. |
stats模式
CALL gds.pageRank.stats(
graphName: String,
configuration: Map
)
YIELD
ranIterations: Integer,
didConverge: Boolean,
createMillis: Integer,
computeMillis: Integer,
postProcessingMillis: Integer,
centralityDistribution: Map,
configuration: Map
表5. 参数 同表1
表6. 在命名图上执行算法的一般配置 同表2
表7. 算法特殊配置 表3
名称 | 类型 | 默认 | 是否可选 | 描述 |
---|---|---|---|---|
relationshipWeightProperty | String | null | yes | 如果设置,则在计算过程中将存储在给定属性中的值将用作关系权重。如果未设置,则认为图无权重 |
表8. 结果
名称 | 类型 | 描述 |
---|---|---|
ranIterations | Integer | 迭代次数 |
didConverge | Boolean | 指示算法是否收敛 |
createMillis | Integer | 用于创建图形的时间(毫秒) |
computeMillis | Integer | 用于运行算法的时间(毫秒) |
postProcessingMillis | Integer | 用于计算中心分布的时间(毫秒) |
centralityDistribution | Map | 包含最小值、最大值、平均值以及中心度值p50、p75、p90、p95、p99和p999百分位值的map |
configuration | Map | 算法运行配置 |
mutate模式
CALL gds.pageRank.mutate(
graphName: String,
configuration: Map
)
YIELD
nodePropertiesWritten: Integer,
ranIterations: Integer,
didConverge: Boolean,
createMillis: Integer,
computeMillis: Integer,
postProcessingMillis: Integer,
mutateMillis: Integer,
centralityDistribution: Map,
configuration: Map
表9. 参数 同表1
表10. 在命名图上执行算法的一般配置 表2
名称 | 类型 | 默认 | 是否可选 | 描述 |
---|---|---|---|---|
mutateProperty | String | n/a | no | GDS图形中写入score的节点属性 |
表11. 算法特殊配置 同表7
表12. 结果 表8
名称 | 类型 | 描述 |
---|---|---|
mutateMillis | Integer | 向内存图中添加属性用时(毫秒) |
nodePropertiesWritten | Integer | 写入内存图中的属性数量 |
write模式
CALL gds.pageRank.write(
graphName: String,
configuration: Map
)
YIELD
nodePropertiesWritten: Integer,
ranIterations: Integer,
didConverge: Boolean,
createMillis: Integer,
computeMillis: Integer,
postProcessingMillis: Integer,
writeMillis: Integer,
centralityDistribution: Map,
configuration: Map
表13. 参数 同表1
表14. 在命名图上执行算法的一般配置 表2
名称 | 类型 | 默认 | 是否可选 | 描述 |
---|---|---|---|---|
writeConcurrency | Integer | value of ‘concurrency’ | yes | 用于写入Neo4j结果的并发线程数量 |
writeProperty | String | n/a | no | Neo4j数据库中写入score的节点属性 |
表15. 算法特殊配置 同表7
表16. 结果 表8
名称 | 类型 | 描述 |
---|---|---|
writeMillis | Integer | 向Neoo4j数据库写入属性用时(毫秒) |
nodePropertiesWritten | Integer | 写入内存图中的属性数量 |
匿名图
也可以在投影图的同时执行算法。在本例中,图没有名称,我们称之为匿名图。在匿名图上执行时,配置map包含图投影配置以及算法配置。所有的执行模式都支持在匿名图上执行,不过为了简洁起见,我们只显示了write模式的语法和基于特定于模式的配置。
有关语法变体的更多信息,请参阅语法概述。
在匿名图上以写模式运行PageRank:
CALL gds.pageRank.write(
configuration: Map
)
YIELD
nodePropertiesWritten: Integer,
ranIterations: Integer,
didConverge: Boolean,
createMillis: Integer,
computeMillis: Integer,
writeMillis: Integer,
centralityDistribution: Map,
configuration: Map
表17. 在命名图上执行算法的一般配置
名称 | 类型 | 默认 | 是否可选 | 描述 |
---|---|---|---|---|
nodeProjection | String, String[] or Map | null | yes | 用于创建匿名图的节点投影 |
relationshipProjection | String, String[] or Map | null | yes | 用于创建匿名图的关系投影 |
nodeQuery | String | null | yes | 通过Cypher投影为匿名图创建选择节点的Cypher查询语句 |
relationshipQuery | String | null | yes | 通过Cypher投影为匿名图创建选择关系的Cypher查询语句 |
nodeProperties | String, String[] or Map | null | yes | 匿名图创建时需投影的节点属性 |
relationshipProperties | String, String[] or Map | null | yes | 匿名图创建时需投影的关系属性 |
concurrency | Integer | 4 | yes | 用于运行算法的并发线程数。还提供“readConcurrency”和“writeConcurrency”的默认值 |
readConcurrency | Integer | value of ‘concurrency’ | yes | 用于创建图形的并发线程数 |
writeConcurrency | Integer | value of ‘concurrency’ | yes | 用于将结果写入Neo4j的并发线程数 |
writeProperty | String | n/a | no | score写入Neo4j数据库中的节点属性 |
表18. 算法特殊配置
名称 | 类型 | 默认 | 是否可选 | 描述 |
---|---|---|---|---|
dampingFactor | Float | 0.85 | yes | PageRank算法的阻尼系数,必须在[0,1)之间 |
maxIterations | Integer | 20 | yes | 运行PageRank的最大迭代次数 |
tolerance | Float | 0.0000001 | yes | 迭代之间score的最小变化。如果所有score的变化小于tolerance,则认为结果是稳定的,返回算法结果 |
relationshipWeightProperty | String | null | yes | 如果设置,则在计算过程中将存储在给定属性中的值将用作关系权重。如果未设置,则认为图无权重 |
sourceNodes | List | [] | yes | 用于计算个性化PageRank的一组节点 |
结果与使用命名图运行write mode的结果相同,请参阅上面的write mode语法。
4. 例子
在本节中,我们将展示在具体图形上运行PageRank算法的示例。其目的是说明结果是什么样的,并为如何在实际环境中使用该算法提供指导。我们将在一个由以特定模式连接的少数节点组成的小型web网络图上执行此操作。示例图如下所示:
下面的Cypher语句将在Neo4j数据库中创建示例图:
CREATE
(home:Page {name:'Home'}),
(about:Page {name:'About'}),
(product:Page {name:'Product'}),
(links:Page {name:'Links'}),
(a:Page {name:'Site A'}),
(b:Page {name:'Site B'}),
(c:Page {name:'Site C'}),
(d:Page {name:'Site D'}),
(home)-[:LINKS {weight: 0.2}]->(about),
(home)-[:LINKS {weight: 0.2}]->(links),
(home)-[:LINKS {weight: 0.6}]->(product),
(about)-[:LINKS {weight: 1.0}]->(home),
(product)-[:LINKS {weight: 1.0}]->(home),
(a)-[:LINKS {weight: 1.0}]->(home),
(b)-[:LINKS {weight: 1.0}]->(home),
(c)-[:LINKS {weight: 1.0}]->(home),
(d)-[:LINKS {weight: 1.0}]->(home),
(links)-[:LINKS {weight: 0.8}]->(home),
(links)-[:LINKS {weight: 0.05}]->(a),
(links)-[:LINKS {weight: 0.05}]->(b),
(links)-[:LINKS {weight: 0.05}]->(c),
(links)-[:LINKS {weight: 0.05}]->(d);
这个图表表示八页,彼此链接。每个关系都有一个称为weight的属性,它描述了关系的重要性。
在下面的示例中,我们将使用命名图和本地投影作为规范。但是,也可以使用匿名图或Cypher投影。
下面的语句将使用本地投影创建一个图,将其命名为“myGraph”并存储在图目录中:
CALL gds.graph.create(
'myGraph',
'Page',
'LINKS',
{
relationshipProperties: 'weight'
}
)
4.1. 内存估计
首先,我们将使用估算过程估算运行该算法的成本。这可以通过任何执行模式完成。在本例中,我们将使用write模式。估计算法对于理解在图形上运行算法将产生的内存影响非常有用。当您稍后实际在其中一种执行模式下运行算法时,系统将执行估计。如果估计表明执行超过其内存限制的可能性非常高,则禁止执行。要了解更多信息,请参阅自动估计和执行阻塞。
有关一般估计的更多详细信息,请参阅内存估计。
下面将估计运行算法所需的内存:
CALL gds.pageRank.write.estimate('myGraph', {
writeProperty: 'pageRank',
maxIterations: 20,
dampingFactor: 0.85
})
YIELD nodeCount, relationshipCount, bytesMin, bytesMax, requiredMemory
表19. 结果
节点数量 | 关系数量 | 最小字节数 | 最大字节数 | 所需内存 |
---|---|---|---|---|
8 | 14 | 856 | 856 | “856 Bytes” |
4.2. Stream
在stream执行模式下,算法返回每个节点的得分。这使我们能够直接检查结果或在Cypher中对结果进行后处理,而不会产生任何副作用。例如,我们可以对结果进行排序,以找到PageRank得分最高的节点。
以下语句将以stream模式运行算法:
CALL gds.pageRank.stream('myGraph')
YIELD nodeId, score
RETURN gds.util.asNode(nodeId).name AS name, score
ORDER BY score DESC, name ASC
表20. 结果
Table 20. Results
name | score |
---|---|
“Home” | 3.2362018343177623 |
“About” | 1.0611098931171001 |
“Links” | 1.0611098931171001 |
“Product” | 1.0611098931171001 |
“Site A” | 0.3292259060894139 |
“Site B” | 0.3292259060894139 |
“Site C” | 0.3292259060894139 |
“Site D” | 0.3292259060894139 |
上面的查询在stream模式下以未加权的方式运行算法。4.6是一个加权的例子
我们使用stream模式来说明算法是以加权还是非加权的方式运行的,所有的算法模式都支持这个配置参数。
4.3. Stats
在stats执行模式中,算法返回一行,其中包含算法结果的摘要。例如,PageRank stats返回中心性直方图,该直方图可用于展示PageRank得分值在所有计算节点上的分布。这种执行模式没有任何其他作用。通过检查computeMillis返回项,可以对算法性能进行评估。在下面的例子中,我们将省略返回计时。完整程序可以在syntax部分找到。
有关stats模式的更多详细信息,请参阅stats。
下面将运行算法并以统计值和测量值的形式返回结果:
CALL gds.pageRank.stats('myGraph', {
maxIterations: 20,
dampingFactor: 0.85
})
YIELD centralityDistribution
RETURN centralityDistribution.max AS max
表21. 结果
max |
---|
3.236204147338867 |
中心性直方图可用于检查计算的score或执行标准化。
4.4. Mutate
mutate执行模式扩展了stats模式,产生了一个重要的其他作用:使用包含该节点得分的新节点属性更新命名图。新属性的名称是使用必需的配置参数mutateProperty指定的。结果是一个单独的摘要行,类似于stats,但是有一些额外的度量。当结合使用多个算法时,mutate模式特别有用。
有关mutate模式的更多详细信息,请参见mutate。
以下语句将在mutate模式下运行算法:
CALL gds.pageRank.mutate('myGraph', {
maxIterations: 20,
dampingFactor: 0.85,
mutateProperty: 'pagerank'
})
YIELD nodePropertiesWritten, ranIterations
表22. 结果
nodePropertiesWritten | ranIterations |
---|---|
8 | 20 |
4.5. Write
write-execution模式扩展了stats模式,产生了一个重要的其他作用:将每个节点的score作为属性写入Neo4j数据库。新属性的名称是使用必需的配置参数writeProperty指定的。结果是一个单独的摘要行,类似于stats,但是有一些额外的度量。写入模式允许直接将结果持久化到数据库。
有关write模式的详细信息,请参阅write。
以下语句将在write模式下运行算法:
CALL gds.pageRank.write('myGraph', {
maxIterations: 20,
dampingFactor: 0.85,
writeProperty: 'pagerank'
})
YIELD nodePropertiesWritten, ranIterations
表23. 结果
nodePropertiesWritten | ranIterations |
---|---|
8 | 20 |