Filtering out specific relationships in a path / Aggregation of relationship properties

Hi Neo4j community,

I'm new to Neo4j. I'm working on a use case to assign a set of Location points as nodes, and have then created a relationship between the locations called DELIVER_TO. I have also created relationship properties called ["congestion", "fuel", "distance", "mdq"].

  1. In the screen shot below, I have Locations from E -> J that can go two different paths [E, F, H, I, G, J] or [E, F, G, J]. The only difference is the relationship property from F->G has congestion of 1. Where all the other paths have congestion set to 0. On line 3 of my WHERE clause, I am trying to filter out the path with the congestion point, but it's still showing up. Any ideas what I'm doing wrong with my WHERE statment?

  1. Can I aggregate and SET a relationship property value for a path? For example, If the distance is set to 200 for each of the paths [E->F->G->J]. Can I create a new relationship property called totalFuel, set the totalFuel for [ E->F] to 200, then path [F->G] set to 200+200=400, and finally the path [G->J] set to 200+200+200=600.
CREATE (E:Location {id:5, name:'E',publicMeterId:'5'})
CREATE (F:Location {id:6, name:'F',publicMeterId:'6'})
CREATE (G:Location {id:7, name:'G',publicMeterId:'7'})
CREATE (H:Location {id:8, name:'H',publicMeterId:'8'})
CREATE (I:Location {id:9, name:'I',publicMeterId:'9'})
CREATE (J:Location {id:10, name:'J',publicMeterId:'10'})

CREATE (E)-[:DELIVER_TO {fuel: 2, congestion: 0, mdq: 1000, distance: 200}]->(F)
CREATE (F)-[:DELIVER_TO {fuel: 2, congestion: 1, mdq: 1000, distance: 200}]->(G)
CREATE (F)-[:DELIVER_TO {fuel: 2, congestion: 0, mdq: 1000, distance: 200}]->(H)
CREATE (H)-[:DELIVER_TO {fuel: 2, congestion: 0, mdq: 1000, distance: 200}]->(I)
CREATE (I)-[:DELIVER_TO {fuel: 2, congestion: 0, mdq: 1000, distance: 200}]->(G)
CREATE (G)-[:DELIVER_TO {fuel: 2, congestion: 0, mdq: 1000, distance: 200}]->(J)
CREATE (J)-[:DELIVER_TO {fuel: 2, congestion: 0, mdq: 1000, distance: 200}]->(N)

Any help is always greatly appreciated.

Thank you,
James

You ‘where’ condition looks correct. Are you sure you got two paths back? Click on the table or text view to verify there are actually two rows. If so, what is happening is neo4j desktop is showing all the relationships between the displayed nodes. That would include the relationship between F and G. This is the default behavior. You can turn it off in the settings.

You can use the reduce operation on the list of path relationships to achieve what you want to do. You have to do it separately for each sub path along the path. I can post a solution later when I get by my computer.

1 Like

Gary, thank you so much for the quick response. I was able to successfully update the settings and see the node path that I was hoping to see!

I look forward to seeing your solution for the other question when you have a minute and get back in front of your computer.

Question 3 - Weighted property for best path variations
I wanted to test out one more scenario: Is there a way to find various different paths based on the different relationship properties? Is there also a way to weight one relationship property higher than another in importance? Using the example above with the two different paths [E, F, H, I, G, J] or [E, F, G, J]. If the distance was the most important, then I might want the path [E, F, G, J], However, if Congestion was more of a factor than, I might need to use the path [E, F, H, I, G, J].

I have seen some examples in the forum with people using a procedure called allShortestPaths and another example where someone looks to be creating a counter based on the relationship property. I'm can't find an example showing what is best practice or correct.

I realize this is a different question. Please advise if I should create a new thread.

THANK YOU in advance!
James

Here is a query to sets a relationship attribute 'total' to the sum of the relationship distances for each relationship. The screenshots show 5 properties where updated (the total attributes) and the graph displays the total attribute for each relationship.

Note, I changed the predicate to use 'none', since this may be more performance, since the evaluation of the predicate can stop once one is found untrue.

match(e:Location{name:'E'})
match(j:Location{name:'J'})
match p=(e)-[*]->(j)
with p, relationships(p) as rels
where none(r in rels where not r.congestion = 0)
unwind range(0,size(rels)-1) as maxIndex
with reduce(s=0, i in range(0,maxIndex) | s+rels[i].distance) as sum, rels[maxIndex] as relationship_to_set
set relationship_to_set.total = sum

You could use the approach I demonstrated to calculate the 'cost' metric for each path between two points, then take the ones with the lowest cost. The cost can be a function of any relationship properties.

The graph data science (GDS) library has path finding algorithms that are based on 'path costs'. Using GDS requires you to project your graph into a memory representation that is used by the GDS algorithms. You then run the algorithms on the projected graph. This means you are taking a snapshot of your graph to process. Graph changes would require you to retroject your graph. I am not a user of GDS, so I am not the best person to ask.

Finally, the neo4j shortest path method does not consider cost. Here is an example usage:

match(n),(m) //add predicates to get specific n, m nodes
return allShortestPaths( (n)-[*..4]-(m) )  //limits to paths of 4 hops as an example
1 Like

Gary,

Thank you so much! This is very helpful and interesting. I look forward to reading and testing out the cypher language further. It's seems extremely powerful for the use cases I'm trying to solve for. Again thank you for the quick reply and details. Very helpful.

James

1 Like

There is a lot of good material in the manuals. I really find the following increased my capabilities:

  1. List predicates (you got that)
  2. list comprehension
  3. List functions
  4. Map projections
  5. Unwind
  6. With
  7. Call subqueries
  8. APOC library

I should note that you can include a where statement after the allShortestPath call and it will be considered. It is discussed here:

There is also shortestPath()