Cypher是否可以根据给定类型的第一个遇到节点的属性过滤结果?

时间:2016-07-02 06:28:51

标签: neo4j cypher graph-databases nosql

我正在使用Neo4J并学习Cypher,并且有一个关于根据给定类型的第一个遇到节点的属性过滤结果的问题(在下面的示例代码的OPTIONAL MATCH行中)。

我的查询如下:

MATCH 
  (a:Word), 
  (b:Word)
WHERE a.lemma IN [ "enjoy" ]
  AND b.lemma IN [ "control", "achievement" ]
OPTIONAL MATCH p = shortestPath((a)-[:IS_DEFINED_AS|IS_A_FORM_OF*..15]-(b)) 
RETURN 
  a.lemma as From, b.lemma as To,
  length(
    filter(n in nodes(p) WHERE 'Word' in labels(n))
  ) - 1 as Shortest_Number_of_Hops_Only_Counting_Words, 
  length(p) as Shortest_Number_of_Hops_Counting_All_Nodes

数据库中可能出现两种常见类型的路径:

(a:Word) <-[IS_A_FORM_OF]- (Morph) -[IS_A_FORM_OF]-> (Word) -[IS_DEFINED_AS]-> (Synset) <-[IS_DEFINED_AS]- (Word) -[IS_DEFINED_AS]-> (Synset) <-[IS_DEFINED_AS]- (b:Word)

(a:Word) -[IS_DEFINED_AS]-> (Synset) <-[IS_DEFINED_AS]- (Word) -[IS_DEFINED_AS]-> (Synset) <-[IS_DEFINED_AS]- (b:Word)

ab之间可能有任意数量的跃点(目前在查询中上限为15)。

我试图在上面给出一个非常具体的示例,但我的问题确实是一个关于使用Cypher的非常普遍的问题:我想过滤遇到的第一个Synset节点包含某些路径的路径属性(例如,{part_of_speech: 'verb'}我一直在阅读Cypher refcard,我想知道是否应使用head()表达式以某种方式选择第一个Synset节点路径,但我不确定该怎么做。有没有一种直接的方法将它添加到MATCH / WHERE语句中?

2 个答案:

答案 0 :(得分:0)

您可以按照此属性

匹配Synset节点
MATCH (verb:Synset {part_of_speech: 'verb'})
RETURN verb

然后变量verb将仅匹配part_of_speech属性为"verb"的Synset节点。

您可以在请求中进一步使用此变量。例如,您可以编写基本相同的请求,限制WHERE部分中节点属性的值:

MATCH (verb:Synset)
WHERE verb.part_of_speech = 'verb'
RETURN verb

根据您的要求申请,您可以像这样重写:

MATCH 
  (a:Word) -[:IS_DEFINED_AS]-> (verb:Synset {part_of_speech: "verb"}), 
  (b:Word)
WHERE a.lemma IN [ "enjoy" ]
  AND b.lemma IN [ "control", "achievement" ]
OPTIONAL MATCH p = shortestPath((a)-[:IS_DEFINED_AS]-(verb)-[:IS_DEFINED_AS|IS_A_FORM_OF*..15]-(b)) 
RETURN 
  a.lemma as From, b.lemma as To,
  length(
    filter(n in nodes(p) WHERE 'Word' in labels(n))
  ) - 1 as Shortest_Number_of_Hops_Only_Counting_Words, 
  length(p) as Shortest_Number_of_Hops_Counting_All_Nodes

答案 1 :(得分:0)

@ oleg-kurbatov的回答 工作,但只有当(a:Word)立即连接到Synset时(它不考虑(a:Word)必须经过的情况Morph等类型的节点,在进入Synset之前(如我在原始问题中的第一个示例路径)。此外,添加路径一起的方法似乎更加计算密集 - 我的原始查询的802ms与使用稍微的2364ms Oleg建议的实现的修改版本(因为Cypher / Neo4J在使用shortestPath()时不允许指定多个特定的跃点:

MATCH 
  (a:Word),
  (b:Word)
WHERE a.lemma IN [ "enjoy" ]
  AND b.lemma IN [ "control", "achievement" ]
MATCH p1 = (a)-[:IS_DEFINED_AS]-> (initial_synset:Synset{pos: 'v'})
OPTIONAL MATCH p2 = shortestPath((initial_synset)-[:IS_DEFINED_AS|IS_A_FORM_OF*..15]-(b))
RETURN 
  a.lemma as From, b.lemma as To,
  length(
    filter(n in nodes(p2) WHERE 'Word' in labels(n))
  ) as Shortest_Number_of_Hops_Only_Counting_Words,
  length(p1) + length(p2) as Shortest_Number_of_Hops_Counting_All_Nodes

以Oleg的建议作为起点,我确实找到了一种方法来过滤shortestPath(),以便它只能在第一个遇到Synset节点的'pos'属性'v'的路径上找到,不增加查询执行时间:我将原始问题中的OPTIONAL MATCH行修改为:

OPTIONAL MATCH p = shortestPath((a)-[:IS_DEFINED_AS|IS_A_FORM_OF*..15]-(b))
WHERE head(filter(x in nodes(p) WHERE x:Synset)).pos = 'v'

据我所知,filter(x in nodes(p) WHERE x:Synset)获取了所考虑路径中所有Synset类型节点的列表。 head(...)从该列表中获取第一个节点,.pos = 'v'检查该节点的“pos”属性是否为“v”。