带聚合函数的Neo4j cypher查询返回不完整的结果

时间:2017-04-02 09:23:48

标签: neo4j cypher graph-databases

大家好!我有一个Neo4j数据库,其中包含有关在特定时刻访问多个检查点的访问者的信息。访问者,访问和检查点表示为节点。

每个访问者都由他/她的设备MAC地址标识,每个检查点都有唯一的ID。

每个访问节点都包含一个EnterTime属性,该属性是在相应检查点附近首次发现具有某些特定MAC地址的访问者时的时间(自1970年以来的毫秒数)。

注意:访问的持续时间应计算为下次访问的EnterTime与此次访问的EnterTime之间的差异。每个检查点可能会被访问​​多次。

使用此密码查询创建数据库:

//Create visitors:
CREATE (Visitor1: Visitor {MAC:'00:0a:95:9d:68:16'})
CREATE (Visitor2: Visitor {MAC:'00:0a:95:9d:68:17'})
CREATE (Visitor3: Visitor {MAC:'00:0a:95:9d:68:18'})

//Create CheckPoints:
CREATE (CheckPoint1: CheckPoint {CheckPointId: 1})
CREATE (CheckPoint2: CheckPoint {CheckPointId: 2})
CREATE (CheckPoint3: CheckPoint {CheckPointId: 3})
CREATE (CheckPoint4: CheckPoint {CheckPointId: 4})
CREATE (CheckPoint5: CheckPoint {CheckPointId: 5})


//Create visits:
//by visitor 1:
CREATE  (Visitor1)-[:MAKES]->(Visit1: Visit {EnterTime: 1488358800000})-[:TO]->(CheckPoint1)
CREATE  (Visitor1)-[:MAKES]->(Visit2: Visit {EnterTime: 1488359400000})-[:TO]->(CheckPoint2)
CREATE  (Visitor1)-[:MAKES]->(Visit3: Visit {EnterTime: 1488361200000})-[:TO]->(CheckPoint3)
CREATE  (Visitor1)-[:MAKES]->(Visit4: Visit {EnterTime: 1488363600000})-[:TO]->(CheckPoint4)
CREATE  (Visitor1)-[:MAKES]->(Visit5: Visit {EnterTime: 1488364800000})-[:TO]->(CheckPoint5)
CREATE  (Visitor1)-[:MAKES]->(Visit6: Visit {EnterTime: 1488365400000})-[:TO]->(CheckPoint1)

//by visitor 2:
CREATE  (Visitor2)-[:MAKES]->(Visit7: Visit {EnterTime: 1488358800000})-[:TO]->(CheckPoint1)
CREATE  (Visitor2)-[:MAKES]->(Visit8: Visit {EnterTime: 1488360300000})-[:TO]->(CheckPoint4)
CREATE  (Visitor2)-[:MAKES]->(Visit9: Visit {EnterTime: 1488362400000})-[:TO]->(CheckPoint2)
CREATE  (Visitor2)-[:MAKES]->(Visit10: Visit {EnterTime: 1488363000000})-[:TO]->(CheckPoint1)

//by visitor 3:
CREATE  (Visitor3)-[:MAKES]->(Visit11: Visit {EnterTime: 1488353820000})-[:TO]->(CheckPoint1)
CREATE  (Visitor3)-[:MAKES]->(Visit12: Visit {EnterTime: 1488354600000})-[:TO]->(CheckPoint4)
CREATE  (Visitor3)-[:MAKES]->(Visit13: Visit {EnterTime: 1488358200000})-[:TO]->(CheckPoint3)
CREATE  (Visitor3)-[:MAKES]->(Visit14: Visit {EnterTime: 1488359700000})-[:TO]->(CheckPoint1)  

我正在编写一个密码查询来查找每个检查点的总访问时间。 我正在尝试这个:

match (vr: Visitor)-->(v1: Visit)-->(cp1: CheckPoint),
 (vr)-->(v2: Visit)-->()
where v2.EnterTime > v1.EnterTime
with cp1.CheckPointId as CheckPointId,
     v1.EnterTime as EnterTime,
     min((v2.EnterTime - v1.EnterTime) / 60000) as visit_duration
return CheckPointId, sum(visit_duration) as total_visit_duration
order by CheckPointId;

结果应为:

cp1  - 48 min
cp2 – 40 min
cp3 – 65 min
cp4 – 115 min
cp5 – 10 min

但是我的查询返回了错误的结果:

cp1  - 23 min
cp2 – 40 min
cp3 – 65 min
cp4 – 115 min
cp5 – 10 min

显然,错误是访问者(mac == 00:0a:95:9d:68:17)访问id == 1的检查点的长度没有被考虑在内。但这是我的猜测。

我的查询有什么问题?如何改进以返回正确的结果?

非常感谢您的帮助!谢谢!

1 个答案:

答案 0 :(得分:2)

我认为你在寻找的是:

match ()<--(v2:Visit)<--(vr: Visitor)-->(v1: Visit)-->(cp1: CheckPoint)
where v2.EnterTime > v1.EnterTime
with vr,
 cp1.CheckPointId as CheckPointId,
 v1.EnterTime as EnterTime,
 min((v2.EnterTime - v1.EnterTime) / 60000) as visit_duration
return CheckPointId, sum(visit_duration) as total_visit_duration
order by CheckPointId;

我在vr声明中添加了with。 Cypher根据您在with语句中输入的所有值进行分组。您的代码无法工作的原因是因为访问者1和2的检查点1的v1.EnterTime是相同的。因为EnterTime语句中只有CheckpointIDwith,所以cypher按EnterTime分组,所以因为你有min(v2.EnterTime - v1.EnterTime)它只是拿了较小的一个并且做了Visitor不要同时使用。现在我们在with语句中引入soundPlayer = new Audio(soundName).play(); ,如果两个人同时启动相同的检查点,它也将按访问者分组,这解决了我们的问题。

希望这有帮助