Thanks to Pieter, AnormCypher 0.4.1 supports versions earlier than Neo4j 1.9 (I didn’t realize this was an issue).
AnormCypher is a Cypher-oriented Scala library for Neo4j Server (REST). The goal is to provide a great API for calling arbitrary Cypher and parsing out results, with an API inspired by Anorm from the Play! Framework.
0.4.1 changes:
Allow configurable Cypher endpoint.
Roadmap:
0.5.0: Scala 2.10 Future/Stream non-blocking support
0.6.0: Cake pattern with pluggable interfaces for different protocols, REST batch/transactional API
So, apparently, the Neo Technology guys read one of my last blog posts titled “It all starts with the START” and wanted to make a liar out of me. Actually, I’m quite certain it had nothing at all to do with that–they are just wanting to improve Cypher to make it the best graph query language out there. But yes, the START clause is now optional. “How do I tell Neo4j where to start my traversals”, you might ask. Well, in the long run, you won’t need to anymore. Neo4j will keep index and node/rel statistics and know which index to use, and know which start points to use to make the match and where the most efficient query based on its cost optimization. It’s not quite there yet, so for a while we’ll probably want to make generous use of “index hints”, but I love the direction this is going–feels just like the good old SQL.
I have a feeling this will be a long post, so bear with me. With a fresh unzip of the tar file… let’s get dirty. I’ll just be running in shell, since some of the index stuff can’t be saved in console yet. This is a beautiful thing:
12345678
neo4j-sh (0)$ match n return n;
+-----------+
| n |
+-----------+
| Node[0]{} |
+-----------+
1 row
14 ms
Say I have a tree where values are stored in the leaf nodes. I want to find the sum of values under a particular node (and, if that node itself is a leaf node, its value). As usual, let’s start by building an example graph.
Thanks to Julien, we now have version 0.4 published with scala 2.10 support!
AnormCypher is a Cypher-oriented Scala library for Neo4j Server (REST). The goal is to provide a great API for calling arbitrary Cypher and parsing out results, with an API inspired by Anorm from the Play! Framework.
0.4.0 changes:
Scala 2.10
play-json
Roadmap:
0.5.0: Scala 2.10 Future/Stream non-blocking support
0.6.0: Cake pattern with pluggable interfaces for different protocols, REST batch API
Let’s say we have properties on our relationships in a path, for example, the distance between two locations. I’ll create an example graph. We want to be able to calculate the total of the properties over the graph.
We’ve got a tree structure with parents and children, and we want to figure out, starting from two children, which ancestor is the most recent common ancestor (MRCA). Let’s start by constructing an example graph (I usually just type this out into the console!). The root will be the common ancestor of all the others, so we’ll always get an answer in this case.
Most people want to find the shortest path between two nodes, which is why there’s a shortestPath function in Cypher. However, there are some use cases where you want to find the longest path while doing a variable length path pattern match. This is why: say I want to see the latest updates in my status list (organized in a linked list of nodes). A first attempt at this query might look like:
“Because friends don’t let friends write atrocious recursive joins in SQL.” -Max De Marzi
The match clause is one of the first things you learn with Cypher. Once you’ve figured out how to look up your starting bound identifiers with start, you usually (but not always) want to match a traversal pattern, which is one of Cypher’s most compelling features.
The goal of this post is not to go over the syntax for all of the different cases in match–for that the docs do a good job: Cypher MATCH docs. Rather, I hoped to explain more the how of how match works.
“It all starts with the START” -Michael Hunger, Cypher webinar, Sep 2012
The start clause is one of those things that seems quite simple initially. You specify your start point(s) for the rest of the query. Typically, you use an index lookup, or if you’re just messing around, a node id (or list of node ids). This sets the stage for you to match a traversal pattern, or just filter your nodes with a where. Let’s start with a simple example–here we’re going to find a single node, and return it (later we’ll get into why start is sort of like a SQL from):
Coming from SQL, I found Cypher a quick learn. The match was new, and patterns were new, but everything else seemed to fit well with SQL concepts. Except with, the way to build a sort of sub-query–it seemed hard to wrap my head around. So, what really happens behind the scenes with a with clause in your query? How does it work? It turns out, almost any complex query ends up needing a with in it, but let’s start with a simple example.