Sunday, December 12, 2010

Neo4j 1.2 M06 is out - Better REST Indexing and Server Plugins!

Peter Neubauer

Hi all, the Neo4j community is proud to release another milestone into the wild - Neo4j 1.2 M06. This time the main effort has been spent in two areas - a more complete REST API, and the first version of a plugin API for the Neo4j Server.

There has been a lot of feedback on the REST API and the server, thanks to all contributors, mailing list discussions, and real customers!

 

Integrated REST Index API

The new Index API that is integrated with the GraphDatabaseService is now exposed through REST, meaning that you can access the same indexes created through embedded Java. Rather than just a single index for nodes and another for relationships, it is now possible to have multiple named indexes of each type. Adding a node to an index automatically creates that index if it doesn't already exist.

For instance, to add a (pre-existing) node to a node index called "persons" you would POST:

curl -HContent-Type:application/json -X POST -d '"http://localhost:7474/db/data/node/123"' http://localhost:7474/db/data/index/node/persons/name/peter

Then, to look up all nodes that have a name property of "peter" in the "persons" index, simply GET:

curl -H Accept:application/json http://localhost:7474/db/data/index/node/persons/name/peter

For more thorough documentation of the REST API, see the API docs. They are even packaged with the download.

 

Server plugins - Hypermedia at work

Plugins provide an easy way to extend the Neo4j REST API with new functionality, without the need to invent your own API. You simply populate an Iterable of Node, Relationship or Path, specify parameters, point of extension and logic, and voila, you are done! Look at this:

 

 

@Description( "An extension to the Neo4j Server for getting all nodes or relationships" )
public class GetAll extends ServerPlugin
{
@Name( "get_all_nodes" )
@Description( "Get all nodes from the Neo4j graph database" )
@PluginTarget( GraphDatabaseService.class )
public Iterable<Node> getAllNodes( @Source GraphDatabaseService graphDb )
{
return graphDb.getAllNodes();
}

 

@Description( "Get all relationships from the Neo4j graph database" )
@PluginTarget( GraphDatabaseService.class )
public Iterable<Relationship> getAllRelationships( @Source GraphDatabaseService graphDb )
{
return new NestingIterable<Relationship, Node>( graphDb.getAllNodes() )
{
@Override
protected Iterator<Relationship> createNestedIterator( Node item )
{
return item.getRelationships( Direction.OUTGOING ).iterator();
}
};
}
}

 

This will make your extension visible in the database representation (@PluginTarget) whenever it is served from the Neo4j Server (this could also be Node or Relationship), letting clients automatically discover it from e.g. at http://localhost:7474/db/data:

 

curl -v http://localhost:7474/db/data/

 

{
"extensions-info" : "http://localhost:7474/db/data/ext",
"node" : "http://localhost:7474/db/data/node",
"node-index" : "http://localhost:7474/db/data/index/node",
"relationship-index" : "http://localhost:7474/db/data/index/relationship",
"reference_node" : "http://localhost:7474/db/data/node/0",
"extensions" : {
"GetAll" : {
"get_all_nodes" : "http://localhost:7474/db/data/ext/GetAll/graphdb/get_all_nodes",
"getAllRelationships" : "http://localhost:7474/db/data/ext/GetAll/graphdb/getAllRelationships"
}
}

 

Requesting a GET on one of the two extension endpoints...

curl http://localhost:7474/db/data/ext/GetAll/graphdb/get_all_nodes

 

...gives back the meta information about the service:

{
"extends" : "graphdb",
"description" : "Get all nodes from the Neo4j graph database",
"name" : "get_all_nodes",
"parameters" : [ ]
}

To use it, just POST to this URL, with parameters as specified in the description (none in this case).

This way, plugins contribute hypermedia and still maintain the notion of a tight REST API which talks Nodes, Relationships and Paths. Some very real plugins we are thinking of in the near future (and that are less than 100 LoC):

 

  • global functions with parameters, like getting some named nodes by id.
  • custom traversal implementations
  • server-side scripting wrappers that can execute scripts (JavaScript, JRuby, Gremlin etc) installed in some server directory
  • plugins that let you execute a scripted payload from the request

We have put a copld of example plugins into the download under /eamples/java, see http://components.neo4j.org/neo4j-examples/1.2-SNAPSHOT/ for online docs on them.

 

All in all, we think that we are getting pretty close to Neo4j 1.2 now, so stay tuned for the big push!

Your friendly Neo4j community.

3 comments:

Anonymous said...

Thanks for the post. How do we access the fulltext type for the lucene provider for index queries via REST?

Also, can you post, respond, or direct me to some resources on how to query an index with wildcards/fuzzy/range queries via the REST interface if it is indeed possible? Thanks!

Peter Neubauer said...

Hi there,
this should be possible. However, I added a functional test to verify that you can create index with custom config (e.g. Lucene Fulltext) and query them, will point you at it when it is done!

/peter

Peter Neubauer said...

Hi again,
it turns out that queries (opposed to exact matches) are not issued by the core API. This will be added in subsequent releases, or you write a simple ServerPlugin for it, taking the query string and returning the result nodes?

/peter