Hi everyone,
I'm working on a Neo4j project where I need to find a path between two pieces of equipment (i.e. from Equipment 552 to Equipment 554) through alternating pipe and hose/clip connections. The challenge is that the connections must alternate between pipe and hose/clip; there can never be pipe-to-pipe or hose-to-hose (or hose-to-clip) connections.
I have a hardcoded query that works for a specific path, like this:
MATCH (a:Equipment {name: "552"})
-[r1:CAN_CONNECT_TO {type: "PIPE"}]->(p1:Port {name: "552-01"})
-[r3:CAN_CONNECT_TO {type: "HOSE"}]->(p3:Port {name: "551-AA09"})
-[r4:CAN_CONNECT_TO {type: "PIPE"}]->(p4:Port {name: "SPM-AA09"})
-[r5:CAN_CONNECT_TO {type: "HOSE"}]->(p5:Port {name: "SPM-AA12"})
-[r6:CAN_CONNECT_TO {type: "PIPE"}]->(p6:Port {name: "553-AA12"})
-[r7:CAN_CONNECT_TO {type: "CLIP"}]->(p7:Port {name: "554-OH"})
-[r8:CAN_CONNECT_TO {type: "PIPE"}]->(p8:Equipment {name: "554"})
RETURN a, p1, p3, p4, p5, p6, p7, p8
However, this approach doesn't scale well and becomes slower as the path length increases. I also tried a more generic query that allows for variable path lengths:
MATCH path = (source:Port {name: '552-01'})
-[l1:CAN_CONNECT_TO]->(:Port)
-[:CAN_CONNECT_TO {type: 'PIPE'}]->(:Port)
-[l2:CAN_CONNECT_TO]->(:Port)
-[:CAN_CONNECT_TO {type: 'PIPE'}]->(:Port)
-[l3:CAN_CONNECT_TO]->(:Port)
-[:CAN_CONNECT_TO {type: 'PIPE'}]->(:Port)
-[l4:CAN_CONNECT_TO]->(:Port)
-[:CAN_CONNECT_TO {type: 'PIPE'}]->(:Port)
-[l5:CAN_CONNECT_TO]->(target:Port {name: '554-OH'})
WHERE NOT 'PIPE' IN [l1, l2, l3, l4, l5]
RETURN source, [n IN nodes(path) | n.name] AS nodes, target
But this still has performance issues and doesn't seem to be the most efficient way to handle the problem.
I'm looking for a way to structure a Neo4j query, either with a projection, or a different query structure, to optimize this alternating pipe/hose connection problem. The goal is to find a path from Equipment 552 to Equipment 554 without specifying the details of the intermediate connections in the query itself.
I need to set these possible paths, and then use one of the shortest path algorithms to determine which one to select, so that I can provide a user with the top 10 fastest paths.
I started trying to dig into using path expansion, based off a separate post here a colleague of mine made a while ago, but am not getting this to match as I work through it.
MATCH (a:Equipment {name: "552"}), (b:Equipment {name: "554"})
CALL apoc.path.expandConfig(a, {
relationshipFilter: "CAN_CONNECT_TO{type:'PIPE'}, CAN_CONNECT_TO{type:'HOSE'}|CAN_CONNECT_TO{type:'CLIP'}",
endNodes: [b],
minLevel: 1,
maxLevel: 10,
bfs: true
})
YIELD path
RETURN path
This query returns nothing, even though I can confirm there is a valid path, based off my hardcoded query working fine
Can anyone suggest a more efficient and scalable approach to solve this problem? I'd really appreciate any insights or ideas you might have.
Thanks in advance for your help!
Best regards,
Keith