试图找出以下情况。
设定:
目标
尝试以下查询:
// Get all events between 2 times
MATCH (m1:Minute { minute: 15 })<--(h:Hour { hour: 8 })<--(d:Day { day: 24 })<--(month:Month { month: 10 })
MATCH (m2:Minute { minute: 45 })<--(h2:Hour { hour: 10 })<--(d2:Day { day: 24 })<--(month2:Month { month: 10 })
MATCH p=((m1)-[:NEXT*]->(m2))
WITH NODES(p) as pnodes UNWIND pnodes AS pwind
MATCH (e:Event)-[:STARTS_AT]->(pwind)
RETURN pwind,e
确实正在检索结果,但注意到:
使用where的另一个变体(仅在将来的日期尝试过):
// Get all events between 2 times
MATCH (e:Event)
WHERE (:Month { month: 10 })-->(:Day { day: 24 })-->(:Hour { hour: 9 })-->(:Minute { minute: 00})-[:NEXT*]->(:Minute)<--(e)
RETURN e
结果:表现甚至是WORSE。 100秒检索1项。
我理解并希望这样做的方法是使用某种允许路径返回相关节点的函数。这是:path函数只返回被查询的特定节点(在本例中为Minutes),但我想为所有这些节点带来“:STARTS_AT”相关的事件。
最后,问题:
提前致谢。
答案 0 :(得分:3)
因此shortestPath
有一个奇怪的地方,如果你没有指定最大长度,它会随意将最大值设置为 15 。见这里:
ShortestPath doesn't find any path without max hops limit
我实际上将此称为错误,因为它不在文档中,并且会导致意外行为,正如您所发现的那样。
因此,问题的解决方案是使用shortestPath
,但选择最大长度。我会选择一些非常高的东西;让我们做十亿,并称之为一天:
MATCH (:Year {year:2015})-[:HAS_MONTH]->(:Month {month:10})-[:HAS_DAY]->(:Day {day:23})-[:HAS_HOUR]->(:Hour {hour:8})-[:HAS_MINUTE]->(startMinute:Minute {minute:15})
MATCH (:Year {year:2015})-[:HAS_MONTH]->(:Month {month:10})-[:HAS_DAY]->(:Day {day:24})-[:HAS_HOUR]->(:Hour {hour:10})-[:HAS_MINUTE]->(endMinute:Minute {minute:45})
MATCH p = shortestPath((startMinute)-[:NEXT*..1000000000]->(endMinute))
UNWIND NODES(p) AS minute
MATCH (event:Event)-[:STARTS_AT]->(minute)
RETURN event, minute;
您应始终使用shortestPath
来查找分钟节点的范围;在(startMinute)-[:NEXT*]->(endMinute)
上进行匹配而不将其包裹在shortestPath
中是试图找到两个节点之间任何长度的所有路径,因此它是详尽无遗的并且需要更长的时间,而shortestPath
可以在它尽快停止找到了路径。
至于查找是否有任何其他事件与某个事件重叠:
MATCH (startMinute:Minute)<-[:STARTS_AT]-(event:Event)-[:ENDS_AT]->(endMinute:Minute)
WHERE event.id = {event_id}
MATCH p = shortestPath((startMinute)-[:NEXT*..1000000000]->(endMinute))
UNWIND NODES(p) AS span
MATCH (overlap:Event)-[:STARTS_AT|ENDS_AT]->(span)
WHERE overlap <> event
RETURN overlap;
下面是如何为概念验证目的创建数据的附录。假设所有月份都有31天。
约束和索引。
CREATE CONSTRAINT ON (year:Year) ASSERT year.year IS UNIQUE;
CREATE INDEX ON :Month(month);
CREATE INDEX ON :Day(day);
CREATE INDEX ON :Hour(hour);
CREATE INDEX ON :Minute(minute);
创建时间树。
WITH RANGE(2014, 2015) AS years, RANGE(1, 12) AS months, RANGE(1, 31) AS days, RANGE(0,23) AS hours, RANGE(0, 45, 15) AS minutes
FOREACH(year IN years |
MERGE (y:Year {year: year})
FOREACH(month IN months |
CREATE (m:Month {month: month})
MERGE (y)-[:HAS_MONTH]->(m)
FOREACH(day IN days |
CREATE (d:Day {day: day})
MERGE (m)-[:HAS_DAY]->(d)
FOREACH(hour IN hours |
CREATE (h:Hour {hour: hour})
MERGE (d)-[:HAS_HOUR]->(h)
FOREACH(minute IN minutes |
CREATE (min:Minute {minute: minute})
MERGE (h)-[:HAS_MINUTE]->(min)
)
)
)
)
);
在所有Minute节点之间创建[:NEXT]关系。
MATCH (year:Year)-[:HAS_MONTH]->(month:Month)-[:HAS_DAY]->(day:Day)-[:HAS_HOUR]->(hour:Hour)-[:HAS_MINUTE]->(minute:Minute)
WITH year, month, day, hour, minute
ORDER BY year.year, month.month, day.day, hour.hour, minute.minute
WITH COLLECT(minute) AS minutes
FOREACH(i IN RANGE(0, LENGTH(minutes) - 2) |
FOREACH(min1 IN [minutes[i]] |
FOREACH(min2 IN [minutes[i + 1]] |
CREATE UNIQUE (min1)-[:NEXT]->(min2)
)
)
);
随机模拟事件及其开始时间。
MATCH (minute:Minute)
WHERE RAND() < 0.3
CREATE (event:Event)-[:STARTS_AT]->(minute);
让所有活动长5分钟。
MATCH (event:Event)-[:STARTS_AT]->(startMinute:Minute)-[:NEXT*5]->(endMinute:Minute)
CREATE (event)-[:ENDS_AT]->(endMinute);