I know it's been awhile since my last post, but, I assure you--one and all--that I have not left you kind folks for good. I can also assure you that the cause of my literary absence has everything to do with being loaded down with work and is not a result of my gallivanting around the world whilst trying strange and wonderful new beers.
(Boy, do I ever wish that was the case.)
No, I've managed to find some time in which to write a bit about something I've been looking into concerning SDN: Paths with multiple entity types.
So, without further ado, let's begin.
While the topics I'm about to go into could very well have solutions to them that I have yet to uncover, I'm presenting my findings and questions in the hopes that not only will someone find the discussion interesting/useful, but, that it might also help lead me to better solutions.
So, please do read on and try to keep the caveat above in mind.
Retrieving Heterogeneous Paths
If you'll recall from several posts ago, I had been attempting to write a web application based around the concept of a simple recommendation engine and a software retailer (a la Babbage's from the last century). The implementation was being done using a Spring-based Java stack with Neo4j as the data store.
I had gotten to a point where I was able to load data into Neo4j via a method not unlike the one from Cineasts' (which can be found as part of the Spring Data Neo4j Reference). A quick recap of the domain model follows below.
One important task of any recommendation engine is the ability to suggest entities that are relevant to a given starting point via some sequence of relationships. Implementing such an engine, while quite doable, is something that I will eventually get to.
Another more simple task is to be able to see how two entities are related, i.e. "how do I get from point A to point B?". As an example, one such question might be, "How is game A related to game B, even though the difference in publication dates is large?" And yes, this type of question is extremely similar to the "Six Degrees of Separation" question.
Some Basic Code
You might also recall that I had implemented a GameRepository class with the following signature:
public interface GameRepository extends GraphRepository<Game>, RelationshipOperationsRepository<Game>
With the above repository extending the GraphRepository and RelationshipOperationsRepository interfaces, we are provided with a host of cool (and handy) methods out of the box (tip: make sure you're comfortable with the "convention over configuration" paradigm, as there is a bit of magic that goes on with those OOTB methods).
As you'd expect, we can also add additional methods to the interface. One example of a method you might want to add could be a custom Cypher query that returns all Game nodes with a particular property (the implementation of this is outside the scope of this post, but it's actually pretty simple; if people want to see it, just shoot me a note!).
However, today we're looking to address the "Six Degrees of Separation" question (minus the limit on the degrees of separation), i.e. "how are node A and node B related"?
So let's give this a (very simple) shot:
@Query("START n=node(1), x=node(97) MATCH p = shortestPath( n-[*]-x ) RETURN p") Iterable<EntityPath<Game, Game> > getPath();
Given that the nodes with IDs 1 and 97 are "Game" nodes, the Cypher query above is essentially determining how the two nodes are related.
(For the sake of this post, I'm ignoring the fact that there could be multiple "shortest paths" between the two nodes as it has little bearing on the goal of this post.)
Quickly going over the return type, SDN allows us to return back an EntityPath given a starting node type and an ending node type which, in this case, is the Game type. An EntityPath is capable of storing nodes and their relationships as part of a Cypher path. The Iterable portion of the return type is necessary unless you want to use EndResult instead of Iterable.
We can then access the individual path(s) via the Iterable return type.
(NOTE: There is currently a bug with SDN that throws an exception when calling a single path's .nodes() or .nodeEntities(). This bug has been around since SDN 2.1.RC4.)