0

在 Neo4j 2.0 M06 中,我了解 CREATE UNIQUE 已被贬值并被 MERGE 和 MATCH 取代,但我发现很难看到如何使用它来创建唯一路径。

例如,我想创建一个

MERGE root-[:HAS_CALENDER]->(cal:Calender{name:'Booking'})-[:HAS_YEAR]->(year:Year{value:2013})-[:HAS_MONTH]-(month:Month{value:'January'})-[:HAS_DAY]->(day:Day{value:1})
ON CREATE cal
SET cal.created = timestamp()
ON CREATE year
SET year.created = timestamp()
ON CREATE month
SET month.created = timestamp()
ON CREATE day
SET day.created = timestamp()

目的是当我尝试向日历添加新的日期时,它应该只创建年份和月份,否则只需添加到现有路径。现在,当我运行查询时,我得到一个 STATEMENT_EXECUTION_ERROR

MERGE only supports single node patterns

我应该在这里执行多个语句来实现这一点。所以问题是在 Neo4j 中处理这种情况的最佳方式是什么?

编辑

我确实稍微改变了我的方法,现在即使在进行了多次调用之后,我认为我的合并是在标签级别发生的,而不是试图限制到我提供的起始节点,因此我最终得到的是跨年共享的节点和月份,这不是我所期待的

在此处输入图像描述

如果有人能建议我如何获得如下所示的正确图表,我将不胜感激

在此处输入图像描述

我的 c# 代码有点像这样:

var qry = GraphClient.Cypher
            .Merge("(cal:CalendarType{ Name: {calName}})")
            .OnCreate("cal").Set("cal = {newCal}")
            .With("cal")
            .Start(new { root = GraphClient.RootNode})
            .CreateUnique("(root)-[:HAS_CALENDAR]->(cal)")
            .WithParams(new { calName = newCalender.Name, newCal = newCalender })
            .Return(cal => cal.Node<CalenderType>());
        var calNode = qry.Results.Single();


        var newYear = new Year { Name = date.Year.ToString(), Value = date.Year }.RunEntityHousekeeping();

        var qryYr = GraphClient.Cypher
            .Merge("(year:Year{ Value: {yr}})")
            .OnCreate("year").Set("year = {newYear}")
            .With("year")
            .Start(new { calNode })
            .CreateUnique("(calNode)-[:HAS_YEAR]->(year)")
            .WithParams(new { yr = newYear.Value, newYear = newYear })
            .Return(year => year.Node<Year>());
        var yearNode = qryYr.Results.Single();


        var newMonth = new Month { Name = date.Month.ToString(), Value = date.Month }.RunEntityHousekeeping();
        var qryMonth = GraphClient.Cypher
            .Merge("(mon:Month{ Value: {mnVal}})")
            .OnCreate("mon").Set("mon = {newMonth}")
            .With("mon")
            .Start(new { yearNode })
            .CreateUnique("(yearNode)-[:HAS_MONTH]->(mon)")
            .WithParams(new { mnVal = newMonth.Value, newMonth = newMonth })
            .Return(mon => mon.Node<Month>());
        var monthNode = qryMonth.Results.Single();


        var newDay = new Day { Name = date.Day.ToString(), Value = date.Day, Date = date.Date }.RunEntityHousekeeping();
        var qryDay = GraphClient.Cypher
            .Merge("(day:Day{ Value: {mnVal}})")
            .OnCreate("day").Set("day = {newDay}")
            .With("day")
            .Start(new { monthNode })
            .CreateUnique("(monthNode)-[:HAS_DAY]->(day)")
            .WithParams(new { mnVal = newDay.Value, newDay = newDay })
            .Return(day => day.Node<Day>());
        var dayNode = qryDay.Results.Single();

问候基兰

4

3 回答 3

2

文档页面上没有任何地方说它CREATE UNIQUE已被弃用。

MERGE只是一种可供您使用的新方法。它支持一些新场景(基于标签ON CREATEON MATCH触发器的匹配),但也不涵盖更复杂的场景(超过单个节点)。

听起来你已经很熟悉了CREATE UNIQUE。目前,我认为您仍然应该使用它。

于 2013-11-04T04:31:47.203 回答
0

在我看来,您希望您的图表看起来像什么样的图片具有由关系强加的顺序,但您的代码使用节点对顺序进行建模。如果你想要那个图,你需要使用关系类型[2010][2011]而不是像[HAS_YEAR]->({value:2010}).

另一种说法是:您试图通过标签和属性的组合,从本质上构成节点的唯一性,例如(unique:Day {value:4})。假设您有相关的限制,这将是数据库范围内的唯一性,因此所有月份只有一个第四天可以共享。您想要的是外在的本地唯一性,即通过关系层次结构可传递地建立和扩展的唯一性。节点的唯一性不在于其内部属性,而在于其相对于其父节点的外部“位置”或“顺序”。当地独特的图案(month)-[:locally_unique_rel]->(day)当月份是唯一的,并且月份是唯一的,而不是通过属性和标签,而是通过其在其年份下的“顺序”或“位置”外在的,它在更广泛的范围内是唯一的。因此具有传递性。我认为这是使用图表建模的优势,除此之外,它还允许您继续划分您的结构。例如,如果您想将您的一些日子分成上午和下午或几个小时,您可以轻松地做到这一点。

因此,在您的图表中,[HAS_DAY]使所有日期与其月份同等相关,因此不能用于区分它们。您已经在一个月内在本地解决了这个问题,因为属性值不同,但自从

(november)-[:HAS_DAY]->(4th)` and `(december)-[:HAS_DAY]->(4th)

不按属性值或标签区分,它们是图中的同一个节点。在本地,不到一个月的时间,唯一节点可以通过

[11]->()-[4]->(unique1), [11]->()-[5]->(unique2)

[HAS_MONTH]->({value:11})-[HAS_DAY]->(unique1 {value:4}), 
[HAS_MONTH]->({value:11})-[HAS_DAY]->(unique2 {value:5})  

不同之处在于,有了前一个外在的局部唯一性,您就可以享受传递性的好处。由于月份在一年中是唯一的,因为(november)in 在[11]->(november)本地是唯一的,因此 11 月的日子在该年也是唯一的 -(fourth)节点在

[11]->(november)-[4]->(fourth)

[12]-(december)->[4]->(fourth)

这相当于将更多的语义模型转移到您的关系中,留下用于存储数据的节点。您发布的图片中的节点标识符仅用于教学,用 x、y、z 或空括号替换它们可能会更好地揭示图形的结构或脚手架。

如果您想保持关系类型不变,向每个关系添加排序属性以创建类似的模式(november)-[:HAS_DAY {order:4}]->(4th)也可以。这对于查询可能性能较差,但您可能还有其他值得考虑的问题。

于 2013-11-04T09:03:47.620 回答
0

此代码允许您在创建特定日期的事件时按需创建日历图表。您需要对其进行修改以允许多天的事件,但您的问题似乎更像是创建独特的路径,对吧?您可能希望修改它以使用您选择的语言中的参数。

首先我创建根:

CREATE (r:Root {id:'root'})

然后使用这个可重用的 MERGE 查询来连续匹配或为日历创建子图。我沿着根传递,所以我可以在最后显示图表:

MATCH (r:Root)
MERGE r-[:HAS_CAL]->(cal:Calendar {id:'General'})
WITH r,cal MERGE (cal)-[:HAS_YEAR]->(y:Year {id:2011})
WITH r,y MERGE (y)-[:HAS_MONTH]->(m:Month {id:'Jan'})
WITH r,m MERGE (m)-[:HAS_DAY]->(d:Day {id:1})
CREATE d-[:SCHEDULED_EVENT]->(e:Event {id:'ev3', t:timestamp()})
RETURN r-[*1..5]-()

多次调用时创建这样的图形:

在此处输入图像描述

这有帮助吗?

于 2014-01-28T16:56:58.173 回答