Deciding to prefer Gremlin over the basic Neo4j REST API in neo4django was quite a plunge. It’s an ongoing process, but I’ve realized that clever use of Gremlin and Cypher are the future for performant remote access to the database, and the switch has already shown significant gains.
One of the first issues I had was the constant need to send large, repetitive scripts over the wire. I wanted a server-side library, but I couldn’t require all users of neo4django to install a custom database extension just to try out the library. Right now, users simply pip install neo4django, fire up the database, and they’re ready to go. That simplicity is important, and worth preserving. And with the recent Heroku addon, I know I’m not the only one with this problem.
The script engine behind the Gremlin plugin persists class and method definitions, which got me excited- maybe I could just send a library once, and then refer to it? However, the engine restarts every 500 requests, wiping out persisted code and my hope for a simple solution.
So, since I really wanted it :), I decided on a more complex solution.
First, the client-side Groovy library this is based on can be found in its entirety in neo4django. The important bits are
class Neo4Django {
static public binding;
static doSomethingAwesome() {
binding.g.v(0)
}
}
Neo4Django.binding = binding;
- A class with a sensible name
- Static method definitions on the class for use in your other scripts
- A statement to make the script binding visible to the static context of the class (so your library functions can access script variables like "g").
Got all that? Good. Now, for every Gremlin call, wrap your script in a try/catch, like this
try {
results = Neo4Django.doSomethingAwesome()
}
catch (MissingPropertyException mpe) {
if (mpe.property == "Neo4Django") {
results = "ERROR: LIBRARY MISSING"
}
else {
throw mpe
}
}
results
Whenever a call returns whatever error message you’ve decided on, you know the library needs to be reloaded. Simply re-send the Gremlin with the library prepended.
Bam, you’re now loading server-side libraries on demand. Congratulations.
Caveats
If you know your Groovy, you might realize that there’s a huge problem here- import statements can’t be wrapped in try/catch blocks! When I first realized this, I was furious. Python’s “import anything, anywhere” approach has spoiled me.
Without imports, it’s much more difficult to take advantage of the native Neo4j API- you’ll only have access to classes already imported in the script binding. Cool, but not good enough.
My solution is a little dirty. Since imports are relatively simple in the Groovy grammar, I just pull them out with a regular expression, and include them before the try/catch. A Python library that parses Groovy would be ideal, but this is the best we’ve got.
Let me know what you think!
