Neo4j中的意外行为链接Any()和None()

时间:2019-03-02 02:02:24

标签: neo4j cypher

我想要得到的是具有任何属性名称(键)的某些属性值,而没有任何属性其他值的节点。

简而言之,伪Google查询如下:

+Tom +val1 +val2 (...) -Cruise -valX -valY (...)

和Cypher查询类似:

MATCH (n) WHERE (
  ANY ( p in KEYS(n) WHERE n[p] CONTAINS 'Tom' ) AND
  NONE ( p in KEYS(n) WHERE n[p] CONTAINS 'Cruise')
)
RETURN n

但是电影数据库(:play电影图)的测试结果只是一个空列表,而数据库中还有其他名为“ Tom”的演员,例如汤姆·汉克斯。 (匹配(n),其中(any(KEYS(n)中的p,其中n [p]包含'Tom'))返回n 给[汤姆·泰克维尔,汤姆·汉克斯,汤姆·克鲁斯,汤姆·斯凯里特])

所以我尝试使用'om'而不是'Tom',这一次,结果是'om'的不完整列表:

match (n) where (
 any( p in KEYS(n) WHERE n[p] contains 'om') and 
 none( p in Keys(n) WHERE n[p] contains 'Cruise')
 )
 return n

给予

[Romantic (genre), Naomie Harris, James Thompson, Jessica Thompson]
(No Tom's -- why?)

也尝试用NOT ANY()代替NONE()并得到相同的结果。

这种不一致是从哪里来的?

2 个答案:

答案 0 :(得分:3)

问题在于节点的属性类型不是string。对于他们来说,NONE验证给出了null,这完全给了where一个错误。例如,此查询不返回任何内容:

WITH {k1: 1, k2: '2'} AS test 
WHERE NONE(key IN keys(test) WHERE test[key] CONTAINS '1')
RETURN test

因此,在这种情况下,您需要检查属性的类型。由于没有本机类型检查功能,因此可以使用APOC library中的功能:

MATCH (n) WHERE (
  ANY(p in KEYS(n) WHERE apoc.meta.cypher.type(n[p]) = 'STRING' AND n[p] CONTAINS 'Tom') AND
  NONE(p in KEYS(n) WHERE apoc.meta.cypher.type(n[p]) = 'STRING' AND n[p] CONTAINS 'Cruise')
)
RETURN n

答案 1 :(得分:3)

@ stdob--提供了对该问题的准确解释。

但是有更简单的解决方法。例如,您可以使用COALESCE function()强制将NULL的值视为FALSE

MATCH (n)
WHERE
  ANY ( p in KEYS(n) WHERE n[p] CONTAINS 'Tom' ) AND
  NONE( p in KEYS(n) WHERE COALESCE(n[p] CONTAINS 'Cruise', FALSE))
RETURN n