Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/neo4j/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Neo4j:如何根据距离为每个节点找到下一个邻居并创建关系_Neo4j_Cypher - Fatal编程技术网

Neo4j:如何根据距离为每个节点找到下一个邻居并创建关系

Neo4j:如何根据距离为每个节点找到下一个邻居并创建关系,neo4j,cypher,Neo4j,Cypher,我导入了一大组节点(>16000),其中每个节点都包含有关位置的信息(纵向/横向地理数据)。所有节点都具有相同的标签。此场景中没有关系。现在,我想通过距离确定每个节点的下一个邻居,并在这些节点之间创建关系 这种(蛮力)方法对于包含大约1000个节点的集合非常有效:(1)我首先定义了包含距离信息的所有节点之间的关系。(2) 然后,我为所有关系定义了属性“mindist=false”。(3)之后,我确定了查看每个关系的距离信息的下一个邻居,并将“mindist”属性设置为“true”,其中关系表示最

我导入了一大组节点(>16000),其中每个节点都包含有关位置的信息(纵向/横向地理数据)。所有节点都具有相同的标签。此场景中没有关系。现在,我想通过距离确定每个节点的下一个邻居,并在这些节点之间创建关系

这种(蛮力)方法对于包含大约1000个节点的集合非常有效:(1)我首先定义了包含距离信息的所有节点之间的关系。(2) 然后,我为所有关系定义了属性“mindist=false”。(3)之后,我确定了查看每个关系的距离信息的下一个邻居,并将“mindist”属性设置为“true”,其中关系表示最短距离。(4) 最后,我删除了所有与“mindist=false”的关系

(一)

(三)

(四)


对于包含约16000个节点的集合,此解决方案不起作用(内存问题…)。我确信有一种更聪明的方法来解决这个问题(但目前我仍然缺乏使用neo4j/cypher的经验)。;-)

我认为,我们在Cypher中的选择仅限于对每个节点到其他节点的距离进行简单的O(n^2)暴力检查。如果您要编写一些定制Java来实现它(您可以将其公开为Neo4j插件),您可以

尽管如此,如果使用APOC将查询拆分为多个事务,您仍然可以使用图中任意数量的节点来执行此操作,而不会破坏堆。注意:您需要重新安装

让我们首先创建20000个测试数据点:

WITH range(0, 20000) as ids
WITH [x in ids | { id: x, loc: point({ x: rand() * 100, y: rand() * 100 }) }] as points
UNWIND points as pt
CREATE (p: Point { id: pt.id, location: pt.loc })
我们可能还需要一些索引:

CREATE INDEX ON :Point(id)
CREATE INDEX ON :Point(location)
通常,以下查询(暂时不要运行…)将为每个点节点创建一个列表,其中包含ID和到图形中每个其他点节点的距离,对该列表进行排序,使最近的一个位于顶部,从列表中提取第一项并创建对应关系

MATCH (p: Point)
MATCH (other: Point) WHERE other.id <> p.id
WITH p, [x in collect(other) | { id: x.id, dist: distance(p.location, x.location) }] AS dists
WITH p, head(apoc.coll.sortMaps(dists, '^dist')) AS closest
MATCH (closestPoint: Point { id: closest.id })
MERGE (p)-[:CLOSEST_TO]->(closestPoint)
第一个查询只返回所有点节点
apoc.periodic.iterate
将从该查询中获取20000个节点,并将它们分成100个批次,然后在每个批次中的每个节点上运行内部查询。在每个批处理之后,我们都会得到一个提交,并且我们的内存使用被限制为运行内部查询所需的任何成本


虽然不快,但确实完成了。在我的机器上,它在一个有20000个节点的图上每秒运行大约12个节点,但是随着图中节点数量的增加,成本呈指数增长。您将很快遇到这种方法无法很好地扩展的问题。

您可以使用APOC为批处理中的每个节点逐个查找最近的邻居。(这也是一种蛮力方式,但运行速度更快)。7322个节点大约需要75秒

CALL apoc.periodic.iterate("MATCH (n1:XXX) 
RETURN n1", "
WITH n1
MATCH (n2:XXX)
WHERE id(n1) <> id(n2)
WITH n1, n2, distance(n1.location,n2.location) as dist ORDER BY dist LIMIT 1
CREATE (n1)-[r:DISTANCE{dist:dist}]->(n2)", {batchSize:1, parallel:true, concurrency:10})
调用apoc.periodic.iterate(“匹配(n1:XXX))
返回n1“,”
带n1
匹配(n2:XXX)
其中id(n1)id(n2)
以n1,n2,距离(n1.位置,n2.位置)作为距离限值1的距离顺序
创建(n1)-[r:DISTANCE{dist:dist}]->(n2)”,{batchSize:1,parallel:true,concurrency:10})
注意:在此查询中,batchSize应始终为1。你可以改变 实验的并发性


如果有两个邻居在同一距离,会发生什么情况?在这种理论情况下,应该有两个或更多的关系(但我使用的是点后超过10位的真实地理数据。因此我认为这种情况不会发生。).您介意运行需要多长时间吗?对于1090个节点,大约10秒后完成步骤1。步骤2-4花了很多分钟(对不起,我不太清楚)。。。终于成功了,。。。但效率不高:-(我刚刚测试了代码。它工作正常,运行速度非常快!非常感谢!非常感谢您的解释!
WITH range(0, 20000) as ids
WITH [x in ids | { id: x, loc: point({ x: rand() * 100, y: rand() * 100 }) }] as points
UNWIND points as pt
CREATE (p: Point { id: pt.id, location: pt.loc })
CREATE INDEX ON :Point(id)
CREATE INDEX ON :Point(location)
MATCH (p: Point)
MATCH (other: Point) WHERE other.id <> p.id
WITH p, [x in collect(other) | { id: x.id, dist: distance(p.location, x.location) }] AS dists
WITH p, head(apoc.coll.sortMaps(dists, '^dist')) AS closest
MATCH (closestPoint: Point { id: closest.id })
MERGE (p)-[:CLOSEST_TO]->(closestPoint)
CALL apoc.periodic.iterate(
"
    MATCH (p: Point)
   RETURN p
",
"
   MATCH (other: Point) WHERE other.id <> p.id
    WITH p, [x in collect(other) | { id: x.id, dist: distance(p.location, x.location) }] 
AS dists
    WITH p, head(apoc.coll.sortMaps(dists, '^dist')) AS closest
   MATCH (closestPoint: Point { id: closest.id })
   MERGE (p)-[:CLOSEST_TO]->(closestPoint)
", { batchSize: 100 })
CALL apoc.periodic.iterate("MATCH (n1:XXX) 
RETURN n1", "
WITH n1
MATCH (n2:XXX)
WHERE id(n1) <> id(n2)
WITH n1, n2, distance(n1.location,n2.location) as dist ORDER BY dist LIMIT 1
CREATE (n1)-[r:DISTANCE{dist:dist}]->(n2)", {batchSize:1, parallel:true, concurrency:10})