我已经将我的关系数据库迁移到neo4j,并在研究是否可以在提交新系统之前实现某些功能。我刚刚读了两本neo4j书,但是不幸的是,它们并没有涵盖我希望会更加不言而喻的两个关键功能。对于这些问题是否易于实现或我是否应该坚持使用sql,我将不胜感激。谢谢!
我需要的功能是: 1)我已经运行了一个脚本,将:leaf标签分配给树上所有叶子的节点。在一个已知节点及其相关的叶节点之间的路径中,我旨在为每个节点分配一个级别属性,以反映该节点来自该已知节点(或叶节点-我能最轻松地工作的)的跳数。 / p>
我尝试过:
match path=(n:Leaf)-[:R*]->(:Parent {Parent_ID: $known_value})
with n, length(nodes(path)) as hops
set n.Level2=hops;
和
path=(n:Leaf)-[:R*]->(:Parent {Parent_ID: $known_value})
with n, path, length(nodes(path)) as hops
foreach (n IN relationships (path) |
set n.Level=hops);
第一个将只具有完整路径值的属性分配给叶节点。第二种方法将具有路径的全长值的属性分配给路径中的所有关系。
我应该使用最短路径,为所有节点创建一个值为= 1的虚假属性,并迭代添加该属性的权重吗?
2)我需要找到给定父节点的公共子节点。例如,我的孩子每个[:like]很多电影,我想建立一个从我自己到我孩子共同喜欢的电影的[:like]关系(因此,如果1个孩子中的1个喜欢电影,那么我也喜欢它,但是如果只有三分之二的人喜欢看电影,那什么也没发生。
我在这里找到了三个路径的解决方案: Need only common nodes across multiple paths - Neo4j Cypher 但是我需要一种适用于任意数量路径(从1开始)的解决方案。
3)然后,我计划从最远的叶子节点开始,创建与儿童电影的关系,并逐步移向我的已知节点,并重复创建关系,以便最顶层的祖父母只喜欢所有儿童的电影。 (在所有孩子中的所有孩子中……)就像一个共同点,如果每个人都同意这一点,那就是整个大家庭在周六晚上观看的电影。
neo4j可以完成这项工作吗?对于拥有基本Cypher的人来说,这项任务有多难?这主要是我在关系数据库中的操作方式/我应该考虑在图形数据库中完全不同地实现这一点吗?
非常感谢任何建议。谢谢!
答案 0 :(得分:0)
1。
当已经匹配的起始节点和结束节点不是根和叶时,shortestPath()可能会有所帮助,因为一旦找到第一个路径,它就不会继续寻找其他路径。如果您的已经匹配的起始节点和结束节点是图的树状结构(无环结构)的根和叶,则没有真正的理由使用shortestPath()。
通常,在设置诸如树中节点深度之类的内容时,您将使用length(path)
,因此根将位于深度0,其子级位于深度1。
您为关系设置属性的方法将是一个问题,因为在不同深度的多个叶节点的多条路径中可能存在相同的关系。您的查询可能会一遍又一遍地覆盖相同关系上的属性,直到最后一次写入获胜为止。最好匹配所有节点(在查询中省略:Leaf
),获取路径中的最后一个关系,并设置其深度:
MATCH path=(:Parent {Parent_ID: $known_value})<-[:R*]-()
WITH length(path) as length, last(relationships(path)) as rel
SET rel.Level = length
2。
因此,如果树中父节点的所有子节点都像电影一样,那么父节点就应该像电影一样。这样的事情应该起作用:
MATCH path=(:Parent {Parent_ID: $known_value})<-[:R*0..]-(n)
WITH n, size((n)<-[:R]-()) as childCount
MATCH (n)<-[:R]-()-[:like]->(m:Movie)
WITH n, childCount, m, count(m) as movieLikes
WHERE childCount = movieLikes
MERGE (n)-[:like]->(m)
这里的想法是,对于电影,如果该电影节点的数量等于子节点的数量,则所有子节点都喜欢该电影(前提是一个节点只能对同一部电影进行一次:)。 / p>
该查询不能用于自下而上地建立喜欢,但是,类似关系(个人喜欢,而不是喜欢,因为所有孩子喜欢它)必须首先出现在所有节点上,这样工作。
3。
为了执行自下而上的方法,您将需要强制以特定顺序执行查询,我认为最好的方法是先按深度顺序对节点进行处理,然后再使用apoc.cypher.doIt(),APOC Procedures中的proc,可让您每行执行整个Cypher查询,以进行计算。
这种方法应该有效:
MATCH path=(:Parent {Parent_ID: $known_value})<-[:R*0..]-(n)
WHERE NOT n:Leaf // leaves should have :like relationships already created
WITH n, length(path) as depth, size((n)<-[:R]-()) as childCount
ORDER BY depth DESC
CALL apoc.cypher.doIt("
MATCH (n)<-[:R]-()-[:like]->(m:Movie)
WITH n, childCount, m, count(m) as movieLikes
WHERE childCount = movieLikes
MERGE (n)-[:like]->(m)
RETURN count(m) as relsCreated",
{n:n, childCount:childCount}) YIELD value
RETURN sum(value.relsCreated) as relsCreated
也就是说,我不确定这是否会按照您认为的那样做。或更确切地说,只有在最初仅在叶子节点上设置与电影的唯一:like关系,并且(在运行此传播查询之前)树中没有其他中间节点的情况下,才可以按照您认为的方式工作。与电影的关系。