虚拟资源

在某些情况下,我们希望用来自外部来源的其他数据来丰富/补充 Neo4j 图中 Cypher 查询的结果,而我们无法(**或不想**)将这些数据加载并持久化到图中。

例如,考虑一个包含网络拓扑结构的 Neo4j 图:所有设备、它们之间的连接、依赖项等。您希望查询特定站点中的所有设备并返回过去两小时的性能指标。这是“时间序列数据”,您可能不想将其导入并持久化到图中。apoc.dv 使您能够在查询时按需访问这些信息,并将其与图中的网络拓扑数据无缝结合。

APOC 扩展库支持定义虚拟资源目录。虚拟资源是 Neo4j 可以用来按需查询和检索数据的外部数据源,将其呈现为虚拟节点,从而丰富存储在图中的数据。虚拟资源目录功能结合了两个 APOC 元素

  • 查询外部数据源的apoc.load.* 过程

  • 创建临时图结构的虚拟过程,这些结构可以作为查询结果返回,但永远不会持久化到图中。

在高级别上,虚拟资源目录功能将外部数据源的连接定义与实际查询解耦。它提供了管理虚拟化资源目录(创建/删除/修改虚拟化资源)以及查询它们的程序。在当前版本中,支持关系型 (RDB) 数据源和 CSV 文件。

apoc.dv.high level

以下示例的图和 RDB

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

apoc.dv.rdb schema diagram

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

apoc.dv.imported graph from RDB

通过 JDBC 管理虚拟化资源

创建虚拟化资源 (JDBC)

在我们可以查询虚拟化资源之前,我们需要对其进行定义。我们使用 apoc.dv.catalog.add 过程来完成此操作。该过程采用两个参数

  • 唯一标识虚拟化资源的名称,可用于查询该资源

  • 一组参数,指示资源的类型(type)、访问点(url)、将在访问点上运行的参数化查询(query)以及将应用于生成的虚拟节点的标签(labels)。

我们正在定义一个基于关系数据库的虚拟化资源(type: **JDBC**),该数据库可以通过本地访问(url: "jdbc:postgresql://#/communes?user=jb&password=jb"),它将返回我们将类型化为Town和PopulatedPlace的节点 - 生成的节点将有两个标签(labels: ["Town","PopulatedPlace"])。我们还提供了SQL查询,包括它所需的和将在查询时传递的参数。最后,我们可以包含一个信息性描述,帮助用户理解虚拟化资源生成的内容以及如何使用它。以下是创建此类虚拟化资源的Cypher语句

CALL apoc.dv.catalog.add("fr-towns-by-dept", {
  type: "JDBC",
  url: "jdbc:postgresql://#/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调用中传递的参数按需生成。

apoc.dv.jdbc 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中使用先前查询的示例。所有代表给定部门中的城镇的蓝色节点都是使用先前查询上的搜索短语按需检索的虚拟节点。

apoc.dv.jdbc queryAndLink

列出虚拟化资源目录

apoc.dv.catalog.list过程返回一个列表,其中包含所有现有的虚拟化资源及其描述。它不接受任何参数。

CALL apoc.dv.catalog.list()

从目录中删除虚拟化资源

当不再需要虚拟化资源时,可以通过使用apoc.dv.catalog.remove过程并将VR的唯一名称作为参数传递来将其从目录中删除。

CALL apoc.dv.catalog.remove("vr-name")

导出元数据

要将dv目录导入到另一个数据库(例如,在./neo4j-admin backup/neo4j-admin restore之后),请参阅apoc.systemdb.export.metadata过程。

通过CSV文件管理虚拟化资源

创建虚拟化资源 (CSV)

在CSV文件上定义虚拟化资源的过程与关系数据库描述的过程相同,查询参数除外。

让我们考虑一个示例,其中我们在图中有一个产品目录,但还有一些关于产品的其他信息,例如当前库存、单价、重新订购级别,出于某种原因,这些信息保存在图外部的单独存储中(在这种情况下为文件)。我们将展示如何使用apoc.dv无缝地组合这两部分信息。

让我们看另一个示例,我们在此示例中定义了一个基于CSV文件的虚拟化资源(type: **CSV**),可以通过HTTP访问(**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.add("prod-details-by-id", {
  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调用中传递的参数来过滤记录而按需生成的(显示返回的虚拟节点的表格视图)。

apoc.dv.csv 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

生成以下输出

apoc.dv.csv query integrated

在这种情况下,我们正在生成一个表格结果,将来自图的数据与来自虚拟化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浏览器中生成此输出

apoc.dv.csv queryAndLink