0

作为 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

等。上述模型是否可行,如果可以,任何人都可以帮我指出正确的方向吗?访问的房间数量无法保证,可以是从 1 到 * 的任意值。但是,如果只访问一个房间,那并不是很有趣,这也是我认为这个模型可能有意义的原因(再次,从博客文章系列中窃取)。

我不知道以上是否有意义,但任何帮助将不胜感激 - 这将是一个极好的用例,并且非常有用。

感谢您的热心帮助。

4

2 回答 2

0

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

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

请允许我再多说几句。是的,我理解在访问节点中拥有 roomID 和 studentID 的便利性(使这个特定的查询变得相当简单),但是你首先忽略了建立关系的全部意义(事实上,如果你这样做的话目前实际上根本没有学生和房间节点)并且您将无法维护它们。其次......如果我们要分裂众所周知的第三范式头发;-),那么实际上应该按如下方式创建访问关系(注意关系的方向):

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

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

希望这会有所帮助,汤姆

于 2017-05-24T05:54:20.137 回答
0

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

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

您可以在 :VISITED 关系上设置输入和左属性,这将允许您按访问顺序对关系(和相应的 :Rooms)进行排序。

这是一个替代导入,它使用APOC 程序(您必须安装与您的 Neo4j 版本相对应的正确版本)从日期字符串中解析出时间戳。

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

现在,您获取所有路径和选择这些路径的学生人数的查询变得非常容易:

MATCH (s:Student)-[v:VISITED]->(r:Room)
WHERE size((s)-[:VISITED]->()) > 1
WITH s, r
ORDER BY v.entered ASC
WITH s, collect(r.roomID) as rooms
RETURN rooms, count(s)
于 2017-05-24T08:28:40.717 回答