Graphs

Playing with graphs and neo4j

After my initial implementation of some BrainExpanded-related ideas on top of dgraph using its GraphQL interface, I realized that the GraphQL data model was a bit restrictive for what I needed. It’s a long story so I won’t bore you.

So, I started thinking of Neo4j. Jim pinged me and said something along the lines of “how dare you not use Neo4j?” Well… he didn’t really say that but I know that’s what he meant 🙂

The challenge – mapping between data models

The first thing I started was to change the implementation of my Web API (implemented in .NET) to interact with Neo4j. I very quickly realized that having to map my domain data model to/from Neo4j’s data model was going to be a pain, whether I used the Neo4j’s .NET driver or the Neo4j Web API. Why worrying about serializing/deserializing objects when middleware can do that automatically? Granted, I may not be able to do absolutely everything that Neo4j has to offer but the middleware should be able to handle most things for me such serialization/deserialization, mapping between .NET and Neo4j data types, representation of nodes and relationships, simple graph queries, navigational queries with projects/filtering, graph traversals, etc.

So, with the help of Github’s copilot and its various models, I built the “Graph Model” abstraction and an implementation of it for Neo4j.

Welcome to the Graph Model

This project is just a tool for what I am doing with my main project so I decided to open source the code in case others are interested. There is a ton more to be done and a lot of cleaning up to do. The coding models tend to write a lot of code which isn’t necessarily beautiful and well-organized. I collaborated with the models by writing tests. I wrote the Graph.Model interfaces, most of the Neo4jGraphProvider class, and most of the tests. The coding AIs wrote most of the LINQ expression → Cypher logic.

What is the Graph Model?

GraphModel is a .NET library that provides a clean abstraction over graph databases, particularly Neo4j. It offers a set of interfaces and tools to model, query, and manage graph data effectively. Think of it as your trusty compass in the vast forest of nodes and relationships.

🚀 Getting Started

Ready to dive in? Here’s how you can get started.

1. Install the NuGet Package:

> dotnet new console
> dotnet add package Cvoya.Graph.Model
> dotnet add package Cvoya.Graph.Provider.Neo4j

2. Define your application domain entities

using Cvoya.Graph.Model;

public class Person : Node
{
    public string Name { get; set; }
}

public class Knows : Relationship
{
    public DateTime Since { get; set; }
}

3. Initialize a provider

Providers implement the Cvoya.Graph.Model.IGraph interface. The Cvoya.Graph.Provider.Neo4j is such a provider.

var provider = new Neo4jGraphProvider("bolt://localhost:7687", "neo4j", "password");

4. Ready to partyyyyy

var alice = new Person { Name = "Alice" };
var bob = new Person { Name = "Bob" };
var knows = new Knows { Since = DateTime.Now };

context.CreateRelationship(alice, knows, bob);

And voilà! You’ve just established a relationship between Alice and Bob.

🔍 Querying the Graph

GraphModel requires providers to implement LINQ queries. The Neo4j provider offers extensive support for queries over the graph database. Check out the tests in the graphmodel repo to get ideas.

var friendsOfAlice = context.Match<Person>()
    .Where(p => p.Name == "Alice")
    .Traverse<Knows>()
    .To<Person>();

🔄 Transactions

Need to perform multiple operations atomically? GraphModel has you covered:

using var tx = context.BeginTransaction())
var charlie = new Person { Name = "Charlie" };
context.CreateNode(charlie);
tx.Commit();

🧩 Attributes

Customize your graph entities using attributes:

[Node(Label = "User")]
public class Person : Node
{
    [Property(Name = "full_name")]
    public string Name { get; set; }
}

var savas = new Person { Id = "savas", Name = "Savas Parastatidis" }
await provider.CreateNode(savas)

This maps the Person class to a User node in Neo4j, with the Name property stored as full_name. It is now possible to retrieve the same node using a completely different class. In other words, there is no tight-coupling between the Person class and the Neo4j representation’s of the graph node.

[Node(Label = "User")]
public class SomeOtherPersonClass : Node
{
    [Property(Name = "full_name")]
    public string FullName { get; set; }
}

var greekDude = await provider.GetNode<SomeOtherPersonClass>("savas")

There is so much more but this entry is a good start.

Feedback

I am sure there are many issues with the project. Please feel free to send me feedback via email or submit an issue. Pull requests are also very much welcomed 🙂

Savas Parastatidis

Savas Parastatidis works at Amazon as a Sr. Principal Engineer in Alexa AI'. Previously, he worked at Microsoft where he co-founded Cortana and led the effort as the team's architect. While at Microsoft, Savas also worked on distributed data storage and high-performance data processing technologies. He was involved in various e-Science projects while at Microsoft Research where he also investigated technologies related to knowledge representation & reasoning. Savas also worked on language understanding technologies at Facebook. Prior to joining Microsoft, Savas was a Principal Research Associate at Newcastle University where he undertook research in the areas of distributed, service-oriented computing and e-Science. He was also the Chief Software Architect at the North-East Regional e-Science Centre where he oversaw the architecture and the application of Web Services technologies for a number of large research projects. Savas worked as a Senior Software Engineer for Hewlett Packard where he co-lead the R&D effort for the industry's Web Service transactions service and protocol. You can find out more about Savas at https://savas.me/about

Share
Published by
Savas Parastatidis

Recent Posts

A Graph Model DSL

Say hello to the Graph Model Domain Specific Language (GMDSL), created with the help of…

2 weeks ago

BrainExpanded – Web app and Data Sources

As I wrote in previous posts, the manual recording of memories for BrainExpanded is just…

1 month ago

BrainExpanded – End-to-end working

Imagine a world where your memory is enhanced by a team of intelligent agents, working…

1 month ago

BrainExpanded – Login State Caching Issue in iOS Share Extension

As part of the BrainExpanded project, I’m building an iOS app that lets users easily…

3 months ago

Is AI Good or Bad?

Artificial Intelligence (AI) has rapidly evolved over the past few decades, becoming an integral part…

3 months ago

BrainExpanded – Copilot

Happy New Year everyone! I was planning for my next BrainExpanded post to be a…

5 months ago