The closest node with label

Hi, I'm looking for a way to find the closest node with certain label. I have a graph like this:

I always start from brown or purple(with digit) node and I'd like find all the nearest pink node.

The count of nearest node isn't known. I tried to use apoc.path.expandConfig but I have to specify a limit or this call will return all of nodes with certain label which are connected in any hops

You can try this.

match(n{id:0}) where n:Brown or n:Purple
match path=(n)-[*]-(m:Pink)
with m, length(path) as len
with collect({node:m, length:len}) as data, min(len) as min_len
with [i in data where i.length = min_len] as pink_nodes
unwind pink_nodes as node
return node
1 Like

Hi, thank you for your answer. I would like to use this query with Full text search. In this database

Two nodes meet the requirements of query. I would like to find the closest pink node for each of this node (distance isn't the same). This is my query CALL db.index.fulltext.queryNodes('textIndex', 'Gdansk') YIELD node match path=(node)-[*]-(m:reference) with m, length(path) as len with collect({node:m, length:len}) as data, min(len) as min_len with [i in data where i.length = min_len] as pink_nodes unwind pink_nodes as node return node

I modified the query to work with multiple starting nodes. The query below will find the closest ‘reference’ nodes for each starting node. A list of the closest node is returned for each starting node, and the minimum length. A collection is returned in case there are multiple reference nodes that have the same minimum distance.

The lists contain the entire node. You can extract just the information you need for these nodes by adding a transformation to the list comprehension.

CALL db.index.fulltext.queryNodes('textIndex', 'Gdansk') YIELD node 
match path=(node)-[*]-(m:reference) 
with node, m, length(path) as len
with node, collect({node:m, length:len}) as data, min(len) as min_len 
return node, [i in data where i.length = min_len | i.node] as closest_nodes, min_len

1 Like

Hello @kamil.partyka1998 :slight_smile:

The answer of @glilienfield is good but can take a long time to run in a very dense graph. You should try shortestPath() if it meets your need:

CALL db.index.fulltext.queryNodes('textIndex', 'Gdansk') 
YIELD node 
MATCH path = shortestPath((node)-[*]-(m:reference)) 
WITH node, m, length(path) AS len
WITH node, collect({node:m, length:len}) AS data, min(len) AS min_len 
WITH node, [i IN data WHERE i.length = min_len] AS closest_nodes, min_len

You can also have a look at path finding algorithms from Graph Data Science plugin.

Best regards,
Cobra

1 Like

@cobra, doesn’t the neo4j shortestPath method require knowing the start and end nodes? The end node is unknown in this case?

The approach is not efficient because it exhaustively find all paths, then filters based on length to return only the ones that are the shortest. It would be best to perform a breadth- first search looking for nodes of the desired label, then stop searching when nodes with the label are found. This isn’t achievable in cypher, but requires a traversal algorithm.

1 Like

Yeah, indeed my bad :see_no_evil:

If he knows the label beforehand, then he could get all nodes in a previous MATCH and use apoc.path.expandConfig() procedure :slight_smile:

Best regards,
Cobra

1 Like

Hi, could you explain how to use apoc.path.expandConfig() in this case?

You can do a MATCH to get all nodes you want as end nodes and use them to set the parameter terminatorNodes for the apoc.path.expandConfig() procedure.

You are thinking of something like this:

CALL db.index.fulltext.queryNodes('textIndex', 'x') YIELD node MATCH (n:reference) CALL apoc.path.expandConfig(node,{terminatorNodes:[n], bfs:TRUE}) yield path as p WITH n, length(p) AS len WITH collect({node:n, length:len}) AS data, min(len) AS minLen WITH [i IN data WHERE i.length = minLen] AS closest_nodes UNWIND closest_nodes AS ids WITH collect(ids.node) AS x return x

MATCH (n:reference) 
WITH collect(n) AS references 
CALL db.index.fulltext.queryNodes('textIndex', 'x') 
YIELD node 
CALL apoc.path.expandConfig(node, {terminatorNodes: references, bfs: true}) 
YIELD path 
etc...