如何用Cypher查询递归获取Neo4j中规则触发的所有规则链
规则与变量依赖图的递归查询实现
图结构定义
图中包含两种节点类型:
- Rule:包含
name属性 - Variable:包含
name属性
存在两种关系:
Rule-[:depends_on]->Variable:规则依赖某个变量Rule-[:targets]->Variable:规则作用于某个变量
创建示例图的Cypher查询
CREATE (rule1:Rule {name:'rule_1'}), (rule2:Rule {name:'rule_2'}), (rule3:Rule {name:'rule_3'}), (rule4:Rule {name:'rule_4'}), (variable1:Variable {name:'variable_1'}), (variable2:Variable {name:'variable_2'}), (variable3:Variable {name:'variable_3'}), (variable4:Variable {name:'variable_4'}), (variable5:Variable {name:'variable_5'}), (variable6:Variable {name:'variable_6'}), (variable7:Variable {name:'variable_7'}), (rule1)-[:targets]->(variable2), (rule1)-[:targets]->(variable3), (rule2)-[:targets]->(variable4), (rule2)-[:targets]->(variable5), (rule3)-[:targets]->(variable6), (rule3)-[:targets]->(variable7), (rule4)-[:targets]->(variable3), (rule1)-[:depends_on]->(variable1), (rule2)-[:depends_on]->(variable2), (rule3)-[:depends_on]->(variable3), (rule4)-[:depends_on]->(variable4)
查询需求
给定规则名称,编写Cypher查询递归获取该规则可触发的所有规则链。例如:
- 触发
rule_1会触发rule_2(rule_1作用于variable_2,而variable_2是rule_2的依赖)和rule_3(rule_1作用于variable_3,variable_3是rule_3的依赖) - 触发
rule_2会触发rule_4(rule_2作用于variable_4,variable_4是rule_4的依赖) - 触发
rule_4会触发rule_3(rule_4作用于variable_3,variable_3是rule_3的依赖)
目标规则链示例
rule_1 -> rule_2 -> rule_4 -> rule_3 rule_1 -> rule_3
实现查询
基于APOC库的灵活递归查询
以下查询借助APOC库实现任意深度的递归遍历,适合链路长度不确定的场景:
MATCH (startRule:Rule {name: $ruleName}) CALL apoc.path.expandConfig(startRule, { relationshipFilter: 'targets>|<depends_on', labelFilter: '>Rule', uniqueness: 'NODE_PATH', beginSequenceAtStart: false }) YIELD path WITH nodes(path) as chainNodes UNWIND [startRule] + chainNodes as fullChainNodes WITH DISTINCT fullChainNodes WHERE size(fullChainNodes) > 1 RETURN reduce(chainStr = '', rule in fullChainNodes | chainStr + rule.name + ' -> ')[:-4] as ruleChain ORDER BY size(fullChainNodes) DESC
说明
- 使用
apoc.path.expandConfig递归遍历起始规则触发的所有后续规则节点,避免重复路径 - 将起始规则与遍历得到的节点合并为完整链路,去除长度为1的无效链路
- 通过字符串拼接生成规则链格式,去除末尾多余的
->
原生Cypher递归查询(无需APOC)
若无法使用APOC库,可通过原生递归语法实现:
MATCH (startRule:Rule {name: $ruleName}) CALL { WITH startRule MATCH path=(startRule)-[:targets]->(:Variable)<-[:depends_on]-(nextRule:Rule) RETURN [startRule, nextRule] as chain UNION ALL WITH startRule MATCH path=(startRule)-[:targets]->(:Variable)<-[:depends_on]-(r1:Rule)-[:targets]->(:Variable)<-[:depends_on]-(r2:Rule) RETURN [startRule, r1, r2] as chain UNION ALL WITH startRule MATCH path=(startRule)-[:targets]->(:Variable)<-[:depends_on]-(r1:Rule)-[:targets]->(:Variable)<-[:depends_on]-(r2:Rule)-[:targets]->(:Variable)<-[:depends_on]-(r3:Rule) RETURN [startRule, r1, r2, r3] as chain } WITH DISTINCT chain RETURN reduce(chainStr = '', rule in chain | chainStr + rule.name + ' -> ')[:-4] as ruleChain ORDER BY size(chain) DESC
说明
通过多层匹配覆盖不同深度的链路,适合链路深度固定的场景,若深度不确定需手动扩展匹配层级。
内容的提问来源于stack exchange,提问作者Higsn
相关产品推荐
相关产品推荐

