neo4j CREATE UNIQUE看起来非常慢

neo4j CREATE UNIQUE看起来非常慢,neo4j,Neo4j,我试图建立一系列的关系,在这些关系中,Foo在一系列的时间范围内“在”酒吧里 我的基本查询如下所示: MERGE (f:Foo {id: 123}) MERGE (b111:Bar {id: 111}) CREATE UNIQUE (f) - [:IN { from:130958270580000000, to: 130958975440000000 } ] -> (b111) // find which :Bar f was in at a particular instance WI

我试图建立一系列的关系,在这些关系中,Foo在一系列的时间范围内“在”酒吧里

我的基本查询如下所示:

MERGE (f:Foo {id: 123})
MERGE (b111:Bar {id: 111})
CREATE UNIQUE (f) - [:IN { from:130958270580000000, to: 130958975440000000 } ] -> (b111)
// find which :Bar f was in at a particular instance
WITH {params.instance} as instance
MATCH (f:Foo {id: 123})-[:IN]->(fb:Foobar)
WHERE fb.from <= instance <= fb.to
WITH fb
MATCH (fb)-[:IN]->(b:Bar)
RETURN b
这在功能上完全符合我的要求,但是当我添加语句时,查询会变得非常慢。循环这个语句也是非常缓慢的

例如:

例如,如果我创建400个这样的关系,需要23秒

我运行了上面的配置文件,看起来它为这个语句做了大量的db点击(158毫秒内总共586次db点击),这看起来很奇怪。随着我添加更多CREATE语句,这似乎呈指数增长

我也尝试过在Foo和Bar中添加索引,但它们似乎没有任何区别


我是neo4j的新手,所以我可能在某处做了一些愚蠢的事情或做了一个错误的假设,但我不明白为什么这个查询会这么慢。

慢不是节点上的匹配,而是关系上的“创建唯一”(合并也会遇到同样的慢)。归根结底,在neo4j中,非索引属性访问可能非常昂贵

关系上没有索引,因此任何创建唯一或合并操作(如上文所述)都必须扫描该类型的所有关系,并比较属性值,以查看该关系是否已经存在。显然,成本将随着存在的此类关系的数量而增加

有几种方法可以缓解这种情况

如果您知道这些与特定属性的关系还不存在,请使用CREATE而不是CREATE UNIQUE。您可以在关系创建结束时运行查询以检查您是否在任何地方进行了错误操作,并且有一个可以删除的重复项

另一种方法是调整模型。不要让属性出现在关系本身上,而是在:Foo和:Bar节点之间创建一个具有自己标签的中间节点,并使用它来保存from和to属性。您需要为这些属性编制索引,以避免合并或创建唯一的减速

我建议使用一个中间节点,特别是当您计划使用涉及这些时间属性的查询时,以及如果其中肯定有很多查询时。如果这些属性仅在关系上,则无法利用索引加快查询速度,这可能是以后的问题

编辑

中间节点的使用可能如下所示(假设索引位于:Foobar(from)和:Foobar(to)):

当然,如果可能的话,您可能需要将您的关系和标签重命名为更合理的名称

使用此选项的查询可能如下所示:

MERGE (f:Foo {id: 123})
MERGE (b111:Bar {id: 111})
CREATE UNIQUE (f) - [:IN { from:130958270580000000, to: 130958975440000000 } ] -> (b111)
// find which :Bar f was in at a particular instance
WITH {params.instance} as instance
MATCH (f:Foo {id: 123})-[:IN]->(fb:Foobar)
WHERE fb.from <= instance <= fb.to
WITH fb
MATCH (fb)-[:IN]->(b:Bar)
RETURN b
//查找特定实例中的:条f
以{params.instance}作为实例
匹配(f:Foo{id:123})-[:IN]->(fb:Foobar)

谢谢,这很有道理。我试着把它改成一个CREATE(没有唯一性),但它对时代基本没有影响。就将其拆分为一个单独的节点而言,我认为我不容易做到这一点,实际的唯一性是关系(例如,foo:1在这两个时间段之间的bar:2中)。我想不出任何方法可以合理地将其拆分为一个新节点?我认为在新实体的foo和bar中加入一些标识符来提供唯一性是愚蠢的?实际上,由于某些原因,它仍然很慢,但由于CREATE(而非unique)不确定速度的慢,db命中数急剧下降,但我添加了一些使用和查询中间节点的示例。请记住,虽然数据库创建时间是一个问题,但更大的问题是您的查询性能,因此使用它作为使用哪种建模的更好基准。简介是你的朋友。如果两段不同关系的时间相同,不会造成一些奇怪,例如如果foo:1在1-2的酒吧:1,foo:2在1-2的酒吧:2,这不意味着foo:1在1-2的酒吧:1和酒吧:2?当应该有两个foobar时,会有一个foobar?我不确定我是否在跟随。通过foo:1和foo:2,您指的是两个独立的:foo节点?如果是这样,那么一个:Foo节点的关系(以及相应的:Foobar节点)应该独立于任何其他:Foobar节点的关系。One:Foobar节点应仅与One:Foo节点和One:Bar节点具有关系。如果您谈论的是单个:Foo节点的:Foobar节点的多次重叠,那么这就是您必须解决的数据输入问题。无论是原始数据模型还是我的数据模型都无法为您解决这一问题。