apoc.diff.graphs 过程
该过程接受 2 个字符串参数,即 source 和 dest,分别代表要进行比较的 2 条查询语句,以及作为第 3 个参数的可选 config 映射。
该过程对 source 和 dest 两个图进行比较,并返回以下方面的差异:
-
相同节点计数
-
每个标签的相同计数
-
相同关系计数器
-
每个关系类型的相同计数
对于 source 图中具有特定标签的每个节点,通过键或内部 ID 在另一个图(dest 图)中查找相同的节点。如果找到,则:* 比较所有标签 * 比较所有属性
请注意,查找节点时会利用现有的约束来寻找等效节点。若要使用内部 ID 查找节点,可以使用 findById:true 配置(见下文)。
对于 source 图中的每段关系,我们将获取该关系的两个节点,并在 dest 图中查看是否存在具有相同属性和相同起始/结束节点的关系。
该过程支持以下 config 参数
| 名称 (name) | type | 默认 | description(描述) |
|---|---|---|---|
findById |
boolean |
false |
通过 ID 查找节点,而不是使用现有约束 |
relsInBetween |
boolean |
false |
如果启用,则在查询返回关系以及开始或结束节点的情况下,考虑其他终端节点。 |
boltConfig |
Map |
{} |
在 |
source |
Map |
{} |
见下文 |
dest |
Map |
{} |
见下文 |
source 和 dest 映射分别应用于第 1 个和第 2 个过程参数,它们可以包含以下键
| 名称 (name) | type | 默认 | description(描述) |
|---|---|---|---|
target(目标) |
Map |
{} |
见下文 |
params |
Map |
{} |
用于传递额外的查询参数 |
target 参数接受
| 名称 (name) | type | 默认 | description(描述) |
|---|---|---|---|
type |
Enum[URL, DATABASE] |
|
使用外部 bolt URL 搜索 |
值 |
字符串 |
{} |
在配置 |
使用示例
在 neo4j 中给定此数据集
CREATE CONSTRAINT IF NOT EXISTS FOR (p:Person) REQUIRE p.name IS UNIQUE;
CREATE (m:Person {name: 'Michael Jordan', age: 54});
CREATE (q:Person {name: 'Tom Burton', age: 23})
CREATE (p:Person {name: 'John William', age: 22})
CREATE (q)-[:KNOWS{since:2016, time:time('125035.556+0100')}]->(p);
我们可以比较同一数据库中的 2 个集合
CALL apoc.diff.graphs("MATCH (start:Person) WHERE start.age < $age RETURN start", "MATCH (start:Person) WHERE start.age > $age RETURN start", {source: {params: {age: 25}}, dest: {params: {age: 25}}})
| difference | entityType | id | sourceLabel | destLabel | source | dest |
|---|---|---|---|---|---|---|
"Total count" |
"Node" |
null |
null |
null |
2 |
1 |
"Count by Label" |
"Node" |
null |
null |
null |
{"Person": 2 } |
|
{"Person": 1 } |
"Destination Entity not found" |
"Node" |
1 |
"Person" |
null |
{"name": "Tom Burton" } |
null |
"Destination Entity not found" |
"Node" |
2 |
"Person" |
null{"name": "John William" } |
null |
如果我们要在新的 secondDb 数据库中创建另一个数据集
CREATE CONSTRAINT IF NOT EXISTS FOR (p:Person) REQUIRE p.name IS UNIQUE;
CREATE (m:Person:Other {name: 'Michael Jordan', age: 54}),
(n:Person {name: 'Tom Burton', age: 47}),
(q:Person:Other {name: 'Jerry Burton', age: 23}),
(p:Person {name: 'Jack William', age: 22}),
(q)-[:KNOWS{since:1999, time:time('125035.556+0100')}]->(p);
我们可以在 neo4j 数据库中执行
CALL apoc.diff.graphs("MATCH p = (start:Person)-[rel:KNOWS]->(end) RETURN start, rel, end",
"MATCH p = (start)-[rel:KNOWS]->(end) RETURN start, rel, end",
{dest: {target: {type: "DATABASE", value: "secondDb"}}})
| difference | entityType | id | sourceLabel | destLabel | source | dest |
|---|---|---|---|---|---|---|
"Destination Entity not found" |
"Node" |
1 |
"Person" |
null |
{"name": "Tom Burton" } |
null |
"Destination Entity not found" |
"Node" |
2 |
"Person" |
null |
{"name": "John William"} |
null |
"Destination Entity not found" |
"Relationship" |
0 |
"KNOWS" |
null |
{"start":{"name":"Tom Burton"},"end":{"name":"John William"},"properties":{"time":"12:50:35.556000000+01:00","since":2016}} |
null |
反之,我们可以从 secondDb 数据库开始比较 2 个数据集
CALL apoc.diff.graphs("MATCH (node:Person) RETURN node",
"MATCH (node:Person) RETURN node",
{dest: {target: {type: "DATABASE", value: "neo4j"}}})
| difference | entityType | id | sourceLabel | destLabel | source | dest |
|---|---|---|---|---|---|---|
"Total count" |
"Node" |
null |
null |
null |
6 |
3 |
"Count by Label" |
"Node" |
null |
null |
null |
{"Person": 4, "Other": 2 } |
|
{"Person": 3 } |
"Different Labels" |
"Node" |
0 |
"Person" |
"Person" |
["Other", "Person"] |
["Person"] |
"Different Properties" |
"Node" |
1 |
"Person" |
"Person" |
{"age": 47 } |
{"age": 23 } |
"Destination Entity not found" |
"Node" |
2 |
"Person" |
null |
{"name": "Jerry Burton" } |
null |
"Destination Entity not found" |
"Node" |
7 |
"Person" |
null |
{"name": "Jack William" } |
如果我们创建另一个具有与 seconddb 相同数据集的 dbms 实例,我们可以利用 apoc.bolt.load 比较这两个图
CALL apoc.diff.graphs("MATCH p = (start:Person)-[rel:KNOWS]->(end) RETURN start, rel, end", "MATCH p = (start)-[rel:KNOWS]->(end) RETURN start, rel, end", {dest: {target: {type: "URL", value: "<MY_BOLT_URL>"}}})
| difference | entityType | id | sourceLabel | destLabel | source | dest |
|---|---|---|---|---|---|---|
"Destination Entity not found" |
"Node" |
1 |
"Person" |
null |
{"name": "Tom Burton" } |
null |
"Destination Entity not found" |
"Node" |
2 |
"Person" |
null |
{"name": "John William"} |
null |
"Destination Entity not found" |
"Relationship" |
0 |
"KNOWS" |
null |
{"start":{"name":"Tom Burton"},"end":{"name":"John William"},"properties":{"time":"12:50:35.556000000+01:00","since":2016}} |
null |
如果我们想要指向远程 target 实例中存在的 secondDestDb 数据库,我们可以传递 boltConfig 参数,向 apoc.bolt.load(url, query, params, <boltConfig>) 传递附加参数。在这种情况下,我们可以传递 databaseName,即
CALL apoc.diff.graphs("MATCH p = (start:Person)-[rel:KNOWS]->(end) RETURN start, rel, end", "MATCH p = (start)-[rel:KNOWS]->(end) RETURN start, rel, end", {boltConfig: {databaseName: "secondDestDb"}, dest: {target: {type: "URL", value: "bolt://neo4j:apoc@localhost:7687"}}})
如果数据集相同,结果与上述相同。