如何基于边缘属性过滤节点

时间:2018-01-26 18:04:56

标签: neo4j cypher

Sample graph

我们有一个Neo4j图表,可以跟踪人们走过门的情况。它包含Person节点,Door节点和WALKED_THROUGH边。 person和door节点具有“name”属性,并且边缘具有“action”属性,该属性设置为“Entered”或“Exited”。

我需要回答的问题是:给定一个人,她至少进入一次,但从未退出的门的名称是什么?

我可以轻松获得相关路径:

match( (person:Person{name:'Mary'})-[walkedThroughEdges:WALKED_THROUGH]->(doors:Door) )
return person, walkedThroughEdges, doors
order by doors.Name

...产生这个:

╒═══════════════╤════════════════════╤═════════════════╕
│"person"       │"walkedThroughEdges"│"doors"          │
╞═══════════════╪════════════════════╪═════════════════╡
│{"name":"Mary"}│{"action":"Exited"} │{"name":"Door B"}│
├───────────────┼────────────────────┼─────────────────┤
│{"name":"Mary"}│{"action":"Entered"}│{"name":"Door B"}│
├───────────────┼────────────────────┼─────────────────┤
│{"name":"Mary"}│{"action":"Entered"}│{"name":"Door A"}│
├───────────────┼────────────────────┼─────────────────┤
│{"name":"Mary"}│{"action":"Entered"}│{"name":"Door A"}│
└───────────────┴────────────────────┴─────────────────┘

...但我无法弄清楚如何操纵结果以获得我需要的答案。在这种情况下,预期的答案是“门A”,因为玛丽进入门A至少一次,但从未退出。门B应该被排除在外,因为玛丽从那扇门出来了。

任何帮助都将不胜感激。

3 个答案:

答案 0 :(得分:1)

编辑:如果您只需要用户刚进入的门,这应该可以。

match(person:Person{name:'Mary'})-[walkedThroughEdges:WALKED_THROUGH]->(door:Door) 
with person, door, collect(walkedThroughEdges.action) as actions
with person, door, size(filter(action in actions where action = "Entered")) as enteredCount, size(actions) as total
where enteredCount = total
return person, door
order by door.Name

答案 1 :(得分:1)

此查询应该找到一个人曾经用过的门,但从来没有退出。 它类似于@InverseFalcon的方法,但使用不同的语法。

MATCH (person:Person{name:'John'})-[r:WALKED_THROUGH]->(door:Door)
WITH person, door, r.action AS action, COUNT(*) AS ct
WITH person, door, COLLECT({action: action, ct: ct}) AS x
WHERE SIZE(x) = 1 AND x[0].action = 'Entered'
RETURN person, door, x[0].ct AS num_enters
ORDER BY door.Name;

第一个WITH子句使用aggregation来计算每个人每个门action执行次数的次数。

第二个WITH子句使用聚合来收集动作/计数对。 可以有1对或2对,因为有2种可能的操作。

WHERE子句检查集合是否只有一个操作/计数对,并且操作是“已输入”。如果确实如此,则输入相关门但从未退出。

答案 2 :(得分:0)

我觉得这样的事情可以奏效......

您只能匹配“已输入”操作的WALKED_THROUGH边缘。然后选择性地匹配那些存在Exited边缘的人,门对。然后返回Exited匹配项不存在的人员,门组合。

MATCH (person:Person {name:'Mary'})-[:WALKED_THROUGH {action: 'Entered'}]->(door:Door)
WITH person, door
OPTIONAL MATCH (person)-[exited:WALKED_THROUGH {action: 'Exited'}]->(door)
WITH person, door, exited
WHERE exited IS NULL
RETURN person, door

另一种方法是将它们全部匹配。然后只返回已进入且没有退出的那些。这可能更有意义,因为我认为一个人在考虑退出之前必须进入。

MATCH (person:Person {name:'Mary'})-[walked_through:WALKED_THROUGH]->(door:Door)
WITH person, door, collect(walked_through.action) AS walked_through
WHERE ALL(action IN walked_through WHERE action = 'Entered' )
RETURN person, door

然而,还有一种方法不是使用NOT EXISTS。最明显的三种可能性。

MATCH (person:Person {name:'Mary'})-[walked_through:WALKED_THROUGH]->(door:Door)
WHERE NOT EXISTS((person)-[:WALKED_THROUGH {action: 'Exited'}]->(door))
RETURN person, door