简体   繁体   English

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

[英]neo4j cypher - how to find all nodes that have a relationship to list of nodes

I have nodes- named "options". 我有节点 - 命名为“选项”。 "Users" choose these options. “用户”选择这些选项。 I need a chpher query that works like this: 我需要一个像这样工作的chpher查询:

retrieve users who had chosen all the options those are given as a list. 检索选择了作为列表给出的所有选项的用户。

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

This query gives me users who chose option(1), option(2) and option(3) and also gives me the user who only chose option(2). 此查询为我提供了选择选项(1),选项(2)和选项(3)的用户,并且还为我提供了仅选择选项(2)的用户。

What I need is only the users who chose all of them -option(1), option(2) and option(3). 我需要的只是选择所有选项的用户 - 选项(1),选项(2)和选项(3)。

For an all cypher solution (don't know if it's better than Chris' answer, you'll have to test and compare) you can collect the option.Key for each user and filter out those who don't have a option.Key for each value in your list 对于所有密码解决方案(不知道它是否比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

or match all the options whose keys are in your list and the users that chose them, collect those options per user and compare the size of the option collection to the size of your list (if you don't give duplicates in your list the user with an option collection of equal size has chosen all the options) 或匹配其列表中的所有选项以及选择它们的用户,按用户收集这些选项,并将选项集的大小与列表的大小进行比较(如果您没有在列表中给出重复项用户)使用相同大小的选项集合选择了所有选项)

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

Either should limit results to users connected with all the options whose key values are specified in {values} and you can vary the length of the collection parameter without changing the query. 要么将结果限制为与{values}中指定了键值的所有选项相关联的用户,并且可以在不更改查询的情况下更改集合参数的长度。

If the number of options is limited, you could do: 如果选项数量有限,您可以:

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

Which will only return the user with all 3 options. 这将只返回具有所有3个选项的用户。

It's a bit rubbishy as obviously you end up with 3 lines where you have 1, but I don't know how to do what you want using the IN keyword. 这有点像垃圾,显然你最终有3行,你有1,但我不知道如何使用IN关键字做你想做的事。

If you're coding against it, it's pretty simple to generate the WHERE and MATCH clause, but still - not ideal. 如果你正在对它进行编码,那么生成WHEREMATCH子句非常简单,但仍然 - 不理想。 :( :(

EDIT - Example 编辑 - 示例

Turns out there is some string manipulation going on here (!), but you can always cache bits. 事实证明这里有一些字符串操作(!),但你总是可以缓存位。 Importantly - it's using Params which would allow neo4j to cache the queries and supply faster responses with each call. 重要的是 - 它正在使用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;
}
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

This will only return users that have relationships with all the Options with the given keys in the array. 这将仅返回与阵列中给定键具有所有选项关系的用户。 This assumes there are not multiple [:CHOSE] relationships between users and options. 这假设用户和选项之间没有多个[:CHOSE]关系。 If it is possible for a user to have multiple [:CHOSE] relationships with a single option, you'll have to add some conditionals as necessary. 如果用户可能与单个选项有多个[:CHOSE]关系,则必须根据需要添加一些条件。

I tested the above query with the below dataset: 我用下面的数据集测试了上面的查询:

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)

And I get only 'User 3' as the output. 我只得到'用户3'作为输出。

For shorter lists, you can use path predicates in your WHERE clause: 对于较短的列表,可以在WHERE子句中使用路径谓词:

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

Advantages: 好处:

  • Clear to read 清楚阅读
  • Easy to generate for dynamic length lists 易于生成动态长度列表

Disadvantages: 缺点:

  • For each different length, you will have a different query that has to be parsed and cached by Cypher. 对于每个不同的长度,您将拥有一个不同的查询,必须由Cypher解析和缓存。 Too many dynamic queries will watch your cache hit rate go through the floor, query compilation work go up, and query performance go down. 太多的动态查询会监视您的缓存命中率,查询编译工作上升,查询性能下降。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM