How to query Graph data in Redis using .NET


Profile picture for Steve Lorello
Author:
Steve Lorello, .NET Developer Advocate at Redis

RedisGraph enables you to store and query graph data in Redis using the Cypher Query Language. In this article, we will discuss the usage of RedisGraph with .NET.

NRedisGraph#

We'll use the NRedisGraph package in this tutorial. To install the package in your project, use dotnet add package NRedisGraph.

Running RedisGraph#

The easiest way to get up and running with RedisGraph locally is to use the RedisGraph docker image:

docker run -p 6379:6379 redislabs/redisgraph

The above command will start an instance of Redis locally with the RedisGraph module loaded, and you will be able to connect to it on localhost:6379

Connecting#

NRedisGraph makes use of the StackExchange.Redis project which is installed along with NRedisGraph. To create the RedisGraph object you'll first create a ConnectionMultiplexer, and pull a reference to an IDatabase object from it, and then initialize the RedisGraph with the IDatabase object:

var muxer = ConnectionMultiplexer.Connect("localhost");
var db = muxer.GetDatabase();
var graph = new RedisGraph(db);

Sending a Query#

Querying in RedisGraph applies to a wide array of operations, but fundamentally when executing queries with NRedisGraph, all you need to do is execute graph.Query or graph.QueryAsync passing in the name of the graph you want to query and the query you want to run. For example, we'll be using the graph pets for the remainder of this tutorial, pets is the name of the key the graph will be stored at. Hence any call to graph.Query or graph.QueryAsync will first pass in pets to indicate the graph to work with.

Creating a Node#

To create a node in RedisGraph, you'll use the Create Operation. Let's start by making 2 Humans, Alice and Bob:

var createBobResult = await graph.QueryAsync("pets", "CREATE(:human{name:'Bob',age:32})");
await graph.QueryAsync("pets", "CREATE(:human{name:'Alice',age:30})");

Running a Query against RedisGraph will result in a ResultSet. This result will contain some metadata about the result of the query in the Statistics section and any results generated by the query. In the above case, the only thing returned is the statistics for the query, which you can print out directly from the results object:

Console.WriteLine($"Nodes Created:{createBobResult.Statistics.NodesCreated}");
Console.WriteLine($"Properties Set:{createBobResult.Statistics.PropertiesSet}");
Console.WriteLine($"Labels Created:{createBobResult.Statistics.LabelsAdded}");
Console.WriteLine($"Operation took:{createBobResult.Statistics.QueryInternalExecutionTime}");

You can create nodes with other labels by simply executing another CREATE statement. For example, if we wanted to create a 'pet' named 'Honey' who is a 5-year-old greyhound, we would run:

await graph.QueryAsync("pets", "CREATE(:pet{name:'Honey',age:5,species:'canine',breed:'Greyhound'})");

Creating Relationships#

Like creating nodes, you can also create relationships in RedisGraph using the Query/QueryAsync commands to create relationships between nodes in RedisGraph. For example, to establish the owner relationship between Bob and the Greyhound Honey, you would use the following:

await graph.QueryAsync("pets",
"MATCH(a:human),(p:pet) WHERE(a.name='Bob' and p.name='Honey') CREATE (a)-[:OWNS]->(p)");

You could establish other relationships as well between nodes, say, for example, both Bob and Alice both walk Honey you could add the connections:

await graph.QueryAsync("pets",
"MATCH(a:human),(p:pet) WHERE(a.name='Alice' and p.name='Honey') CREATE (a)-[:WALKS]->(p)");
await graph.QueryAsync("pets",
"MATCH(a:human),(p:pet) WHERE(a.name='Bob' and p.name='Honey') CREATE (a)-[:WALKS]->(p)");

Querying Relationships#

Now that we've created a few Nodes and Relationships between nodes, we can query things in the Graph, again using Query and QueryAsync. So, for example, if we wanted to find all of Honey's owners, we would issue the following query:

var matches = await graph.QueryAsync("pets", "MATCH(a:human),(p:pet) where (a)-[:OWNS]->(p) and p.name='Honey' return a");

We can then iterate over the resultant matches, which is the same ResultSet class we were using before, but it will have actual results we can access this time.

foreach (var match in matches)
{
Console.WriteLine(((Node) match.Values.First()).PropertyMap["name"].Value);
}

We can also find all the walkers of Honey by finding all the human's who have a WALKS relationship with Honey:

matches = await graph.QueryAsync("pets", "MATCH(a:human),(p:pet) where (a)-[:WALKS]->(p) and p.name='Honey' return a");

Then if we wanted to find all of Bob's dogs, we would query the graph and find all the canines who have an OWNS relationship with a human named Bob:

matches = await graph.QueryAsync("pets", "MATCH(a:human),(p:pet) where (a)-[:OWNS]->(p) and p.species='canine' and a.name='Bob' return p");

Resources#

  • Code for this demo is available in GitHub
  • To learn more about RedisGraph, check out the docs site
  • To learn more about The Cypher Query Language, check out opencypher.org