neo4j cypher - 如何查找与节点列表有关系的所有节点

时间:2014-01-13 13:10:11

标签: neo4j

我有节点 - 名为“选项”。 “用户”选择这些选项。我需要一个像这样工作的chpher查询:

检索选择了作为列表提供的所有选项的用户。

MATCH (option:Option)<-[:CHOSE]-(user:User) WHERE  option.Key IN ['1','2','2'] Return user

此查询为我提供了选择选项(1),选项(2)和选项(3)的用户,并且还为我提供了仅选择选项(2)的用户。

我需要的只是选择所有选项的用户 - 选项(1),选项(2)和选项(3)。

4 个答案:

答案 0 :(得分:10)

对于所有密码解决方案(不知道它是否比Chris的回答更好,你必须进行测试和比较)你可以为每个用户收集option.Key并过滤掉那些不是列表中的每个值都有option.Key

MATCH (u:User)-[:CHOSE]->(opt:Option)
WITH u, collect(opt.Key) as optKeys
WHERE ALL (v IN {values} WHERE v IN optKeys)
RETURN u

或匹配其列表中的所有选项以及选择它们的用户,按用户收集这些选项,并将选项集的大小与列表的大小进行比较(如果您没有在列表中提供重复项)列出具有相同大小的选项集合的用户已选择所有选项)

MATCH (u:User)-[:CHOSE]->(opt:Option)
WHERE opt.Key IN {values}
WITH u, collect(opt) as opts
WHERE length(opts) = length({values}) // assuming {values} don't have duplicates
RETURN u

要么将结果限制为与{values}中指定了键值的所有选项相关联的用户,并且可以在不更改查询的情况下改变集合参数的长度。

答案 1 :(得分:2)

如果选项数量有限,您可以这样做:

MATCH 
    (user:User)-[:Chose]->(option1:Option),
    (user)-[:Chose]->(option2:Option),
    (user)-[:Chose]->(option3:Option)
WHERE
    option1.Key = '1'
    AND option2.Key = '2'
    AND option3.Key = '3'
RETURN
    user.Id

只返回具有所有3个选项的用户。

有点邋is,因为很明显你最终得到3行你有1,但我不知道如何使用IN关键字做你想做的事。

如果您正在编码,那么生成WHEREMATCH子句非常简单,但仍然 - 不理想。 :(

编辑 - 示例

原来这里有一些字符串操作(!),但你总是可以缓存位。重要的是 - 它正在使用Params,这将允许neo4j缓存查询并在每次调用时提供更快的响应。

public static IEnumerable<User> GetUser(IGraphClient gc)
{
    var query = GenerateCypher(gc, new[] {"1", "2", "3"});
    return query.Return(user => user.As<User>()).Results;
}


public static ICypherFluentQuery GenerateCypher(IGraphClient gc, string[] options)
{
    ICypherFluentQuery query = new CypherFluentQuery(gc);
    for(int i = 0; i < options.Length; i++)
        query = query.Match(string.Format("(user:User)-[:CHOSE]->(option{0}:Option)", i));

    for (int i = 0; i < options.Length; i++)
    {
        string paramName = string.Format("option{0}param", i);
        string whereString = string.Format("option{0}.Key = {{{1}}}", i, paramName);
        query = i == 0 ? query.Where(whereString) : query.AndWhere(whereString);
        query = query.WithParam(paramName, options[i]);
    }

    return query;
}

答案 2 :(得分:2)

MATCH (user:User)-[:CHOSE]->(option:Option) 
WHERE option.key IN ['1', '2', '3']
WITH user, COUNT(*) AS num_options_chosen
WHERE num_options_chosen = LENGTH(['1', '2', '3'])
RETURN user.name

这将仅返回与阵列中给定键具有所有选项关系的用户。 这假设用户和选项之间没有多个[:CHOSE]关系。如果用户可以通过单个选项拥有多个[:CHOSE]关系,则必须添加一些必要时的条件。

我使用以下数据集测试了上述查询:

CREATE (User1:User {name:'User 1'}),
       (User2:User {name:'User 2'}),
       (User3:User {name:'User 3'}),

       (Option1:Option {key:'1'}),
       (Option2:Option {key:'2'}),
       (Option3:Option {key:'3'}),
       (Option4:Option {key:'4'}),

       (User1)-[:CHOSE]->(Option1),
       (User1)-[:CHOSE]->(Option4),

       (User2)-[:CHOSE]->(Option2),
       (User2)-[:CHOSE]->(Option3),

       (User3)-[:CHOSE]->(Option1),
       (User3)-[:CHOSE]->(Option2),
       (User3)-[:CHOSE]->(Option3),
       (User3)-[:CHOSE]->(Option4)

我只得到'用户3'作为输出。

答案 3 :(得分:1)

对于较短的列表,您可以在WHERE子句中使用路径谓词:

MATCH (user:User)
WHERE (user)-[:CHOSE]->(:Option { Key: '1' })
AND   (user)-[:CHOSE]->(:Option { Key: '2' })
AND   (user)-[:CHOSE]->(:Option { Key: '3' })
RETURN user

优点:

  • 清除阅读
  • 易于为动态长度列表生成

缺点:

  • 对于每个不同的长度,您将有一个不同的查询,必须由Cypher解析和缓存。太多的动态查询会监视您的缓存命中率,查询编译工作上升,查询性能下降。