【问题标题】:Filter Relationships in Neo4j Using Start/End Dates在 Neo4j 中使用开始/结束日期过滤关系
【发布时间】:2018-10-06 07:57:32
【问题描述】:

我有一个图模型 -

(p:Person)-[r:LINK {startDate: timestamp, endDate: timestamp}]->(c:Company)

一个人可以同时链接到多个公司,一个公司可以有多个人同时链接到它(即公司和人之间存在多对多的关系)。

endDate 属性是可选的,只有在一个人离开公司时才会出现。

我正在尝试显示一个连接网络,并且可以使用以下密码查询成功返回一个人的所有相关节点(这将显示 2 个级别的人连接)-

MATCH (p:Person {id:<id>})-[r:LINK*0..4]-(l) RETURN *

我现在需要做的是过滤关系在时间范围内匹配的关系,例如第 1 个人于 2000 年 1 月 1 日至 2002 年 12 月 31 日期间在 A 公司工作。第 2 个人于 2001 年 1 月 1 日至 2001 年 6 月 31 日在 A 公司工作。第 3 个人于 2005 年 1 月 1 日在 A 公司工作,目前仍在 A 公司。第 1 个人的结果应包括第 2 个人,但不包括第 3 个人。

同样的逻辑需要应用于图表的所有级别(我们允许用户显示 3 级连接)并与每个级别的父节点相关联,即在显示级别 2 时,Person 2 的日期和Person 3 应该用于过滤他们各自的关系。

基本上,我们正在尝试做一些类似于 LinkedIn 连接的事情,但要根据同时在公司工作的人进行过滤。

我已尝试使用 REDUCE 函数,但无法使逻辑适用于可选的结束日期 - 有人可以建议如何根据开始日期和结束日期过滤关系吗?

【问题讨论】:

  • 显示您的尝试和样本数据以供验证。
  • 当您在同一公司中搜索具有重叠时间的人员时,请注意解释多层次的含义。在linkedIn 上,Person1 与Person2 相关,Person2 与Person3 相关,因此如果您查看其他公司,它可能会告诉您Person3 是2 级连接。没有示例,您要达到的目标是不清楚的

标签: neo4j cypher


【解决方案1】:

事实证明,日期范围有 4 种重叠方式,但只有 2 种不会重叠(第 1 个人在第 2 个人开始之前结束,或者第 2 个人在第 1 个人开始之前结束),所以要简单得多检查这些不重叠的条件是否都不存在。

在级别 1 的情况下,这个查询应该可以解决问题:

MATCH (start:Person{id:1})-[r1:LINK]->(c)<-[r2:LINK]-(suggest)
WHERE NOT ((r1.endDate IS NOT NULL and r1.endDate < r2.startDate) 
        OR (r2.endDate IS NOT NULL and r2.endDate < r1.startDate))
RETURN suggest

棘手的部分是将其应用于多个级别。

虽然我们可以创建一个 Cypher 查询来动态处理这个问题,但关系的评估只会在扩展之后发生,而不是在扩展期间发生,因此它可能不是最有效的:

MATCH path = (start:Person{id:1})-[:LINK*..6]-(suggest:Person)
WITH path, start, suggest, apoc.coll.pairsMin(relationships(path)) as pairs
WITH path, start, suggest, [index in range(0, size(pairs)-1) WHERE index % 2 = 0 | pairs[index]] as pairs
WHERE none(pair in pairs WHERE (pair[0].endDate IS NOT NULL AND pair[0].endDate < pair[1].startDate) 
                          OR (pair[1].endDate IS NOT NULL AND pair[1].endDate < pair[0].startDate))
RETURN suggest

这里的一些亮点......

我们使用 APOC Procedures 中的 apoc.coll.pairsMin() 从每个路径中的关系集合中获取相邻关系对,但我们只对偶数条目感兴趣(来自同一工作人员的两个关系company),因为奇数对对应于同一个人前往两家不同公司的关系。

所以如果我们在这个模式上执行:

MATCH path = (start:Person)-[r1:LINK]-&gt;(c1)&lt;-[r2:LINK]-(person2)-[r3:LINK]-&gt;(c2)&lt;-[r4:LINK]-(person3)

apoc.coll.pairsMin(relationships(path)) 将返回 [[r1, r2], [r2,r3], [r3,r4]],正如您所见,我们需要考虑的关系是将 2 个人与一家公司联系起来,因此在配对列表中索引 0 和 2。

在我们获得配对后,我们需要确保考虑到建议的路径中所有那些有趣的关系对都符合您的标准并且重叠(或不重叠)。

【讨论】:

  • 非常感谢@InverseFalcon - 这正是我想要的。
【解决方案2】:

这样的事情应该可以工作:

MATCH path=(p:Person {id: $id})-[r:LINK*..4]-(l)
WHERE ALL(x IN NODES(path)[1..] WHERE x.startDate <= p.endDate AND x.endDate >= p.startDate)
RETURN path;

假设:

  • 主要关注人的id值由$idparameter提供。
  • 您希望variable-length relationship 模式的下限为 1(这是默认值)。如果您使用 0 作为下限,那么您也会因此获得主要的关注人物——这可能不是您想要的。
  • startDateendDate 的值适合使用 comparison operators 进行比较

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-11-10
    • 2015-01-28
    • 2017-01-15
    • 1970-01-01
    • 1970-01-01
    • 2020-03-04
    • 1970-01-01
    相关资源
    最近更新 更多