匹配 FOAF,但按日期限制路径;特别是在 Neo4j 中以顺序方式
Match FOAF, but constrain path by date; specifically in a sequential manner, in Neo4j
我正在 Neo4j 中进行 'friend of a friend' 类型的 MATCH。唯一让我失望的是试图按日期限制所有关系。
基本图是这样的:
图表的 'real' 版本有 10 个一级朋友和 3385 个二级朋友。
虽然我没有在上图中的每条边上都写上日期 属性,但确实如此。任何日期都没有顺序。
总体思路非常简单:我想确保忽略日期 属性 早于预定最大日期的任何关系。
稍微棘手的部分是,如果在第一个关系中违反了最大日期约束(如上图中从节点脱落的三个边之一),则该边被分成两半并且没有沿着该路径的其他遍历应该能够发生。 (例如,我不想要任何叶节点)。
我写了这个:
MATCH
(n)-[f1:FRIEND]-()-[f2:FRIEND]-(m)
WITH n, m,split('1962-1-1', '-') AS maxdate
WHERE n.person_id='180'
AND(
(
toInt(maxdate[0]) > toInt(split(f1.date, '-')[0])
)
OR
(
toInt(maxdate[0]) = toInt(split(f1.date, '-')[0])
AND
toInt(maxdate[1]) >= toInt(split(f1.date, '-')[1])
))
AND(
(
toInt(maxdate[0]) > toInt(split(f2.date, '-')[0])
)
OR
(
toInt(maxdate[0]) = toInt(split(f2.date, '-')[0])
AND
toInt(maxdate[1]) >= toInt(split(f2.date, '-')[1])
))
RETURN m;
这个代码块 运行 大约 20 分钟,最终似乎产生了接近我的目标的结果。这是它在浏览器中的样子:
(有350个节点)
首先,我承认这显然是一些非常糟糕的代码(无论是在美学还是性能方面)。其次,我注意到周边没有关联的节点。
我认为发生的事情是,一级关系的日期条件不合格,但二级关系的日期条件不合格,所以我最终得到了我不想的 'friend of a friend'被包括在内。
如何修改我的日期条件,以便在一次度边无效时消除这些独立节点?
如果有人有任何见解,我将不胜感激。 (不要太糊涂,但多亏了 SO 社区,我已经取得了相当快的进展,为此我很感激。)
首先不应该运行那么久,主要原因是您的节点上没有标签+索引。
首先添加那些:
CREATE CONSTRAINT ON (p:Person) ASSERT p.person_id is unique;
MATCH (n) where exists(n.person_id) SET n:Person;
如果你有时间 yyyy-mm-dd
无论如何(我希望至少如此)你可以直接比较它们:(有 2 位数字又名 01
)即 '2012-01-10' > '2011-08-31'
)
WITH '1962-01-01' AS maxdate
MATCH (n:Person)-[f1:FRIEND]-()-[f2:FRIEND]-(m:Person)
WHERE n.person_id='180' AND f1.date < maxdate and f2.date < maxdate
RETURN m;
您也可以使用缩写形式:(n:Person {person_id:'180'})
如果您想对路径中的关系有一个通用表达式,请在可变长度路径模式中使用变量 rels
(然后是一个集合):
WITH '1962-01-01' AS maxdate
MATCH (n:Person {person_id:'180'})-[rels:FRIEND*2]-(m:Person)
WHERE ALL(r in rels WHERE r.date < maxdate)
RETURN m;
你也可以使用rels(path)
WITH '1962-01-01' AS maxdate
MATCH path = (n:Person {person_id:'180'})-[:FRIEND*2]-(m:Person)
WHERE ALL(r in rels(path) WHERE r.date < maxdate)
RETURN m;
或者如果路径的关系是相互关联的:
WITH '1962-01-01' AS maxdate
MATCH (n:Person {person_id:'180'})-[rels:FRIEND*2]-(m:Person)
WHERE ALL(idx in range(0, size(rels)-2) WHERE (rels[idx]).date < maxdate AND (rels[idx]).date < (rels[idx+1]).date)
RETURN m;
我正在 Neo4j 中进行 'friend of a friend' 类型的 MATCH。唯一让我失望的是试图按日期限制所有关系。
基本图是这样的:
图表的 'real' 版本有 10 个一级朋友和 3385 个二级朋友。
虽然我没有在上图中的每条边上都写上日期 属性,但确实如此。任何日期都没有顺序。
总体思路非常简单:我想确保忽略日期 属性 早于预定最大日期的任何关系。
稍微棘手的部分是,如果在第一个关系中违反了最大日期约束(如上图中从节点脱落的三个边之一),则该边被分成两半并且没有沿着该路径的其他遍历应该能够发生。 (例如,我不想要任何叶节点)。
我写了这个:
MATCH
(n)-[f1:FRIEND]-()-[f2:FRIEND]-(m)
WITH n, m,split('1962-1-1', '-') AS maxdate
WHERE n.person_id='180'
AND(
(
toInt(maxdate[0]) > toInt(split(f1.date, '-')[0])
)
OR
(
toInt(maxdate[0]) = toInt(split(f1.date, '-')[0])
AND
toInt(maxdate[1]) >= toInt(split(f1.date, '-')[1])
))
AND(
(
toInt(maxdate[0]) > toInt(split(f2.date, '-')[0])
)
OR
(
toInt(maxdate[0]) = toInt(split(f2.date, '-')[0])
AND
toInt(maxdate[1]) >= toInt(split(f2.date, '-')[1])
))
RETURN m;
这个代码块 运行 大约 20 分钟,最终似乎产生了接近我的目标的结果。这是它在浏览器中的样子:
(有350个节点)
首先,我承认这显然是一些非常糟糕的代码(无论是在美学还是性能方面)。其次,我注意到周边没有关联的节点。
我认为发生的事情是,一级关系的日期条件不合格,但二级关系的日期条件不合格,所以我最终得到了我不想的 'friend of a friend'被包括在内。
如何修改我的日期条件,以便在一次度边无效时消除这些独立节点?
如果有人有任何见解,我将不胜感激。 (不要太糊涂,但多亏了 SO 社区,我已经取得了相当快的进展,为此我很感激。)
首先不应该运行那么久,主要原因是您的节点上没有标签+索引。
首先添加那些:
CREATE CONSTRAINT ON (p:Person) ASSERT p.person_id is unique;
MATCH (n) where exists(n.person_id) SET n:Person;
如果你有时间 yyyy-mm-dd
无论如何(我希望至少如此)你可以直接比较它们:(有 2 位数字又名 01
)即 '2012-01-10' > '2011-08-31'
)
WITH '1962-01-01' AS maxdate
MATCH (n:Person)-[f1:FRIEND]-()-[f2:FRIEND]-(m:Person)
WHERE n.person_id='180' AND f1.date < maxdate and f2.date < maxdate
RETURN m;
您也可以使用缩写形式:(n:Person {person_id:'180'})
如果您想对路径中的关系有一个通用表达式,请在可变长度路径模式中使用变量 rels
(然后是一个集合):
WITH '1962-01-01' AS maxdate
MATCH (n:Person {person_id:'180'})-[rels:FRIEND*2]-(m:Person)
WHERE ALL(r in rels WHERE r.date < maxdate)
RETURN m;
你也可以使用rels(path)
WITH '1962-01-01' AS maxdate
MATCH path = (n:Person {person_id:'180'})-[:FRIEND*2]-(m:Person)
WHERE ALL(r in rels(path) WHERE r.date < maxdate)
RETURN m;
或者如果路径的关系是相互关联的:
WITH '1962-01-01' AS maxdate
MATCH (n:Person {person_id:'180'})-[rels:FRIEND*2]-(m:Person)
WHERE ALL(idx in range(0, size(rels)-2) WHERE (rels[idx]).date < maxdate AND (rels[idx]).date < (rels[idx+1]).date)
RETURN m;