如何限制节点之间的关系数?

时间:2019-01-09 19:52:16

标签: neo4j cypher

我有一个关于如何限制节点之间创建的关系数的问题。我肯定可以在执行MATCH时限制数量或产生的音符。但实际上,我更关心的是不存储数据(在这种情况下为关系)的想法,因为将来我将永远不会使用它。

在我的情况下,我有以下图形:

Jypiter notebooks

请注意,我有一个用户和10个不同的艺术家。

我的要求是存储用户通过CREATE (u:User {id: 100001}), (:Artist {id: "0001"}), (:Artist {id: "0002"}), (:Artist {id: "0003"}), (:Artist {id: "0004"}), (:Artist {id: "0005"}),(:Artist {id: "0006"}),(:Artist {id: "0007"}),(:Artist {id: "0008"}),(:Artist {id: "0009"}),(:Artist {id: "0010"}); 关系收听的最近5位艺术家。因此,执行后:

LISTENED_TO

我会有一个像这样的图

MATCH (u:User {id: 100001}), (a:Artist {id: "0001"})
CREATE (u)-[:LISTENED_TO]->(a);
MATCH (u:User {id: 100001}), (a:Artist {id: "0003"})
CREATE (u)-[:LISTENED_TO]->(a);
MATCH (u:User {id: 100001}), (a:Artist {id: "0005"})
CREATE (u)-[:LISTENED_TO]->(a);
MATCH (u:User {id: 100001}), (a:Artist {id: "0007"})
CREATE (u)-[:LISTENED_TO]->(a);
MATCH (u:User {id: 100001}), (a:Artist {id: "0009"})
CREATE (u)-[:LISTENED_TO]->(a);

现在,我得到的信息是该用户已经听了5位不同的艺术家的音乐。现在让我们假设用户收听了来自艺术家{id:“ 0010”}的歌曲,我希望删除第一个插入的关系(u:User {id: 100001})-[l:LISTENED_TO]->(a:Artist {id: "0001"}) (u:User {id: 100001})-[l:LISTENED_TO]->(a:Artist {id: "0003"}) (u:User {id: 100001})-[l:LISTENED_TO]->(a:Artist {id: "0005"}) (u:User {id: 100001})-[l:LISTENED_TO]->(a:Artist {id: "0007"}) (u:User {id: 100001})-[l:LISTENED_TO]->(a:Artist {id: "0009"}) (例如使用类似FIFO的机制),并删除新的图就像:

(u:User {id: 100001})-[l:LISTENED_TO]->(a:Artist {id: "0001"})

也许我正在扩展Neo4J支持的功能,但是我想知道这是否可能。我的目标是节省不需要存储的空间,因为我只需要最近使用的(在这种情况下为听众)最近的5位艺术家即可。

1 个答案:

答案 0 :(得分:1)

如果LISTENED_TO关系在time属性中包含时间戳,那么在添加新关系时,您可以使用该关系仅保留5个最新关系(假设新关系的时间戳)总是足够近,并且您通过了userIdartistIdtime parameters):

MATCH (u:User {id: $userId})
OPTIONAL MATCH (u)-[lt:LISTENED_TO]->(:Artist)
WITH u, lt ORDER BY lt.time DESC
WITH u, COLLECT(lt) AS lts
FOREACH(x IN lts[4..] | DELETE x)
MERGE (a:Artist {id: $artistId})
CREATE (u)-[:LISTENED_TO {time: $time}]->(a)

[更新]

注意:如果该用户最近多次收听同一位艺术家,则上述查询允许该位艺术家与该用户具有多种关系。

如果您希望某个艺术家与特定用户最多具有一种关系,则此更复杂的查询应该可以工作:

MATCH (u:User {id: $userId})
OPTIONAL MATCH p= (u)-[lt:LISTENED_TO]->(a:Artist)
WITH u, {lt: lt, a: a} AS data ORDER BY lt.time DESC
WITH u, REDUCE(
  s = {cnt: 0, del: []}, x IN COLLECT(data) |
    CASE WHEN x.a.id = $artistId OR s.cnt = 4
    THEN {cnt:s.cnt, del:s.del + x.lt}
    ELSE {cnt:s.cnt + 1, del:s.del} END).del AS del
FOREACH(x IN del | DELETE x)
MERGE (a:Artist {id: $artistId})
CREATE (u)-[:LISTENED_TO {time: $time}]->(a)