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
优化Cypher查询Neo4j_Neo4j_Cypher_Graph Databases - Fatal编程技术网

优化Cypher查询Neo4j

优化Cypher查询Neo4j,neo4j,cypher,graph-databases,Neo4j,Cypher,Graph Databases,我想用Cypher编写一个查询并在Neo4j上运行它 查询是: 给定一些起始顶点,遍历边并找到所有连接到任一起始顶点的顶点 (start)-[*]->(v) 每走一条路,我都会走 if startVertex(E).someproperty != endVertex(E).someproperty, output E. 该图可能包含循环 例如,在上图中,顶点按“group”属性分组。查询应返回7行,表示图中的7条橙色边 如果我自己编写算法,它将是一个简单的深度/广度优先搜索,如果过滤

我想用Cypher编写一个查询并在Neo4j上运行它

查询是:

给定一些起始顶点,遍历边并找到所有连接到任一起始顶点的顶点

(start)-[*]->(v)
每走一条路,我都会走

if startVertex(E).someproperty != endVertex(E).someproperty, output E.
该图可能包含循环

例如,在上图中,顶点按“group”属性分组。查询应返回7行,表示图中的7条橙色边

如果我自己编写算法,它将是一个简单的深度/广度优先搜索,如果过滤条件为真,则对访问的每条边输出此边。复杂性为O(V+E)

但是我不能用密码来表达这个算法,因为它是一种非常不同的语言

然后我写了这个查询:

查找所有可到达的顶点

(start)-[*]->(v), reachable = start + v. 
从任何可到达的边开始查找所有边。如果边以任何可到达顶点结束并通过过滤器,则输出它

match (reachable)-[]->(n) where n in reachable and reachable.someprop != n.someprop
所以密码是这样的:

MATCH (n:Col {schema:"${DWMDATA}",table:"CHK_P_T80_ASSET_ACCT_AMT_DD"})
WITH n MATCH (n:Col)-[*]->(m:Col)
WITH collect(distinct n) + collect(distinct m) AS c1
UNWIND c1 AS rn
MATCH (rn:Col)-[]->(xn:Col) WHERE rn.schema<>xn.schema and xn in c1
RETURN rn,xn
MATCH(n:Col{schema:${DWMDATA}),表:“CHK_P_T80_ASSET_act_AMT_DD”})
与n匹配(n:Col)-[*]->(m:Col)
使用collect(不同的n)+collect(不同的m)作为c1
将c1作为rn展开
匹配(rn:Col)-[]->(xn:Col),其中rn.schemaxn.schema和c1中的xn
返回rn,xn
这个查询的性能不如我想象的那么好。在:列(架构)上有索引

我正在windows笔记本电脑上从dockerhub运行neo4j 2.3.0 docker映像。实际上它在我笔记本电脑上的linux虚拟机上运行

我的示例数据是一个包含0.1M顶点和0.5M边的小数据集。对于某些起始节点,完成此查询需要60秒或更长时间。对优化或重写查询有什么建议吗?谢谢

以下代码块是我想要的逻辑:

 VertexQueue1 = (starting vertexes);
 VisitedVertexSet = (empty);
 EdgeSet1 = (empty);
 While (VertexSet1 is not empty)
 {
     Vertex0 = VertexQueue1.pop();
     VisitedVertexSet.add(Vertex0);
     foreach (Edge0 starting from Vertex0)
     {
           Vertex1 = endingVertex(Edge0);
           if (Vertex1.schema <> Vertex0.schema)
           {
               EdgeSet1.put(Edge0);
           }
           if (VisitedVertexSet.notContains(Vertex1) 
               and VertexQueue1.notContains(Vertex1)) 
           {
               VertexQueue1.push(Vertex1);
           }
     }
 }
 return EdgeSet1;
VertexQueue1=(起始顶点);
VisitedVertexSet=(空);
EdgeSet1=(空);
While(VertexSet1不是空的)
{
Vertex0=VertexQueue1.pop();
VisitedVertexSet.add(Vertex0);
foreach(从顶点0开始的边0)
{
顶点1=结束顶点(边0);
if(Vertex1.schema Vertex0.schema)
{
EdgeSet1.put(Edge0);
}
if(VisitedVertexSet.notContains(Vertex1)
和VertexQueue1.notContains(Vertex1))
{
VertexQueue1.push(Vertex1);
}
}
}
返回边1;
编辑:

轮廓结果表明,扩展所有路径的成本很高。查看行号,似乎Cypher exec引擎返回所有路径,但我只需要distint edge list

左一:

match (start:Col {table:"F_XXY_DSMK_ITRPNL_IDX_STAT_W"})
,(start)-[*0..]->(prev:Col)-->(node:Col)
 where prev.schema<>node.schema 
return distinct prev,node
match(开始:Col{table:“F_XXY_DSMK_ITRPNL_IDX_statw})
,(开始)-[*0..]->(上一个:列)-->(节点:列)
其中prev.schemaAnode.schema
返回不同的上一个节点
正确的一点:

MATCH (n:Col {schema:"${DWMDATA}",table:"CHK_P_T80_ASSET_ACCT_AMT_DD"})
WITH n MATCH (n:Col)-[*]->(m:Col)
WITH collect(distinct n) + collect(distinct m) AS c1
UNWIND c1 AS rn
MATCH (rn:Col)-[]->(xn:Col) WHERE rn.schema<>xn.schema and xn in c1
RETURN rn,xn
MATCH(n:Col{schema:${DWMDATA}),表:“CHK_P_T80_ASSET_act_AMT_DD”})
与n匹配(n:Col)-[*]->(m:Col)
使用collect(不同的n)+collect(不同的m)作为c1
将c1作为rn展开
匹配(rn:Col)-[]->(xn:Col),其中rn.schemaxn.schema和c1中的xn
返回rn,xn

如果我理解查询,我认为Cypher让这比您预期的要容易得多。试试这个:

MATCH (start:Col {schema:"${DWMDATA}",table:"CHK_P_T80_ASSET_ACCT_AMT_DD"})-->(node:Col)
WHERE start.schema <> node.schema
RETURN start, node
不过,这种开放式的可变长度关系规范可能很慢

还要注意的是,当Cypher浏览一个特定路径时,它会停止浏览,并发现它被循环回到迄今为止匹配的路径中的某个节点(编辑关系,而不是节点),因此循环不是真正的问题

另外,您传入的
DWMDATA
值是插值的吗?如果是这样,您应该考虑使用安全/性能参数:

编辑:

根据你的评论,我有一些想法。首先限制为
不同的路径
不会有帮助,因为它找到的每个路径都是不同的。我认为,您需要的是一组不同的对,我认为可以通过向查询中添加
distinct
来实现:

MATCH
  (start:Col {schema:"${DWMDATA}",table:"CHK_P_T80_ASSET_ACCT_AMT_DD"})
  (start)-[*0..]->(prev:Col)-->(node:Col)
WHERE prev.schema <> node.schema
RETURN DISTINT prev, node
匹配
(开始:Col{schema:“${DWMDATA}”,表:“CHK_P_T80_ASSET_ACCT_AMT_DD”})
(开始)-[*0..]->(上一个:列)-->(节点:列)
其中prev.schema node.schema
返回DISTINT prev,节点
下面是另一种方法,可能更有效,也可能不更有效,但至少可以让你了解如何以不同的方式行事:

MATCH
  path=(start:Col {schema:"${DWMDATA}",table:"CHK_P_T80_ASSET_ACCT_AMT_DD"})-->(node:Col)
WITH rels(path) AS rels
UNWIND rels AS rel
WITH DISTINCT rel
WITH startNode(rel) AS start_node, endNode(rel) AS end_node
WHERE start_node.schema <> end_node.schema
RETURN start_node, end_node
匹配
path=(开始:Col{schema:${DWMDATA}),表:“CHK_P_T80_ASSET_ACCT_AMT_DD”}-->(节点:Col)
使用rels(路径)作为rels
将rel作为rel展开
具有明显的相关性
startNode(rel)作为开始节点,endNode(rel)作为结束节点
其中start_node.schema end_node.schema
返回开始节点,结束节点

我不能说这会更快,但这里有另一种尝试方法:

MATCH (start:Col)-[*]->(node:Col)
WHERE start.property IN {property_values}

WITH collect(ID(node)) AS node_ids

MATCH (:Col)-[r]->(node:Col)
WHERE ID(node) IN node_ids
WITH DISTINCT r
RETURN startNode(r) AS start_node, endNode(r) AS end_node
我怀疑所有情况下的问题都与开放式可变长度路径有关。事实上,我已经要求Slack小组试着更好地理解它是如何工作的。同时,对于您尝试的所有查询,我建议在它们前面加上
PROFILE
关键字,以便从Neo4j获得关于查询中哪些部分比较慢的报告

// this is very inefficient!
MATCH (start:Col)-[*]->(node:Col)
WHERE start.property IN {property_values}
WITH distinct node
MATCH (prev)-[r]->(node)
RETURN distinct prev, node;
您最好使用以下方法:

MATCH (start:Col)
WHERE start.property IN {property_values}

MATCH (node:Col)
WHERE shortestPath((start)-[*]->(node)) IS NOT NULL

MATCH (prev)-[r]->(node)
RETURN distinct prev, node;

谢谢你的回答:)我需要开放式可变长度关系。我运行了您答案中的第二段代码,它返回了start、prev和node的所有可能路径。在我的示例数据(v=0.1M)上,等待300秒后,查询返回了9M行。我认为对于我的数据,期望的输出应该是大约300行(代表300条不同的边)。我添加了
(prev)->[path]->(node)返回不同的路径
,但它不影响EXPLAIN输出的执行计划。有没有办法告诉neo4j“您只需要访问每个边缘和节点一次”并加快查询速度?通过添加DISTINCT,查询返回了DISTINCT对集,但性能没有提高。似乎执行引擎计算了所有可能的路径,我不需要所有不同的路径,只需要不同的边集就可以了。我添加了一个代码块
MATCH (start:Col)
WHERE start.property IN {property_values}

MATCH (node:Col)
WHERE shortestPath((start)-[*]->(node)) IS NOT NULL

MATCH (prev)-[r]->(node)
RETURN distinct prev, node;