A graph database is a storage engine that is specialized in storing and retrieving vast networks of data. It efficiently stores nodes and relationships and allows high performance traversal of those structures. Properties can be added to nodes and relationships.
Graph databases are well suited for storing most kinds of domain models. In almost all domain models, there are certain things connected to other things. In most other modeling approaches, the relationships between things are reduced to a single link without identity and attributes. Graph databases allow one to keep the rich relationships that originate from the domain, equally well-represented in the database without resorting to also modeling the relationships as "things". There is very little "impedance mismatch" when putting real-life domains into a graph database.
Neo4j is a graph database. It is a fully transactional database (ACID) that stores data structured as graphs. A graph consists of nodes, connected by relationships. Inspired by the structure of the human brain, it allows for high query performance on complex data, while remaining intuitive and simple for the developer.
Neo4j has been in commercial development for 10 years and in production for over 7 years. Most importantly it has a helpful and contributing community surrounding it, but it also:
In addition, Neo4j has ACID transactions, durable persistence, concurrency control, transaction recovery, high availability, and more. Neo4j is released under a dual free software/commercial license model.
The interface org.neo4j.graphdb.GraphDatabaseService
provides access to the
storage engine. Its features include creating and retrieving nodes and relationships, managing
indexes (via the IndexManager), database life cycle callbacks, transaction management, and more.
The EmbeddedGraphDatabase
is an implementation of GraphDatabaseService that is used to
embed Neo4j in a Java application. This implementation is used so as to provide the highest
and tightest integration with the database. Besides the embedded mode, the
Neo4j server
provides access to the graph database via an HTTP-based REST API.
Using the API of GraphDatabaseService, it is easy to create nodes and relate them to each other. Relationships are typed. Both nodes and relationships can have properties. Property values can be primitive Java types and Strings, or arrays of Java primitives or Strings. Node creation and modification has to happen within a transaction, while reading from the graph store can be done with or without a transaction.
Example 18.1. Neo4j usage
GraphDatabaseService graphDb = new EmbeddedGraphDatabase( "helloworld" ); Transaction tx = graphDb.beginTx(); try { Node firstNode = graphDb.createNode(); Node secondNode = graphDb.createNode(); firstNode.setProperty( "message", "Hello, " ); secondNode.setProperty( "message", "world!" ); Relationship relationship = firstNode.createRelationshipTo( secondNode, DynamicRelationshipType.of("KNOWS") ); relationship.setProperty( "message", "brave Neo4j " ); tx.success(); } finally { tx.finish(); }
Getting a single node or relationship and examining it is not the main use case of a graph database.
Fast graph traversal and application of graph algorithms are. Neo4j provides a DSL for defining
TraversalDescription
s that can then be applied to a start node and will produce a
lazy java.lang.Iterable
result of nodes and/or relationships.
Example 18.2. Traversal usage
TraversalDescription traversalDescription = Traversal.description() .depthFirst() .relationships(KNOWS) .relationships(LIKES, Direction.INCOMING) .evaluator(Evaluators.toDepth(5)); for (Path position : traversalDescription.traverse(myStartNode)) { System.out.println("Path from start node to current position is " + position); }
The best way for retrieving start nodes for traversals is by using Neo4j's integrated index facilities. The GraphDatabaseService provides access to the IndexManager which in turn provides named indexes for nodes and relationships. Both can be indexed with property names and values. Retrieval is done with query methods on indexes, returning an IndexHits iterator.
Spring Data Graph provides automatic indexing via the @Indexed annotation, eliminating the need for manual index management.
Example 18.3. Index usage
IndexManager indexManager = graphDb.index(); Index<Node> nodeIndex = indexManager.forNodes("a-node-index"); Node node = ...; Transaction tx = graphDb.beginTx(); try { nodeIndex.add(node, "property","value"); tx.success(); } finally { tx.finish(); } for (Node foundNode : nodeIndex.get("property","value")) { // found node }