Cypher:限制选择节点返回链接的数量

3

我需要翻译一个看似简单的查询。

算法:

  1. Sort nodes by some value (desc):

    MATCH (n) WHERE has(n.II_VAL) WITH n, n.II_VAL as ShInflInd order by ShInflInd desc
    
  2. For each node, return its direct neighbors (ordered by a second value):

    MATCH (n)-[r]->(m) with n, m, m.VALUE as SubsOpRev order by SubsOpRev desc
    
挑战在于返回前100个n节点,对于每个节点只返回10个关系r(如果可能在一行中)。
编辑:
很抱歉我之前表述不够明确导致大家误解了。
具体来说,以下查询会给出排名靠前的节点:
MATCH (n) WHERE HAS(n.II_VAL)
WITH n, n.`II_VAL` AS ShInflInd ORDER BY ShInflInd DESC
RETURN n.NAME LIMIT 100;

+--------------------------------------+
| n.NAME                               |
+--------------------------------------+
| "PUBLIC"                             |
| "BARCLAYS PLC"                       |

现在,我可以将子查询添加到此处以添加链接:
MATCH (n) WHERE HAS(n.II_VAL)
WITH n, n.`II_VAL` AS ShInflInd ORDER BY ShInflInd DESC LIMIT 100
MATCH (n)-[r]->(m) WHERE HAS(m.VALUE)
WITH r, n, m, m.VALUE AS SubsOpRev
RETURN n.NAME, r.WEIGHT_MERGED, m.NAME, SubsOpRev LIMIT 10;

+----------------------------------------------------------------------------------------+
| n.NAME   | r.WEIGHT_MERGED    | m.NAME                                     | SubsOpRev |
+----------------------------------------------------------------------------------------+
| "PUBLIC" | 0.66               | "VBS MUTUAL BANK"                          | 2630      |
| "PUBLIC" | 0.2923             | "STRATCORP LIMITED"                        | 10842     |

现在我想要的是,在返回了10个与“PUBLIC”相关的链接后(可能按r.WEIGHT_MERGED或SubsOpRev进行排序),查询返回第二个节点(“BARCLAYS PLC”)及其10个链接,以此类推。
我已经尝试过:
MATCH (n) WHERE HAS(n.II_VAL)
WITH n, n.`II_VAL` AS ShInflInd ORDER BY ShInflInd DESC
MATCH (n)-[r]->(m) WHERE HAS(m.VALUE)
WITH r, n, m, m.VALUE AS SubsOpRev
RETURN collect([n.NAME, r.WEIGHT_MERGED, m.NAME, SubsOpRev])[0..10];

导致:
+------------------------------------------------------------------------------------------------------------------------------------------+
| collect([n.NAME, r.WEIGHT_MERGED, m.NAME, SubsOpRev])[0..3]                                                                              |
+------------------------------------------------------------------------------------------------------------------------------------------+
| [["PUBLIC",0.66,"VBS MUTUAL BANK",2630],["PUBLIC",0.2923,"STRATCORP LIMITED",10842], ...

这意味着我仍然只能使用“PUBLIC”。稍作修改查询会使情况变得更糟,因为它返回完全不同的数据。
MATCH (n) WHERE HAS(n.II_VAL)
WITH n, n.`II_VAL` AS ShInflInd ORDER BY ShInflInd DESC
MATCH (n)-[r]->(m) WHERE HAS(m.VALUE)
WITH r, n, m, m.VALUE AS SubsOpRev
RETURN n.NAME, collect([r.WEIGHT_MERGED, m.NAME, SubsOpRev])[0..10] LIMIT 3;

+------------------------------------------------------------------------------+
| n.NAME                | collect([r.WEIGHT_MERGED, m.NAME, SubsOpRev])[0..10] |
+------------------------------------------------------------------------------+
| "RS-INVEST AS"        | [[0.5,"VERUCO EIENDOM AS",100]]                      |
| "DBM"                 | [[0.1435,"CHELYABINSKOBLGAZ",6752]]                  |

理想情况下,查询应该返回类似于以下的结果:
| [["PUBLIC",0.66,"VBS MUTUAL BANK",2630],["PUBLIC",0.2923,"STRATCORP LIMITED",10842], ... |
| [["BARCLAYS PLC",x,"XYZ",y], ... |
5个回答

2

您只需要对查询进行限制并继续执行。为了提供一个可重复的示例,让我们切换到Neo4j附带的电影数据集。假设您想获取数据库中最旧的3部电影,然后是每部电影中最老的2位演员。

MATCH (m:Movie)
WITH m ORDER BY m.released LIMIT 3
MATCH (p:Person)-[:ACTED_IN]->(m)
WITH m, p ORDER BY p.born
WITH m, COLLECT(p.name)[0..2] AS oldest
RETURN m.title, oldest;

这将产生:
   | m.title                         | oldest                              
---+---------------------------------+--------------------------------------
 1 | Something's Gotta Give          | ['Jack Nicholson', 'Diane Keaton']
 2 | Top Gun                         | ['Tom Skerritt', 'Kelly McGillis']
 3 | One Flew Over the Cuckoo's Nest | ['Jack Nicholson', 'Danny DeVito']

所以你需要像这样:
MATCH (n) WHERE HAS(n.II_VAL)
WITH n ORDER BY n.II_VAL DESC LIMIT 100
MATCH (n)-[r]->(m) WHERE HAS(m.VALUE)
WITH n, r, m ORDER BY m.VALUE DESC
RETURN n.NAME, COLLECT([r.WEIGHT_MERGED, m.NAME, m.VALUE])[0..10];

这正是我所需的,谢谢。加上以下小改动后,我可以再次获得按n.II_VAL排序的最终列表:"... WITH n, n.II_VAL AS ii, r, m ORDER BY m.VALUE DESC RETURN n.NAME, ii, COLLECT([r.WEIGHT_MERGED, m.NAME, m.VALUE])[0..2] ORDER BY ii DESC;" - jnode

1

你能描述一下问题是什么吗?

最大的问题似乎是你没有在查询末尾加上RETURNWITH用于中间传递数据。此外,你实际上不需要提取值来进行排序。你可以这样做:

MATCH (n)
WHERE has(n.II_VAL)
RETURN n ORDER BY n.II_VAL DESC LIMIT 100

对于您的第二个查询:
MATCH (n)-[r]->(m)
RETURN n, m ORDER BY m.VALUE DESC LIMIT 100

编辑:抱歉,忘记了LIMIT


查询片段仅用作说明。请查看我原帖的编辑。 - jnode

1
您可以将节点数限制为100:

MATCH (n)
WHERE has(n.II_VAL)
WITH n, n.II_VAL AS ShInflInd
ORDER BY ShInflInd DESC 
LIMIT 100

你可以收集所有的SubsOpRev,然后返回你收集的片段。以下是一个示例代码(假定SubsOpRev是你想要的内容):
MATCH (n)-[r]->(m)
WITH n, m.VALUE AS SubsOpRev 
ORDER BY SubsOpRev DESC
RETURN n, collect(DISTINCT SubsOpRev)[1..10]

这将为您每行提供一个节点n和所有收集的SubsOpRev列表的切片。

我需要将这两个查询合并起来。请查看我原帖的修改。 - jnode
你可以把它们结合在一起。关于你的编辑:你必须首先进行ORDER,然后只有在关系或者想要返回的值上进行collect()。如果你希望再次拥有相同的节点顺序,你可能需要在你的RETURN中再次进行排序。 - Martin Preusse
是的,但我需要在从第一个排序搜索中获取的每个节点中添加一个子查询(检索10个链接)。我不知道如何以非平凡的方式组合这些查询... - jnode

0
要根据您的第一个查询获取前100个节点,您需要在排序后添加一个RETURN子句和一个LIMIT子句。
MATCH (n) 
WHERE has(n.II_VAL) 
RETURN n, n.II_VAL as ShInflInd 
order by ShInflInd desc 
LIMIT 100

对于第二个问题,您需要执行两个查询,并在客户端实现Foreach逻辑。因为您不能限制第一个查询结果只有100个节点,然后在同一查询中获取每个节点的10个相关节点。


(Note: Since Chinese is a character-based language, the translated text may appear longer than the original.)

我无法处理循环。请查看我原帖的编辑。 - jnode

0

我认为你想要的是在一个查询中返回两个结果集。为了实现这一点,我认为最好的方法是在WITH语句中使用collect函数,这将给你一个行,然后将该值与其他数据的collect一起RETURN。类似于以下内容:

MATCH (n) WHERE HAS(n.II_VAL)
WITH collect([n, n.`II_VAL`])[0..100] AS set1 ORDER BY n.`II_VAL` DESC
MATCH (n)-[r]->(m) WHERE HAS(m.VALUE)
RETURN set1, collect([n.NAME, r.WEIGHT_MERGED, m.NAME])[1..10] ORDER BY r.WEIGHT_MERGED

我加入了 ORDER BY r.WEIGHT_MERGED 作为按值排序的示例。
如果你想让数据更结构化,也可以像这样收集对象映射而不是数组:
MATCH (n) WHERE HAS(n.II_VAL)
WITH collect({n: n, II_VAL: n.`II_VAL`})[0..100] AS set1 ORDER BY n.`II_VAL` DESC
MATCH (n)-[r]->(m) WHERE HAS(m.VALUE)
RETURN set1, collect({n_name: n.NAME, weight_merged: r.WEIGHT_MERGED, m_name: m.NAME})[1..10] ORDER BY r.WEIGHT_MERGED

好的,关闭 :) 但是,在第二行中查询不知道“n”(“n未定义”)(ORDER BY n.II_VAL)。如果我在“WITH”之后添加它(WITH n,collect({n ...)),我会失去原始的按n.II_VAL排序。但它返回的结构看起来像我正在寻找的... - jnode
你没有在WITH子句中指定绑定变量 n,因此失去了它的限制作用。在第3行代码中,你只是匹配所有的节点。 - Nicole White

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接