虚拟资源
所有这些存储过程(列表和显示相关的除外)都旨在系统数据库中执行,因此必须通过打开系统数据库会话来使用它们。有几种方法可以实现这一点:- 当使用 cypher-shell 或 Neo4j Browser 时,可以在 Cypher 查询前加上 此外,它们将想要安装/更新/移除自动 UUID 的目标数据库名称作为第一个参数。通过这种实现,我们可以利用集群路由机制在集群环境中使用这些存储过程。 |
在某些情况下,我们希望用来自外部源的额外数据来丰富/补充 Neo4j 图中 Cypher 查询的结果,而这些数据我们无法(或不想)加载并持久化到图中。 例如,想象一个具有网络拓扑的 Neo4j 图:所有的设备、它们之间的连接、依赖关系等等。你想要查询某个特定站点中的所有设备,并返回过去两小时的性能指标。这是“时间序列数据”,你可能不想将其导入并持久化到图中。apoc.dv 提供了在查询时按需访问该信息并将其与图中的网络拓扑数据无缝结合的选项。 |
APOC 扩展库支持定义虚拟资源目录。虚拟资源是 Neo4j 可以用来按需查询和检索数据、将其呈现为虚拟节点以丰富图中存储数据的外部数据源。虚拟资源目录特性结合了 APOC 的两个元素:
-
用于从外部源查询数据的 apoc.load.* 存储过程。
-
创建临时图结构(可作为查询结果返回但永不持久化到图中)的虚拟存储过程。
从宏观上看,虚拟资源目录特性将外部数据源连接的定义与实际查询解耦。它提供了管理虚拟化资源目录(创建/移除/修改虚拟化资源)以及查询这些资源的存储过程。当前版本支持关系型数据库 (RDB) 数据源和 CSV 文件。

以下示例的图和 RDB
本示例使用存储在 Postgres 中的数据库。您可以使用此脚本重新创建它。它只包含三个表

我们已将区域和部门导入到 Neo4j 中(导入脚本作为附件提供),但未导入城镇,我们将把城镇虚拟化,仅在需要时从 RDB 检索。图看起来像这样(片段)

通过 JDBC 管理虚拟化资源
创建虚拟化资源 (JDBC)
在查询虚拟化资源之前,我们需要对其进行定义。我们使用 apoc.dv.catalog.install
存储过程来实现这一点。该存储过程接受三个参数
-
唯一标识虚拟化资源并可用于查询该资源的名称
-
我们想要使用该资源的数据库名称(默认为
'neo4j'
) -
一组参数,指示资源的类型 (type)、访问点 (url)、将在访问点上运行的参数化查询 (query) 以及将应用于生成的虚拟节点的标签 (labels)。
我们正在定义一个通过关系型数据库 (type: JDBC) 进行虚拟化的资源,该资源可在本地访问 (url: "jdbc:postgresql://localhost/communes?user=jb&password=jb"),它将返回我们将其类型设置为 Town 和 PopulatedPlace 的节点——生成的节点将有两个标签 (labels: ["Town","PopulatedPlace"]
)。我们还提供了包含所需参数的 SQL 查询,这些参数将在查询时传递。最后,我们可以包含一段描述性信息,帮助用户理解虚拟化资源生成的内容以及如何使用它。下面是创建此类虚拟化资源的 Cypher 查询
CALL apoc.dv.catalog.install("fr-towns-by-dept", "neo4j", {
type: "JDBC",
url: "jdbc:postgresql://localhost/communes?user=jb&password=jb",
labels: ["Town","PopulatedPlace"],
query: "SELECT code, name FROM towns where department = $dept_no",
desc: "french towns by department number"
})
有关如何传递凭据以访问 RDB 的更多详细信息,请查阅 加载 JDBC 文档。
查询虚拟化资源 (JDBC)
定义后,我们可以通过名称查询虚拟化资源,只需传递所需的参数即可。我们为此使用 apoc.dv.query 存储过程。它接受两个参数
-
虚拟化资源的名称
-
包含所需参数的映射。
CALL apoc.dv.query("fr-towns-by-dept", { dept_no: "73" })
查询返回一组虚拟节点,这些节点是根据虚拟化资源中定义的查询和在 apoc.dv.query
调用中传递的参数按需生成的。

通常,我们会希望将此存储过程调用与 Neo4j 图中的数据结合使用。下面是一个示例
WITH "Basse-Normandie" AS reg_name
MATCH (dep:Region { name: reg_name})-[:HAS_DEPT]->(d:Department)
CALL apoc.dv.query("fr-towns-by-dept",{dept_no: d.code}) YIELD node
RETURN node
我们甚至可以将 apoc.dv.query 返回的虚拟化节点链接到图中的真实节点,以提供更丰富的查询结果。这就是 apoc.dv.queryAndLink 方法的用途。apoc.dv.queryAndLink 方法接受两个附加参数:用于链接虚拟节点的节点,以及用于链接的关系类型
MATCH (dep:Region { name: $regionName })-[hd:HAS_DEPT]->(d:Department)
CALL apoc.dv.queryAndLink(d,"HAS_TOWN", "fr-towns-by-dept",{ dept_no: d.code }) YIELD path
RETURN *
apoc.dv.queryAndLink
方法返回由作为第一个参数传递的节点以及从虚拟化资源返回的虚拟节点和关系组成的路径。
下面是 Bloom 中使用上述查询的示例。所有代表给定部门中城镇的蓝色节点都是按需检索的虚拟节点,使用了基于先前查询的搜索短语。

关系的默认方向是出站的(即 {direction: "OUT"}
),但可以通过配置参数来反转方向。例如
MATCH (hook:Hook) WITH hook
CALL apoc.dv.queryAndLink(hook, $relType, $name, $queryParams, { direction: "IN" }) yield path
RETURN path
列出虚拟化资源目录
apoc.dv.catalog.list 存储过程返回所有现有虚拟化资源及其描述的列表。它接受一个参数:即我们想要使用该资源的数据库名称(默认为 'neo4j')。
CALL apoc.dv.catalog.show()
从目录中移除虚拟化资源
当不再需要虚拟化资源时,可以通过使用 apoc.dv.catalog.remove 存储过程并传递 VR 的唯一名称作为参数将其从目录中移除。
CALL apoc.dv.catalog.drop("vr-name", <dbName>)
导出元数据
要在另一个数据库中导入 dv 目录(例如,在执行 |
通过 CSV 文件管理虚拟化资源
创建虚拟化资源 (CSV)
基于 CSV 文件定义虚拟化资源的过程与关系型数据库的定义过程相同,但查询参数除外。
让我们考虑一个示例,图谱中有一个产品目录,但有一些关于产品的额外信息,例如当前库存、单价、再订购点,出于某种原因,这些信息维护在图谱外部的独立存储中(在本例中是文件)。我们将展示如何使用 apoc.dv 无缝结合这两部分信息。
让我们看另一个示例,我们在一个可通过 HTTP 访问的 CSV 文件上定义一个虚拟化资源 (type: CSV) (url: "http://data.neo4j.com/northwind/products.csv"),它将返回我们类型化为 ProductDetails 的节点 (labels: ["ProductDetails"])。关于查询,不像关系型数据库那样有标准的查询语言,因此我们使用类似 Cypher 的符号,使用 map
前缀来引用解析 CSV 文件返回的记录 (query: "map.productID = $prod_id")。请注意,文件也可以使用 file://
协议而不是 http://
在本地访问。
下面是创建此类虚拟化资源的 Cypher 查询
CALL apoc.dv.catalog.install("prod-details-by-id", "neo4j", {
type: "CSV",
url: "http://data.neo4j.com/northwind/products.csv",
labels: ["ProductDetails"],
query: "map.productID = $prod_id",
desc: "Product Details By ID"
})
查询虚拟化资源 (CSV)
与 JDBC 的情况相同,我们可以通过名称查询虚拟化 CSV 资源,只需传递所需的参数即可
CALL apoc.dv.query("prod-details-by-id", { prod_id: "3" })
在本例中,查询返回一个虚拟节点,该节点是通过解析定义为虚拟化资源的 CSV 文件并使用在 apoc.dv.query 调用中传递的参数应用查询参数中的表达式来过滤记录而按需生成的(显示返回的虚拟节点的表格视图)。

将此存储过程调用与 Neo4j 图中的数据结合使用的示例
MATCH (p:Product { productName: "Northwoods Cranberry Sauce"})
CALL apoc.dv.query("prod-details-by-id",{ prod_id: p.productId }) YIELD node as details
RETURN p.productName as prodName,
apoc.any.property(details, "unitsInStock") as unitsInStock,
apoc.any.property(details, "reorderLevel") as reorderLevel,
apoc.any.property(details, "quantityPerUnit") as quantityPerUnit,
apoc.any.property(details, "unitPrice") as unitPrice
产生以下输出

在本例中,我们生成了一个表格结果,结合了图中的数据和从虚拟化 CSV 资源按需检索的数据。请注意,为了访问虚拟节点中的属性值,我们需要使用 apoc.any.property 函数。
如果希望将查询返回的虚拟化节点链接到图中的真实节点,我们将按如下方式使用 apoc.dv.queryAndLink 方法
MATCH (p:Product { productName: "Northwoods Cranberry Sauce" })
CALL apoc.dv.queryAndLink(p, "HAS_DETAILS", "prod-details-by-id", { prod_id: p.productId }) YIELD path
RETURN *
在 Neo4j 浏览器中产生此输出
