这是一个初学者的问题,基于neo4j在线培训。 (第二章:使用模式过滤)。
问题是关于与Gene Hackman合作的演员的查询,但不是在他与Robin Williams合作的时候。
他们的解决方案是:
MATCH (gene:Person {name:"Gene Hackman"})-[:ACTED_IN]->(movie),
(other)-[:ACTED_IN]->(movie),
(robin:Person {name:"Robin Williams"})
WHERE NOT (robin)-[:ACTED_IN]->(movie)
RETURN DISTINCT other;
通过试图找出为什么真正需要带有新标识符的第3行,我尝试了以下片段,但没有成功。
MATCH (gene:Person)-[:ACTED_IN]->()<-[:ACTED_IN]-(other)
WHERE gene.name="Gene Hackman"
AND other.name <> "Robin Williams"
RETURN DISTINCT other;
和
MATCH (gene:Person)-[:ACTED_IN]->()<-[:ACTED_IN]-(other)
WHERE gene.name="Gene Hackman"
AND NOT "Robin Williams" IN other.name
RETURN DISTINCT other;
显然我错过了一些东西。 我很感激任何指针!
答案 0 :(得分:3)
您的第一次尝试:
MATCH (gene:Person)-[:ACTED_IN]->()<-[:ACTED_IN]-(other)
WHERE gene.name="Gene Hackman"
AND other.name <> "Robin Williams"
RETURN DISTINCT other;
这将匹配Gene Hackman与Robin Williams合作过的所有演员,但这并不符合,但是当他还在你的简报的工作组件时。为了做到这一点,你将不得不绑定关系链的movie
部分。要使用IN
,您还必须使用WITH
,因为Chrisophe举了一个例子:
MATCH (gene:Person{name:"Gene Hackman"})-[:ACTED_IN]->(movie:Movie)<-[:ACTED_IN]-(other)
WITH movie, COLLECT(other.name) AS costars
WHERE NOT "Robin Williams" in costars
RETURN movie, costars
不幸的是,现在你有一个由电影作为结果的演员姓名(字符串)的聚合集合,而不是一组不同的演员(节点)。为避免字符串/节点问题,您可以使用WITH
来转发other
而不是other.name
。然后,您将使用WHERE NOT
谓词而不是FILTER
。您仍然需要做一些工作才能回到不同的节点集。
MATCH (gene:Person{name:"Gene Hackman"})-[:ACTED_IN]->(movie:Movie)<-[:ACTED_IN]-(other)
WITH movie, COLLECT(other) AS costars
WHERE NONE(costar IN costars WHERE costar.name = "Robin Williams")
RETURN movie, costars
我想问的是,为什么你不想绑定'robin'节点?索引命中并绑定变量很便宜并且允许Neo4J工作它想要如何工作,使用未绑定的字符串将导致与每个节点进行多次交互的成本(“你是罗宾威廉姆斯吗?”)。
答案 1 :(得分:1)
您给出的第二次尝试几乎是正确的,您误用了IN运算符。
IN用于验证集合中是否存在元素,或者other.name是字符串。
以下是IN的一个例子:
MATCH (n:Person) AS persons
WITH collect(persons.name) as names
WHERE NOT 'Gene Hackman' IN names
RETURN names
你可以试试这个:
MATCH (gene:Person)-[:ACTED_IN]->()<-[:ACTED_IN]-(other)
WHERE gene.name="Gene Hackman"
AND NOT "Robin Williams" = other.name
RETURN DISTINCT other;
但是,您现在有一个很长的模式,将在数据库中查找。拥有多个准确的细分更具性能。在您的用例中,将会有一个全局图表查找,如果可能,应该避免使用。