Using Cypher with Neography
Join the DZone community and get the full member experience.
Join For FreeCypher is the query language of Neo4j, and as promised I’ll show you how you can use it to implement friend recommendations as well as degrees of separation.
We can send any cypher query to Neo4j via the REST API and neography using the execute_query command. Let’s implement suggestions_for so it sends a cypher query to the server:
def suggestions_for(node) node_id = node["self"].split('/').last @neo.execute_query("START me = node({node_id}) MATCH (me)-[:friends]->(friend)-[:friends]->(foaf) RETURN foaf.name", {:node_id => node_id})["data"] end puts "Johnathan should become friends with #{suggestions_for(johnathan).join(', ')}" # RESULT # Johnathan should become friends with Mary, Phil
Let’s go through the query:
START me = node({node_id})
is the place in the graph where we will begin. We are naming this node “me” and will reference it later. The
{node_id}
part defines a parameter which we will fill in later. Like before, we want to find nodes that are two friends relationships away
MATCH (me)-[:friends]->(friend)-[:friends]->(foaf)
and we want to return the name of these friends of a friend which we are labeling “foaf”, skipping over our known friends which were labeled “friend”
RETURN foaf.name
We then pass in our parameter
{:node_id => node_id}
This last bit just grabs the name data, ignoring the names of the columns which are also returned
["data"]
How about degrees of separation?
def degrees_of_separation(start_node, destination_node) start_node_id = start_node["self"].split('/').last destination_node_id = destination_node["self"].split('/').last @neo.execute_query("START me=node({start_node_id}), them=node({destination_node_id}) MATCH path = allShortestPaths( me-[?*]->them ) RETURN length(path), extract(person in nodes(path) : person.name)", {:start_node_id => start_node_id, :destination_node_id => destination_node_id })["data"] end degrees_of_separation(johnathan, mary).each do |path| nodes = path.last[1..(path.last.size - 2)].split(", ") puts "#{path.first} degrees: " + nodes.join(' => friends => ') end # RESULT # 2 degrees: Johnathan => friends => Mark => friends => Mary
We are once again using some of the built in graph functions of Neo4j. In this case we are using allShortestPaths. We start with “me” as the start node and “them” as the destination node
START me=node({start_node_id}), them=node({destination_node_id})
We want to match any relationship between me and them, and get the shortest paths
MATCH path = allShortestPaths( me-[?*]->them )
MATCH path = allShortestPaths( me-[?*]->them )
then we want to return the length of the paths and the names of the nodes. We use the extract function to pull node data from the paths. You can think of extract like map or collect in Ruby
RETURN length(path), extract(person in nodes(path) : person.name)
We pass in our parameters
{:start_node_id => start_node_id, :destination_node_id => destination_node_id }
and we just want the data returned, ignoring the column names
["data"]
We do a bit of string wrangling at the end to get the format we want and that’s all there is too it.
Cypher is a fairly new language and is undergoing constant additions and improvements. Contribute and stay up to date by checking the Neo4j Google Group.
Source: http://maxdemarzi.com/2012/01/07/cypher-with-neography/
Opinions expressed by DZone contributors are their own.
Comments