在Neo4j

时间:2017-05-24 04:57:10

标签: neo4j path complete journey

作为neo4j中的一个绝对的菜鸟并且对前一个问题有过非常慷慨的帮助,我以为我会再次尝试运气,因为我还在苦苦挣扎。

示例场景是进入房屋并从一个房间走到另一个房间的学生。旅程不必在特定房间开始或结束,但学生进入房间的顺序很重要。

我想知道的是学生们所采取的所有完整路径,以及相关路径的计算次数。以下是示例数据和我尝试过的内容(感谢上一个问题的回答以及一系列博客文章):

文件dorm.csv

ID|SID|EID|ROOM|ENTERS|LEAVES
1|1|12|BLUE|1/01/2015 11:00|4/01/2015 10:19
2|2|18|GREEN|1/01/2015 12:11|1/01/2015 12:11
3|2|18|YELLOW|1/01/2015 12:11|1/01/2015 12:20
4|2|18|BLUE|1/01/2015 12:20|5/01/2015 10:48
5|3|28|GREEN|1/01/2015 18:41|1/01/2015 18:41
6|3|28|YELLOW|1/01/2015 18:41|1/01/2015 21:00
7|3|28|BLUE|1/01/2015 21:00|9/01/2015 9:30
8|4|36|BLUE|1/01/2015 19:30|3/01/2015 11:00
9|5|40|GREEN|2/01/2015 19:08|2/01/2015 19:08
10|5|40|ORANGE|2/01/2015 19:08|3/01/2015 2:43
11|5|40|PURPLE|3/01/2015 2:43|4/01/2015 16:44
12|6|48|GREEN|3/01/2015 11:52|3/01/2015 11:52
13|6|48|YELLOW|3/01/2015 11:52|3/01/2015 17:45
14|6|48|RED|3/01/2015 17:45|7/01/2015 10:00

为学生,房间和访问创建节点,其中访问是学生进入由ID属性唯一标识的房间的事件

CREATE CONSTRAINT ON (student:Student) ASSERT student.studentID IS UNIQUE;
CREATE CONSTRAINT ON (room:Room) ASSERT room.roomID IS UNIQUE;
CREATE CONSTRAINT ON (visit:Visit) ASSERT visit.visitID IS UNIQUE;


USING PERIODIC COMMIT
LOAD CSV WITH HEADERS FROM "file:///dorm.csv" as line fieldterminator '|'
MERGE (student:Student {studentID: line.SID})
MERGE (room:Room {roomID: line.ROOM})
MERGE (visit:Visit {visitID: line.ID, roomID: line.ROOM, studentID: line.SID, ticketID: line.EID})
create (student)-[:VERB]->(visit)-[:OBJECT]->(room)

创建PREV关系允许学生进入的排序或排序。这使用文件dormprev.csv中的数据。如果学生只访问过一个房间,则此ID不会出现在dormprev文件中,因为其目的是链接/链接访问。数据如下

ID|PREV_ID|EID
3|2|18
4|3|18
6|5|28
7|6|28
10|9|40
11|10|40
13|12|48
14|13|48

USING PERIODIC COMMIT
LOAD CSV WITH HEADERS FROM "file:///dormprev.csv" as line fieldterminator '|'
MATCH (new:Visit {visitID: line.ID})
MATCH (old:Visit {visitID: line.PREV_ID})
MERGE (new)-[:PREV]->(old)

我可以通过以下查询查看所有学生的旅程

MATCH (student:Student)-[:VERB]->(visit:Visit)-[:OBJECT]-(room:Room)
RETURN student, visit, room

但是,我不知道如何以完整的路径返回所有房间。

如果我运行此查询

MATCH p = (:Visit)<-[:PREV]-(:Visit) return p

我可以看到它,例如,学生ID 2返回绿色和黄色,然后黄色和蓝色作为单独的一对 - 我想将其视为绿色,黄色,蓝色

这也意味着如果我运行以下查询:

MATCH p = (:Visit)<-[:PREV]-(:Visit)
WITH p, EXTRACT(v IN NODES(p) | v.roomID) AS rooms
UNWIND rooms AS stays
WITH p, COUNT(DISTINCT stays) AS distinct_stays
WHERE distinct_stays = LENGTH(NODES(p))
RETURN EXTRACT(v in NODES(p) | v.roomID), count(p)
ORDER BY count(p) DESC

如果有意义,它将返回这些配对的计数而不是“整个路径”的计数。

例如,SID 2和SID 3按顺序访问房间GREEN,YELLOW,BLUE。 SID 5按顺序访问GREEN,ORANGE,PURPLE。

我希望看到的是:

[GREEN, YELLOW, BLUE] 2
[GREEN, ORANGE, PURPLE] 1

等。这可能与上述型号有关,如果是这样,任何人都可以请帮助我指出正确的方向吗?访问的房间数量不保证,可以是一个到*。然而,如果只访问了一个房间,那不是真正有趣的,所以我认为这个模型可能有意义的原因(再次,从博客文章系列中偷来的)。

我不知道上述内容是否有意义,但是我们非常感谢任何帮助 - 这样做是一个很好的用例,并且非常有用。

感谢您的帮助。

2 个答案:

答案 0 :(得分:0)

我认为您正在寻找的是可变路径长度。您只需在查询中更改此内容即可完成此操作(请注意星号):

MATCH p = (:Visit)<-[:PREV*]-(:Visit)

请允许我再说几句。是的,我理解在Visit节点中拥有roomID和studentID的便利性(让这个特定的查询保持相当简单),但是你忽略了首先建立关系的重点(事实上,如果你这样做的话)实际上,学生和会议室节点实际上没有任何意义,并且您将无法维护它们。其次......如果我们要分裂众所周知的第3范式毛发;-),那么访问的关系实际上应该如下创建(注意关系的方向):

CREATE (student)-[:VERB]->(visit)<-[:OBJECT]-(room)

除此之外,我必须说你的行动非常快: - )

希望这有帮助,汤姆

答案 1 :(得分:0)

根据Tom的建议,您可能会考虑使用替代模型:完全访问节点,并使您的关系类型更加集中,如下所示:

QMessageBox.question(parent, title, text, button0, button1)

您可以在:VISITED关系中设置输入和左侧属性,这样您就可以按照访问顺序订购关系(和相应的:房间)。

以下是使用APOC Procedures执行此操作的替代导入(您必须安装与Neo4j版本对应的正确版本)以从日期字符串中解析出时间戳。< / p>

(:Student)-[:VISITED]->(:Room)

现在,您获取所有路径以及采用这些路径的学生数量的查询变得非常简单:

USING PERIODIC COMMIT
LOAD CSV WITH HEADERS FROM "file:///dorm.csv" as line fieldterminator '|'
MERGE (student:Student {studentID: line.SID})
MERGE (room:Room {roomID: line.ROOM})
WITH student, room, apoc.date.parse(line.ENTERS, 'ms', 'MM/dd/yyyy HH:mm') as entered, apoc.date.parse(line.LEAVES, 'ms', 'MM/dd/yyyy HH:mm') as left
CREATE (student)-[r:VISITED]->(room)
SET r.entered = entered, r.left = left