我需要帮助解决问题并更好地理解Neo4j的机制。下面的文字很长,因为我试图尽可能详细地解释我的问题和尝试。
要介绍问题,请以下面的简单结构为例。每个节点都标记为Point
,有2个属性:point_id
和num
,point_id
用作节点代表。
CREATE (a:Point {point_id: 1, num: 1}),
(b:Point {point_id: 2, num: 1}),
(c:Point {point_id: 3, num: 1}),
(d:Point {point_id: 4, num: 2}),
(e:Point {point_id: 5, num: 2}),
(f:Point {point_id: 6, num: 1}),
(g:Point {point_id: 7, num: 2}),
(h:Point {point_id: 8, num: 2}),
(i:Point {point_id: 9, num: 1}),
(a)-[:NEXT]->(b),
(a)-[:NEXT]->(c),
(c)-[:NEXT]->(d),
(b)-[:NEXT]->(e),
(b)-[:NEXT]->(f),
(f)-[:NEXT]->(g),
(f)-[:NEXT]->(i),
(g)-[:NEXT]->(h),
(h)-[:NEXT]->(i);
假设我想选择从带有point_id = 1
的Point开始的路径中的所有路径/节点,其中路径中的所有节点都需要满足相同的过滤条件(如num = 1
)。
在上图中,结果将是(point_id
作为节点代表):
以下查询返回预期结果:
MATCH p=((a:Point {point_id: 1})-[:NEXT*]->(b:Point))
WHERE ALL (x IN NODES(p) WHERE x.num = 1)
RETURN p
现在让我们考虑一下我的真实环境:我有一个图表,代表一个拥有大约200万个节点和280万个关系的道路网络(如果以双向方式表示,则为两倍)。每个节点有3个属性,具有以下加权分布:0(30%),1(30%),2(20%),3(14%),4(5%)和5(1%)。任何属性都可以用作具有任何可能值的过滤器。
节点结构是:
(:Intersection {
intersection_id: int,
num_hotels: int,
num_restaurants: int,
num_gas_stations: int
})
关系标记为[:CONNECTED_TO]
。节点表示交叉点/端点,关系表示道路。属性intersection_id
已编入索引。
我试图解决上面列举的问题一段时间但没有成功。在没有指定遍历的最大深度的情况下,Neo4j的内存使用量会爆炸,并且查询无限期地运行,直到我取消操作或结束进程(有时我需要这样做,因为系统由于缺少可用内存而几乎冻结)。我理解这种行为,因为查询复杂性随着访问的每个新深度级别呈指数级增长。
然而,即使我设置了最大深度级别(例如15级),操作仍然非常昂贵。我的图形具有节点,其从它们开始的高达10到15个级别的查询可以涉及大量节点,例如数据库的1/4,或者相对低的量,例如几千个节点(<2k)。上述行为都发生在两种情况下。
我使用20或30%分布的值作为过滤器,因为由于图形的大小,很难将值映射到分布的5%或1%。我尝试使用带有和不带索引的属性num_hotels
进行过滤。
以下是我尝试过的一些问题:
MATCH p=((a:Intersection {Intersection: 562818})-[:CONNECTED_TO*]->(b:Intersection))
WHERE ALL (x IN NODE(p) WHERE x.num_hotels = 0)
RETURN p
MATCH path=(a:Intersection {intersection_id: 562818})-[:CONNECTED_TO*]->(b:Intersection {num_hotels: 0})
WHERE ALL(x IN NODES(path) WHERE SINGLE(y IN NODES(path) WHERE y = x))
RETURN p;
对于某些情况,如果遍历中涉及的节点数量较少(300-600),我获得了合理的结果,但查询并不总是正常执行。有时交易似乎经常冻结,所以我不得不结束并再次启动它们以获得结果,而且这并不总能得到保证。
我想提出解决问题的技巧,以及有关Neo4j在此类操作中的行为的一些解释。到目前为止我的印象是Neo4j正在寻找所有路径,然后应用过滤器,无论我如何组织查询。
Neo4j版本:3.3.1
操作系统:Linux Mint Cinnamon 18.2
内存:6GB,大约4.5GB可用于测试。