带属性的可选MATCH(和标签?)

时间:2013-07-28 20:05:13

标签: neo4j

我正在尝试在Neo4j http://blog.neo4j.org/2012/02/modeling-multilevel-index-in-neoj4.html

中构建此模型

现在我需要一个查询来查明时间轴路径是否已经存在。问题是我似乎无法使节点成为可选节点,同时检查属性是否存在。

理想情况下我想要这个查询:

START a=node(2)
MATCH a:timeline -[?]-> b:time_year -[?]-> c:time_month -[?]-> d:time_day
WHERE b.year = 2013 AND c.month = 7 AND d.day = 28
RETURN b, c, d

但由于似乎不支持可选节点上的标签,我将使用此查询:

START a=node(2)
MATCH a:timeline -[?]-> b -[?]-> c -[?]-> d
WHERE b.year = 2013 AND c.month = 7 AND d.day = 28
RETURN b, c, d

如果没有WHERE子句,则会返回:

a    b    c
null null null

结果很好,因为我知道我必须制作年,月和日节点。但是如果没有WHERE子句,我就无法指定我希望渲染整个查询的日期无用。

我正在使用Neo4j 2.0.0-M03

更新: 澄清标签不起作用的原因。这是在一个新的数据库上运行。

在控制台中:

neo4j-sh (0)$ CREATE (n:timeline) RETURN n;
==> +-----------+
==> | n         |
==> +-----------+
==> | Node[1]{} |
==> +-----------+
==> 1 row
==> Nodes created: 1
==> Labels added: 1
==> 967 ms
neo4j-sh (0)$ START a=node(1) MATCH a:timeline -[?]-> b:time_year -[?]-> c:time_month -[?]-> d:time_day WHERE b.year = 2013 AND c.month = 7 AND d.day = 28 RETURN b as year, c as month, d as day;
==> Unrecognized option '['

在数据浏览器中:

START a=node(1) MATCH a:timeline -[?]-> b:time_year -[?]-> c:time_month -[?]-> d:time_day WHERE b.year = 2013 AND c.month = 7 AND d.day = 28 RETURN b as year, c as month, d as day;
Returned 0 rows. Query took 138ms
Not found
There is no data matching your query in the database.

我刚刚发现这些查询在我的代码中有效,但在Neo4j控制台或数据浏览器中却没有。我认为那些将是“完美无瑕”,因此之前没有在我的代码中测试这些查询。同样奇怪的是,控制台和数据浏览器给出了不同的结果。在start而不是node(1)选择节点(*)并没有什么区别。

更新2 : 彼得·纽鲍尔(Peter Neubauer)发布的示例要点让我玩了一些。问题是这个例子每次都返回。虽然我想使返回的列可选。所以在这个例子中我希望Query3返回:

Columns: year, month, day
Data: 2010, null, null

但它返回:

Query took 264 ms and returned no rows.

当我将属性设为可选时,如下所示:

START a=node(*) 
MATCH a:timeline -[?]-> b:time_year -[?]-> c:time_month -[?]-> d:time_day 
WHERE b.year? = 2010 AND c.month? = 1 AND d.day? = 1 
RETURN b AS year, c AS month, d AS day

我得到(在gists网站上):

 Error: java.lang.NullPointerException

这是踢球者:这只发生在firefox上,在chrome上返回:查询花了1毫秒并且没有返回任何行。

然后这个查询:

START a=node(*) 
MATCH a:timeline -[?]-> b -[?]-> c -[?]-> d 
WHERE b.year? = 2010 AND c.month? = 1 AND d.day? = 1 
RETURN b AS year, c AS month, d AS day

返回:

Columns: year, month, day
Data: (9:time_year {name:"Year 2010", year:2010}), [empty table cell], [empty table cell]

这是我想要的结果(但之后没有使用标签)

然后在Chrome上进行相同的查询:

Query took 4 ms and returned no rows.

所以到目前为止我的结论是:
有5种不同的环境会产生不同的结果:

我还没有尝试过:

  • 以批处理文件开头的控制台
  • 使用Opera
  • 的gists网站http://gist.neo4j.org
  • http://console.neo4j.org/的neo4j控制台(我希望这能给出与gists相同的结果,因为它看起来一样,但我还没有测试过)

所以我对查询和一堆环境有很多变化。也许这可以通过一种方式编写脚本,以便在不同的环境中运行查询并返回结果。然后我可以将结果放在一个表中,其中一个轴是环境,另一个是测试中的查询。

4 个答案:

答案 0 :(得分:1)

为每个可选标签约束执行此操作以解决此问题

CASE
    WHEN b IS NOT NULL AND ANY(x IN LABELS(b) WHERE x="time_year") THEN b
    ELSE NULL 
END AS newB

由于b是任何类型的节点,这将确保如果存在,则它是正确的标签。它有点冗长,但很好。

- edit-- 基于flip关于索引的评论,我做了以下内容:(执行计划基于第二次运行每个查询)

CREATE INDEX ON :time_year(year);
create 
(_7:timeline ),
(_8:time_year  {year:2010}),
(_9:timeline ),
_9-[:HAS_YEAR]->_8;

第一个想法

MATCH a:timeline WITH a
MATCH a-[?]->b 
WITH a, b,  CASE WHEN b IS NOT NULL AND ANY (x IN LABELS(b) 
                                             WHERE x="time_year")  THEN b  ELSE NULL END AS newB 
WHERE newB.year? = 2010 
RETURN a, newB AS year

Detailed Query Results
Query Results

+--------------------------------+
| a         | year               |
+--------------------------------+
| Node[7]{} | Node[8]{year:2010} |
| Node[9]{} |              |
+--------------------------------+
2 rows
2 ms

Execution Plan

ColumnFilter(symKeys=["a", "b", "newB", "year"], returnItemNames=["a", "year"], _rows=2, _db_hits=0)
Extract(symKeys=["a", "b", "newB"], exprKeys=["year"], _rows=2, _db_hits=0)
  Filter(pred="nullable([($anonfun$nullableProperty$3$$anonfun$apply$21$$anon$1,true)],[$anonfun$nullableProperty$3$$anonfun$apply$21$$anon$1 == Literal(2010)])", _rows=2, _db_hits=2)
    ColumnFilter(symKeys=["a", "b", "  UNNAMED33", "newB"], returnItemNames=["a", "b", "newB"], _rows=2, _db_hits=0)
      Extract(symKeys=["a", "b", "  UNNAMED33"], exprKeys=["newB"], _rows=2, _db_hits=0)
        PatternMatch(g="(a)-['  UNNAMED33']-(b)", _rows=2, _db_hits=1)
          PatternMatch(g="", _rows=2, _db_hits=0)
            Filter(pred="hasLabel(a: timeline)", _rows=2, _db_hits=0)
              NodeByLabel(label="timeline", identifier="a", _rows=2, _db_hits=0)

第二个想法

MATCH a:timeline WITH a
MATCH a-[?]->b 
WHERE b.year? = 2010 
RETURN a, b AS year

Detailed Query Results
Query Results

+--------------------------------+
| a         | year               |
+--------------------------------+
| Node[7]{} | Node[8]{year:2010} |
| Node[9]{} |              |
+--------------------------------+
2 rows
2 ms

Execution Plan

ColumnFilter(symKeys=["a", "b", "  UNNAMED33", "year"], returnItemNames=["a", "year"], _rows=2, _db_hits=0)
Extract(symKeys=["a", "b", "  UNNAMED33"], exprKeys=["year"], _rows=2, _db_hits=0)
  Filter(pred="nullable([($anonfun$nullableProperty$3$$anonfun$apply$21$$anon$1,true)],[$anonfun$nullableProperty$3$$anonfun$apply$21$$anon$1 == Literal(2010)])", _rows=2, _db_hits=2)
    PatternMatch(g="(a)-['  UNNAMED33']-(b)", _rows=2, _db_hits=3)
      PatternMatch(g="", _rows=2, _db_hits=0)
        Filter(pred="hasLabel(a: timeline)", _rows=2, _db_hits=0)
          NodeByLabel(label="timeline", identifier="a", _rows=2, _db_hits=0)

如果我们在Cypher中只提供NULLIF功能,那么这会让它变得更清晰一些。虽然在任何一种情况下检查关系上的节点都不会使用任何索引。

答案 1 :(得分:0)

从这个页面得到答案:http://grokbase.com/t/gg/neo4j/137qbdyn14/use-label-in-start

START a=node(2)
MATCH a:timeline -[?]-> b -[?]-> c -[?]-> d
WHERE b.year? = 2013 AND c.month? = 7 AND d.day? = 28
RETURN b, c, d

然而关于标签的其他问题现在仍然是个谜。

答案 2 :(得分:0)

这个问题的正确答案是,Neo4j 2.0.0里程碑03中没有此功能或缺少(错误?)。但现在已添加到Neo4j 2.0.0 Milestone 05中。{{1 }}

来源:https://github.com/neo4j/neo4j/blob/master/packaging/standalone/standalone-community/src/main/distribution/text/community/CHANGES.txt

(我还没有测试过)

答案 3 :(得分:-1)

我对此做了一个图表要点,请参阅http://gist.neo4j.org/?6113785,似乎标签正在运作。想做出贡献并澄清一下吗?