我有一个分析用例,我将一堆节点堆叠到具有不同属性集的Neo4j中。它们来自不同的系统和不同的表,但是各种节点类型都有共享属性(信息已通过ETL过程)。
我想要做的是查询具有属性的所有节点的图形,例如customer_id,并查找具有相同值属性的所有其他节点,并在它们之间创建边缘,捕获任意匹配。
我根据源表在摄取期间标记节点,我已经为链接属性创建了自动索引,并且我已经为具有公共属性的节点添加了标签,这样我就可以放置标签关于它们的索引,但我没有偶然发现正确的语法来有效地建立所有连接。
我希望将其保留在Cypher中,因为它是客户可能会要求不同观点的东西,因此我们可能会根据其他类型的匹配发明新的边缘(所以"发现& #34;关系)而不是考虑到完整的模式,然后能够使用发现的边来执行遍历,回答在关联之前无法提出的问题。
我的测试套件有900万个节点,到目前为止,我所做的许多尝试都表现不佳。
这是一种天真的尝试,它实际上可以对少数节点起作用,但不能很好地扩展。你会如何解决这个问题?我认为有一些方法可以有效地使用集合,但我还没有找到这种语法。
这是一个天真的尝试,它适用于一小组节点,但不能很好地扩展。
using periodic commit 100
match
(a:CUST_ID_NODES), (b:CUST_ID_NODES)
where
a.customer_id=b.customer_id
create unique
(a)-[r:CUSTOMER_ID {customer_id: a.customer_id}]-(b);
答案 0 :(得分:2)
标签:CUST_ID_NODES
是否可以在属性.customer_id
上加入节点?如果是这样,你最好在摄取时创建关系。这听起来像是为潜在的未来视图定义索引来创建,但我不认为这比从一开始就创建你知道的所有视图更便宜或更容易。
如果您仍想在密码中进行此操作,请参阅以下内容。您当前的查询执行为:将所有客户ID节点匹配为a
;对于每个a
,将所有客户ID节点与b
匹配;过滤共享.customer_id
。如果您有10万个客户ID节点,那么10 000 000 000个结果将过滤共享属性,而这些结果都不会使用索引。查询的第一个改进可能是从.customer_id
的每个不同值开始,并从索引中查找具有该值的节点。假设你有一个像
CREATE INDEX ON :CUST_ID_NODES(customer_id)
执行此操作以获取每个customer_id的节点
MATCH (a:CUST_ID_NODES)
WITH DISTINCT a.customer_id as id
MATCH (a:CUST_ID_NODES {customer_id:id})
// You can continue with flat (id, a) rows, or collect a per id
// and do stuff in a FOREACH loop, something like:
WITH id, collect(a) as aa
MERGE (common {customer_id:id})
FOREACH (a IN aa | MERGE a-[:COMMON]->common)
现在,查询获取了用于查找节点的不同值列表,这次是在获取节点时使用标签索引。
然后有不同的方法来连接这些节点。您将每个节点与共享其id的每个节点相关联。最佳表示取决于您以后如何查询图表。如果想法是共享customer_id
的节点表示相同的事物并因此可以合并,最简单的方法可能是将共享表示为新节点并将共享节点与其关联,或者合并属性以及从共享节点到新节点的关系。但是我仍然不相信在cypher而不是在ETL和摄取期间这样做有好处 - 它似乎只是Talend或Pentaho中的Transform步骤的事情。
答案 1 :(得分:0)
如果节点a和b具有相同的customer_id,您是否应该在两个方向上创建它们之间的关系?这似乎不是一件非常有效的事情。我认为你可以简单地避免创建这些关系。
我的建议是:
根据该标签和属性创建索引:
CREATE INDEX ON:客户(customer_id);
然后,只要您需要找到具有相同customer_id的所有节点,就可以有效地执行此操作:
MATCH (c:Customer {customer_id:{id}}) RETURN c;