Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Using Cypher with Neography

DZone's Guide to

Using Cypher with Neography

· Database Zone
Free Resource

Navigating today's database scaling options can be a nightmare. Explore the compromises involved in both traditional and new architectures.

Cypher 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/

 

 

Understand your options for deploying a database across multiple data centers - without the headache.

Topics:

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}