Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/neo4j/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Neo4j 查找多个节点之间所有关系的密码查询_Neo4j_Cypher_Neo4j Apoc - Fatal编程技术网

Neo4j 查找多个节点之间所有关系的密码查询

Neo4j 查找多个节点之间所有关系的密码查询,neo4j,cypher,neo4j-apoc,Neo4j,Cypher,Neo4j Apoc,我有一个复杂的图表,如下图所示: 这里每个关系都有一个类型值。我需要编写一个密码查询来查找给定节点集(两个或多个)之间的所有关系(及其类型值)。可以按任意顺序输入节点,如x64->Linux->Oracle或Oracle->Linux->10.2 编辑 我期待这样的输出。具有链接节点的关系名称的所有节点组合 输入:x64->Linux->Oracle 输入:Linux->64->Oracle->12c 数据 可以从以下位置访问数据: 编辑 输入x64->Linux->Oracle的新输出格

我有一个复杂的图表,如下图所示:

这里每个关系都有一个类型值。我需要编写一个密码查询来查找给定节点集(两个或多个)之间的所有关系(及其类型值)。可以按任意顺序输入节点,如x64->Linux->Oracle或Oracle->Linux->10.2

编辑

我期待这样的输出。具有链接节点的关系名称的所有节点组合

  • 输入:x64->Linux->Oracle
  • 输入:Linux->64->Oracle->12c
  • 数据

    可以从以下位置访问数据:

    编辑 输入x64->Linux->Oracle的新输出格式

    备注 在我呈现解决方案和结果之前,我想建议修改您的模型

    • 如果尚未这样做,则以标签的形式引入不同的节点类型(
      架构
      软件
      软件版本
      ,等等),这将使您的数据检索更加容易
    • 根据源数据库
      domain\u database\n
      的数量以及由此产生的并行
      支持关系,可以更清晰、更高效地使用。在这种情况下,更多的关系是多余的
    • Neo4j不关注关系属性的搜索和过滤。将这些属性建模为节点或节点的属性会显著提高性能,特别是对于大型图
    • 考虑一下这个问题
    您的图表/初始情况 为了便于进一步回答和解决问题,我注意到我的图表创建声明:

    CREATE
      (pc:UntypedNode {name: 'PC'})-[:SUPPORTS {type: 'domain_database_1'}]->(tenDotTwo:UntypedNode {name:'10.2'}),
      (pc)-[:SUPPORTS {type: 'domain_database_2'}]->(tenDotTwo),
      (pc)-[:SUPPORTS {type: 'domain_database_3'}]->(tenDotTwo),
      (pc)-[:SUPPORTS {type: 'domain_database_4'}]->(tenDotTwo),
      (pc)-[:SUPPORTS {type: 'domain_database_5'}]->(tenDotTwo),
      (pc)-[:SUPPORTS {type: 'domain_database_6'}]->(tenDotTwo),
      (pc)-[:SUPPORTS {type: 'domain_database_7'}]->(tenDotTwo),
      (tenDotTwo)-[:SUPPORTS {type: 'domain_database_1'}]->(linux:UntypedNode {name:'Linux'}),
      (tenDotTwo)-[:SUPPORTS {type: 'domain_database_2'}]->(linux),
      (tenDotTwo)-[:SUPPORTS {type: 'domain_database_3'}]->(linux),
      (tenDotTwo)-[:SUPPORTS {type: 'domain_database_4'}]->(linux),
      (tenDotTwo)-[:SUPPORTS {type: 'domain_database_5'}]->(linux),
      (tenDotTwo)-[:SUPPORTS {type: 'domain_database_6'}]->(linux),
      (tenDotTwo)-[:SUPPORTS {type: 'domain_database_7'}]->(linux),
      (linux)-[:SUPPORTS {type: 'domain_database_1'}]->(sevenDotZero:UntypedNode {name:'7.0'}),
      (linux)-[:SUPPORTS {type: 'domain_database_2'}]->(sevenDotZero),
      (linux)-[:SUPPORTS {type: 'domain_database_3'}]->(sevenDotZero),
      (linux)-[:SUPPORTS {type: 'domain_database_4'}]->(sevenDotZero),
      (linux)-[:SUPPORTS {type: 'domain_database_5'}]->(sevenDotZero),
      (linux)-[:SUPPORTS {type: 'domain_database_6'}]->(sevenDotZero),
      (linux)-[:SUPPORTS {type: 'domain_database_7'}]->(sevenDotZero),
      (sevenDotZero)-[:SUPPORTS {type: 'domain_database_1'}]->(x64:UntypedNode {name:'x64'}),
      (sevenDotZero)-[:SUPPORTS {type: 'domain_database_2'}]->(x64),
      (sevenDotZero)-[:SUPPORTS {type: 'domain_database_3'}]->(x64),
      (sevenDotZero)-[:SUPPORTS {type: 'domain_database_4'}]->(x64),
      (sevenDotZero)-[:SUPPORTS {type: 'domain_database_5'}]->(x64),
      (sevenDotZero)-[:SUPPORTS {type: 'domain_database_6'}]->(x64),
      (sevenDotZero)-[:SUPPORTS {type: 'domain_database_7'}]->(x64),
      (x64)-[:SUPPORTS {type: 'domain_database_1'}]->(sixtyFour:UntypedNode {name:'64'}),
      (x64)-[:SUPPORTS {type: 'domain_database_2'}]->(sixtyFour),
      (x64)-[:SUPPORTS {type: 'domain_database_3'}]->(sixtyFour),
      (x64)-[:SUPPORTS {type: 'domain_database_4'}]->(sixtyFour),
      (x64)-[:SUPPORTS {type: 'domain_database_5'}]->(sixtyFour),
      (x64)-[:SUPPORTS {type: 'domain_database_6'}]->(sixtyFour),
      (x64)-[:SUPPORTS {type: 'domain_database_7'}]->(sixtyFour),
      (sixtyFour)-[:SUPPORTS {type: 'domain_database_1'}]->(sqlServer:UntypedNode {name:'SQL Server'}),
      (sixtyFour)-[:SUPPORTS {type: 'domain_database_2'}]->(sqlServer),
      (sixtyFour)-[:SUPPORTS {type: 'domain_database_3'}]->(sqlServer),
      (sqlServer)-[:SUPPORTS {type: 'domain_database_1'}]->(year2014:UntypedNode {name:'2014'}),
      (sqlServer)-[:SUPPORTS {type: 'domain_database_2'}]->(year2016:UntypedNode {name:'2016'}),
      (sqlServer)-[:SUPPORTS {type: 'domain_database_3'}]->(year2017:UntypedNode {name:'2017'}),
      (year2014)-[:SUPPORTS {type: 'domain_database_1'}]->(s:UntypedNode {name:'S'}),
      (year2016)-[:SUPPORTS {type: 'domain_database_2'}]->(s),
      (year2017)-[:SUPPORTS {type: 'domain_database_3'}]->(s),
      (sixtyFour)-[:SUPPORTS {type: 'domain_database_4'}]->(oracle:UntypedNode {name:'Oracle'}),
      (sixtyFour)-[:SUPPORTS {type: 'domain_database_5'}]->(oracle),
      (sixtyFour)-[:SUPPORTS {type: 'domain_database_6'}]->(oracle),
      (sixtyFour)-[:SUPPORTS {type: 'domain_database_7'}]->(oracle),
      (oracle)-[:SUPPORTS {type: 'domain_database_4'}]->(release12c:UntypedNode {name:'12c'}),
      (oracle)-[:SUPPORTS {type: 'domain_database_5'}]->(release12gr2:UntypedNode {name:'12gR2'}),
      (oracle)-[:SUPPORTS {type: 'domain_database_6'}]->(release12cr:UntypedNode {name:'12cR'}),
      (oracle)-[:SUPPORTS {type: 'domain_database_7'}]->(release12cr1:UntypedNode {name:'12cR1'}),
      (release12c)-[:SUPPORTS {type: 'domain_database_4'}]->(s),
      (release12gr2)-[:SUPPORTS {type: 'domain_database_5'}]->(s),
      (release12cr)-[:SUPPORTS {type: 'domain_database_6'}]->(s),
      (release12cr1)-[:SUPPORTS {type: 'domain_database_7'}]->(s);
    
    解决方案

    备注 在我呈现解决方案和结果之前,我想建议修改您的模型

    • 如果尚未这样做,则以标签的形式引入不同的节点类型(
      架构
      软件
      软件版本
      ,等等),这将使您的数据检索更加容易
    • 根据源数据库
      domain\u database\n
      的数量以及由此产生的并行
      支持关系,可以更清晰、更高效地使用。在这种情况下,更多的关系是多余的
    • Neo4j不关注关系属性的搜索和过滤。将这些属性建模为节点或节点的属性会显著提高性能,特别是对于大型图
    • 考虑一下这个问题
    您的图表/初始情况 为了便于进一步回答和解决问题,我注意到我的图表创建声明:

    CREATE
      (pc:UntypedNode {name: 'PC'})-[:SUPPORTS {type: 'domain_database_1'}]->(tenDotTwo:UntypedNode {name:'10.2'}),
      (pc)-[:SUPPORTS {type: 'domain_database_2'}]->(tenDotTwo),
      (pc)-[:SUPPORTS {type: 'domain_database_3'}]->(tenDotTwo),
      (pc)-[:SUPPORTS {type: 'domain_database_4'}]->(tenDotTwo),
      (pc)-[:SUPPORTS {type: 'domain_database_5'}]->(tenDotTwo),
      (pc)-[:SUPPORTS {type: 'domain_database_6'}]->(tenDotTwo),
      (pc)-[:SUPPORTS {type: 'domain_database_7'}]->(tenDotTwo),
      (tenDotTwo)-[:SUPPORTS {type: 'domain_database_1'}]->(linux:UntypedNode {name:'Linux'}),
      (tenDotTwo)-[:SUPPORTS {type: 'domain_database_2'}]->(linux),
      (tenDotTwo)-[:SUPPORTS {type: 'domain_database_3'}]->(linux),
      (tenDotTwo)-[:SUPPORTS {type: 'domain_database_4'}]->(linux),
      (tenDotTwo)-[:SUPPORTS {type: 'domain_database_5'}]->(linux),
      (tenDotTwo)-[:SUPPORTS {type: 'domain_database_6'}]->(linux),
      (tenDotTwo)-[:SUPPORTS {type: 'domain_database_7'}]->(linux),
      (linux)-[:SUPPORTS {type: 'domain_database_1'}]->(sevenDotZero:UntypedNode {name:'7.0'}),
      (linux)-[:SUPPORTS {type: 'domain_database_2'}]->(sevenDotZero),
      (linux)-[:SUPPORTS {type: 'domain_database_3'}]->(sevenDotZero),
      (linux)-[:SUPPORTS {type: 'domain_database_4'}]->(sevenDotZero),
      (linux)-[:SUPPORTS {type: 'domain_database_5'}]->(sevenDotZero),
      (linux)-[:SUPPORTS {type: 'domain_database_6'}]->(sevenDotZero),
      (linux)-[:SUPPORTS {type: 'domain_database_7'}]->(sevenDotZero),
      (sevenDotZero)-[:SUPPORTS {type: 'domain_database_1'}]->(x64:UntypedNode {name:'x64'}),
      (sevenDotZero)-[:SUPPORTS {type: 'domain_database_2'}]->(x64),
      (sevenDotZero)-[:SUPPORTS {type: 'domain_database_3'}]->(x64),
      (sevenDotZero)-[:SUPPORTS {type: 'domain_database_4'}]->(x64),
      (sevenDotZero)-[:SUPPORTS {type: 'domain_database_5'}]->(x64),
      (sevenDotZero)-[:SUPPORTS {type: 'domain_database_6'}]->(x64),
      (sevenDotZero)-[:SUPPORTS {type: 'domain_database_7'}]->(x64),
      (x64)-[:SUPPORTS {type: 'domain_database_1'}]->(sixtyFour:UntypedNode {name:'64'}),
      (x64)-[:SUPPORTS {type: 'domain_database_2'}]->(sixtyFour),
      (x64)-[:SUPPORTS {type: 'domain_database_3'}]->(sixtyFour),
      (x64)-[:SUPPORTS {type: 'domain_database_4'}]->(sixtyFour),
      (x64)-[:SUPPORTS {type: 'domain_database_5'}]->(sixtyFour),
      (x64)-[:SUPPORTS {type: 'domain_database_6'}]->(sixtyFour),
      (x64)-[:SUPPORTS {type: 'domain_database_7'}]->(sixtyFour),
      (sixtyFour)-[:SUPPORTS {type: 'domain_database_1'}]->(sqlServer:UntypedNode {name:'SQL Server'}),
      (sixtyFour)-[:SUPPORTS {type: 'domain_database_2'}]->(sqlServer),
      (sixtyFour)-[:SUPPORTS {type: 'domain_database_3'}]->(sqlServer),
      (sqlServer)-[:SUPPORTS {type: 'domain_database_1'}]->(year2014:UntypedNode {name:'2014'}),
      (sqlServer)-[:SUPPORTS {type: 'domain_database_2'}]->(year2016:UntypedNode {name:'2016'}),
      (sqlServer)-[:SUPPORTS {type: 'domain_database_3'}]->(year2017:UntypedNode {name:'2017'}),
      (year2014)-[:SUPPORTS {type: 'domain_database_1'}]->(s:UntypedNode {name:'S'}),
      (year2016)-[:SUPPORTS {type: 'domain_database_2'}]->(s),
      (year2017)-[:SUPPORTS {type: 'domain_database_3'}]->(s),
      (sixtyFour)-[:SUPPORTS {type: 'domain_database_4'}]->(oracle:UntypedNode {name:'Oracle'}),
      (sixtyFour)-[:SUPPORTS {type: 'domain_database_5'}]->(oracle),
      (sixtyFour)-[:SUPPORTS {type: 'domain_database_6'}]->(oracle),
      (sixtyFour)-[:SUPPORTS {type: 'domain_database_7'}]->(oracle),
      (oracle)-[:SUPPORTS {type: 'domain_database_4'}]->(release12c:UntypedNode {name:'12c'}),
      (oracle)-[:SUPPORTS {type: 'domain_database_5'}]->(release12gr2:UntypedNode {name:'12gR2'}),
      (oracle)-[:SUPPORTS {type: 'domain_database_6'}]->(release12cr:UntypedNode {name:'12cR'}),
      (oracle)-[:SUPPORTS {type: 'domain_database_7'}]->(release12cr1:UntypedNode {name:'12cR1'}),
      (release12c)-[:SUPPORTS {type: 'domain_database_4'}]->(s),
      (release12gr2)-[:SUPPORTS {type: 'domain_database_5'}]->(s),
      (release12cr)-[:SUPPORTS {type: 'domain_database_6'}]->(s),
      (release12cr1)-[:SUPPORTS {type: 'domain_database_7'}]->(s);
    
    解决方案

    如果您只查找直接连接集合中每对节点的关系(而不是查找集合中每对节点之间的所有多跳路径),APOC过程正好适用于此用例:

    ...
    // assume `nodes` is the collection of nodes
    CALL apoc.algo.cover(nodes) YIELD rel
    RETURN rel
    
    编辑

    正如我在评论中提到的,您对需求的更改极大地改变了问题的性质

    您似乎希望获得完整的路径结果(定向),包括不在输入中的节点,并且希望确保路径中的所有关系都具有相同的
    type
    属性

    MATCH (entity:Entity) 
    WHERE entity.key in ['Product','Version','BinaryType'] AND entity.value in ['pc','10.2','64']
    WITH collect(entity) as nodes
    UNWIND nodes as node
    WITH nodes, node, [()-[r]->(node) | {type:r.type, level:r.level}] as inputs, [(node)-[r]->() | {type:r.type, level:r.level}] as outputs
    WITH nodes, collect({node:node, inputs:apoc.coll.toSet(inputs), outputs:apoc.coll.toSet(outputs)}) as nodeData
    UNWIND nodeData as start
    UNWIND nodeData as end
    WITH nodes, start, end, nodeData
    WHERE start <> end
    WITH nodes, start, end, apoc.coll.subtract(nodeData, [start, end]) as theRest
    WITH nodes, start.node as start, end.node as end, apoc.coll.intersection(start.outputs, end.inputs) as possibles, [data in theRest | apoc.coll.intersection(data.inputs, data.outputs)] as others
    WITH nodes, start, end, reduce(possibles = possibles, data in others | apoc.coll.intersection(possibles, data)) as possibles
    WHERE size(possibles) > 0
    UNWIND possibles as typeAndLevel
    MATCH path = (start)-[*]->(end)
    WHERE all(rel in relationships(path) WHERE rel.type = typeAndLevel.type AND rel.level = typeAndLevel.level) 
     AND length(path) >= size(nodes) - 1 
     AND all(node in nodes WHERE node in nodes(path))
    RETURN nodes(path) as pathNodes, typeAndLevel.type as type, typeAndLevel.level as level
    
    这需要我们找到这些节点的顺序,以便我们能够识别它们之间的路径。虽然我们可以找到输入节点的所有可能排列(对于路径的遍历顺序),但我认为我们可以只找到起始节点和结束节点的2排列(通过两次展开集合并删除起始节点和结束节点相同的行)。我们将首先查找所有输入和输出关系类型,以便使用一些集合操作(开始节点的输出类型与结束节点的输入类型相交,结束节点的输入类型与其他节点的所有(相交)输入和输出类型相交)查找可以连接所有节点的关系上可能存在的潜在类型

    通过此筛选后的剩余行,我们可以匹配到可以连接所有这些节点的可变长度路径,只使用提供的类型,以便每个路径只遍历具有单个类型的关系。然后,我们过滤以确保所有输入节点都在路径中

    MATCH (entity:Entity) 
    WHERE entity.key in ['Product','Version','BinaryType'] AND entity.value in ['pc','10.2','64']
    WITH collect(entity) as nodes
    UNWIND nodes as node
    WITH nodes, node, [()-[r]->(node) | {type:r.type, level:r.level}] as inputs, [(node)-[r]->() | {type:r.type, level:r.level}] as outputs
    WITH nodes, collect({node:node, inputs:apoc.coll.toSet(inputs), outputs:apoc.coll.toSet(outputs)}) as nodeData
    UNWIND nodeData as start
    UNWIND nodeData as end
    WITH nodes, start, end, nodeData
    WHERE start <> end
    WITH nodes, start, end, apoc.coll.subtract(nodeData, [start, end]) as theRest
    WITH nodes, start.node as start, end.node as end, apoc.coll.intersection(start.outputs, end.inputs) as possibles, [data in theRest | apoc.coll.intersection(data.inputs, data.outputs)] as others
    WITH nodes, start, end, reduce(possibles = possibles, data in others | apoc.coll.intersection(possibles, data)) as possibles
    WHERE size(possibles) > 0
    UNWIND possibles as typeAndLevel
    MATCH path = (start)-[*]->(end)
    WHERE all(rel in relationships(path) WHERE rel.type = typeAndLevel.type AND rel.level = typeAndLevel.level) 
     AND length(path) >= size(nodes) - 1 
     AND all(node in nodes WHERE node in nodes(path))
    RETURN nodes(path) as pathNodes, typeAndLevel.type as type, typeAndLevel.level as level
    
    我们假设节点的类型为:Node,属性为'name'

    MATCH (entity:Entity) 
    WHERE entity.key in ['Product','Version','BinaryType'] AND entity.value in ['pc','10.2','64']
    WITH collect(entity) as nodes
    UNWIND nodes as node
    WITH nodes, node, [()-[r]->(node) | r.type] as inputTypes, [(node)-[r]->() | r.type] as outputTypes
    WITH nodes, node, apoc.coll.toSet(inputTypes) as inputTypes, apoc.coll.toSet(outputTypes) as outputTypes
    WITH nodes, collect({node:node, inputTypes:inputTypes, outputTypes:outputTypes}) as nodeData
    UNWIND nodeData as start
    UNWIND nodeData as end
    WITH nodes, start, end, nodeData
    WHERE start <> end
    WITH nodes, start, end, apoc.coll.subtract(nodeData, [start, end]) as theRest
    WITH nodes, start.node as start, end.node as end, apoc.coll.intersection(start.outputTypes, end.inputTypes) as possibleTypes, [data in theRest | apoc.coll.intersection(data.inputTypes, data.outputTypes)] as otherTypes
    WITH nodes, start, end, reduce(possibleTypes = possibleTypes, types in otherTypes | apoc.coll.intersection(possibleTypes, types)) as possibleTypes
    WHERE size(possibleTypes) > 0
    UNWIND possibleTypes as type
    MATCH path = (start)-[*]->(end)
    WHERE all(rel in relationships(path) WHERE rel.type = type) 
     AND length(path) >= size(nodes) - 1 
     AND all(node in nodes WHERE node in nodes(path))
    RETURN nodes(path) as pathNodes, type
    
    匹配(实体:实体)
    其中,['Product'、'Version'、'BinaryType']中的entity.key和['pc'、'10.2'、'64'中的entity.value
    以collect(实体)作为节点
    将节点作为节点展开
    使用节点,[()-[r]->(节点)| r.type]作为输入类型,[(节点)-[r]->()| r.type]作为输出类型
    将nodes、node、apoc.coll.toSet(输入类型)作为输入类型,apoc.coll.toSet(输出类型)作为输出类型
    对于节点,收集({node:node,inputTypes:inputTypes,outputTypes:outputTypes})作为节点数据
    展开节点数据作为开始
    将节点数据作为结束展开
    使用节点、开始、结束、节点数据
    从哪里开始结束
    使用节点,开始,结束,apoc.coll.subtract(nodeData,[start,end])作为测试
    使用节点,start.node作为开始,end.node作为结束,apoc.coll.intersection(start.outputTypes,end.inputTypes)作为可能类型,[rest | apoc.coll.intersection中的数据(data.inputTypes,data.outputTypes)]作为其他类型
    将节点、开始、结束、减少(possibleTypes=possibleTypes,otherTypes中的类型| apoc.coll.intersection(possibleTypes,types))作为possibleTypes
    其中大小(可能类型)>0
    将可能类型作为类型展开
    匹配路径=(开始)-[*]->(结束)
    WHERE all(关系中的rel(路径),其中rel.type=type)
    和长度(路径)>=大小(节点)-1
    和全部(节点中的节点,其中节点中的节点(路径))
    将节点(路径)返回为pathNodes,键入
    
    要同时处理类型和级别,我们需要在查询的前面收集它们,因此我们不只是处理类型,而是处理类型和级别的映射。这确实使查询变得更加复杂