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

时间:2015-11-25 10:35:46

标签: neo4j cypher

我在一个看似简单的查询中失败了。

ALGO:

  1. 按某个值(desc)对节点排序:

    MATCH (n) WHERE has(n.II_VAL) WITH n, n.II_VAL as ShInflInd order by ShInflInd desc
    
  2. 对于每个节点,返回其直接邻居(按第二个值排序):

    MATCH (n)-[r]->(m) with n, m, m.VALUE as SubsOpRev order by SubsOpRev desc
    
  3. 挑战是返回前100个节点,并且每个节点只返回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     |
    

    现在我想要的是,在返回“PUBLIC”的10个链接(可能按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 个答案:

答案 0 :(得分:2)

您只需要限制然后继续查询。为了提供可重现的示例,让我们切换到Neo4j附带的电影数据集。让我们假设您想要抓住数据库中最古老的3部电影,然后再拍摄每部电影中最老的两部演员。

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];

答案 1 :(得分:1)

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

最大的问题似乎是您没有使用RETURN完成查询。 WITH用于中间传递数据。此外,您实际上并不需要提取值来对其进行排序。你可以这样做:

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

答案 2 :(得分:1)

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

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

您可以收集所有SubsOpRev,然后RETURN一部分收藏品。这一行(我假设SubsOpRev是你想要的):

MATCH (n)-[r]->(m)
WITH n, m.VALUE AS SubsOpRev 
ORDER BY SubsOpRev DESC
RETURN n, collect(DISTINCT SubsOpRev)[1..10]

这将为您提供每行一个节点n以及所有收集的SubsOpRev列表的一部分。

答案 3 :(得分: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个相关节点。

答案 4 :(得分:0)

我认为您所说的是您希望在一个查询中返回两组结果。要做到这一点,我认为最好的办法是collect中的WITH,它只会给你一行,然后RETURN这个值和collect其他数据。类似的东西:

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