Reference
Introduction
Neo4j-OGM is a fast object-graph mapping library for Neo4j, optimised for server-based installations utilising Cypher.
It aims to simplify development with the Neo4j graph database and like JPA, it uses annotations on simple POJO domain objects to do so.
With a focus on performance, Neo4j-OGM introduces a number of innovations, including:
-
non-reflection based classpath scanning for much faster startup times
-
variable-depth persistence to allow you to fine-tune requests according to the characteristics of your graph
-
smart object-mapping to reduce redundant requests to the database, improve latency and minimise wasted CPU cycles
-
user-definable session lifetimes, helping you to strike a balance between memory-usage and server request efficiency in your applications.
Overview
This reference documentation is broken down into sections to help the user understand specifics of how Neo4j-OGM works.
- Getting started
-
Getting started can sometimes be a chore. What versions of Neo4j-OGM do you need? Where do you get them from? What build tool should you use? Getting Started is the perfect place to well… get started!
- Configuration
-
Drivers, logging, properties, configuration via Java. How to make sense of all the options? Configuration has got you covered.
- Annotating your Domain Objects
-
To get started with your Neo4j-OGM application, you need only your domain model and the annotations provided by the library. You use annotations to mark domain objects to be reflected by nodes and relationships of the graph database. For individual fields the annotations allow you to declare how they should be processed and mapped to the graph. For property fields and references to other entities this is straightforward. Because Neo4j is a schema-free database, Neo4j-OGM uses a simple mechanism to map Java types to Neo4j nodes using labels. Relationships between entities are first class citizens in a graph database and therefore worth a section of it’s own describing their usage in Neo4j-OGM.
- Connecting to the Database
-
Managing how you connect to the database is important. Connecting to the Database has all the details on what needs to happen to get you up and running.
- Interacting with the Graph Model
-
Neo4j-OGM offers a session for interacting with the mapped entities and the Neo4j graph database. Neo4j uses transactions to guarantee the integrity of your data and Neo4j-OGM supports this fully. The implications of this are described in the transactions section. To use advanced functionality like Cypher queries, a basic understanding of the graph data model is required. The graph data model is explained in the chapter about in the introduction chapter.
- Type Conversion
-
Neo4j-OGM provides support for default and bespoke type conversions, which allow you to configure how certain data types are mapped to nodes or relationships in Neo4j. See Type Conversion for more details.
- Filtering your domain objects
-
Filters provides a simple API to append criteria to your stock
Session.loadX()
behaviour. This is covered in more detail in Filters. - Reacting to Persistence events
-
The Events mechanism allows users to register event listeners for handling persistence events related both to top-level objects being saved as well as connected objects. Event handling discusses all the aspects of working with events.
- Testing in your application
-
Sometimes you want to be able to run your tests against an in-memory version of Neo4j-OGM. Testing goes into more detail of how to set that up.
Getting Started
Versions
Consult the version table to determine which version of Neo4j-OGM to use with a particular version of Neo4j and related technologies.
Compatibility
Neo4j-OGM Version | Neo4j Version1 |
---|---|
4.0.x2 |
4.4.x6, 5.x |
3.2.x |
3.2.x, 3.3.x, 3.4.x, 3.5.x, 4.0.x2, 4.1.x2, 4.2.x2, 4.3.x2,5, 4.4.x2,5 |
3.1.x3 |
3.1.x, 3.2.x, 3.3.x, 3.4.x |
3.0.x3 |
3.1.9, 3.2.12, 3.3.4, 3.4.4 |
2.1.x4 |
2.3.9, 3.0.11, 3.1.6 |
2.0.24 |
2.3.8, 3.0.7 |
2.0.14 |
2.2.x, 2.3.x |
1 The latest supported bugfix versions.
2 These versions only support connections via Bolt.
3 These versions are no longer actively developed.
4 These versions are no longer actively developed or supported.
5 Neo4j-OGM 3.2.24+ only.
6 Technical working but not officially supported
Dependency Management
For building an application, your build automation tool needs to be configured to include the Neo4j-OGM dependencies.
Neo4j-OGM dependencies consist of neo4j-ogm-core
, together with the relevant dependency declarations on the driver you want to use.
Neo4j-OGM 4.x provides only support for the Bolt driver, but for compatibility reasons you have to declare the dependency:
-
neo4j-ogm-bolt-driver
- Uses native Bolt protocol to communicate between Neo4j-OGM and a remote Neo4j instance. -
neo4j-ogm-bolt-native-types
- Support for all of Neo4j’s property types through the Bolt protocol.
Neo4j-OGM projects can be built using Maven, Gradle or any other build system that utilises Maven’s artifact repository structure.
Maven
In the <dependencies>
section of your pom.xml
add the following:
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-ogm-core</artifactId>
<version>4.0.19</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-ogm-bolt-driver</artifactId>
<version>4.0.19</version>
<scope>runtime</scope>
</dependency>
Please also have a look at the native type system to take advantage of Neo4j-OGM’s support for native temporal and spatial types.
Configuration
Configuration method
There are several ways to supply configuration to Neo4j-OGM:
-
using a properties file
-
programmatically using Java
-
by providing an already configured Neo4j Java driver instance
These methods are described below. They are also available as code in the examples.
Using a properties file
Properties file on classpath:
ConfigurationSource props = new ClasspathConfigurationSource("my.properties");
Configuration configuration = new Configuration.Builder(props).build();
Properties file on filesystem:
ConfigurationSource props = new FileConfigurationSource("/etc/my.properties");
Configuration configuration = new Configuration.Builder(props).build();
Programmatically using Java
In cases where you are not able to provide configuration via a properties file you can configure Neo4j-OGM programmatically instead.
The Configuration
object provides a fluent API to set various configuration options.
This object then needs to be supplied to the SessionFactory
constructor in order to be configured.
By providing a Neo4j driver instance
Just configure the driver as you would do for direct access to the database, and pass the driver instance to the session factory.
This method allows the greatest flexibility and gives you access to the full range of low level configuration options.
org.neo4j.driver.Driver nativeDriver = ...;
Driver ogmDriver = new BoltDriver(nativeDriver);
new SessionFactory(ogmDriver, ...);
Driver Configuration
For configuration through properties file or configuration builder the driver is automatically inferred from given URI. Empty URI means embedded driver with impermanent database.
Bolt Driver
Note that for the URI
, if no port is specified, the default Bolt port of 7687
is used.
Otherwise, a port can be specified with bolt://neo4j:password@localhost:1234
.
Also, the bolt driver allows you to define a connection pool size, which refers to the maximum number of sessions per URL.
This property is optional and defaults to 50
.
ogm.properties | Java Configuration |
---|---|
|
|
A timeout to the database with the Bolt driver can be set by updating your Database’s neo4j.conf
.
The exact setting to change can be found here.
Credentials
If you are using the Bolt Driver you have a number of different ways to supply credentials to the Driver Configuration.
ogm.properties | Java Configuration |
---|---|
|
|
Note: Currently only Basic Authentication is supported by Neo4j-OGM. If you need to use more advanced authentication scheme, use the native driver configuration method.
Transport Layer Security (TLS/SSL)
The Bolt and HTTP drivers also allow you to connect to Neo4j over a secure channel. These rely on Transport Layer Security (aka TLS/SSL) and require the installation of a signed certificate on the server.
In certain situations (e.g. some cloud environments) it may not be possible to install a signed certificate even though you still want to use an encrypted connection.
To support this, both drivers have configuration settings allowing you to bypass certificate checking, although they differ in their implementation.
Both of these strategies leave you vulnerable to a MITM attack. You should probably not use them unless your servers are behind a secure firewall. |
Bolt
ogm.properties | Java Configuration |
---|---|
|
|
TRUST_ON_FIRST_USE
means that the Bolt Driver will trust the first connection to a host to be safe and intentional.
On subsequent connections, the driver will verify that the host is the same as on that first connection.
Bolt connection testing
In order to prevent some network problems while accessing a remote database, you may want to tell the Bolt driver to test connections from the connection pool.
This is particularly useful when there are firewalls between the application tier and the database.
You can do that with the connection liveness parameter which indicates the interval at which the connections will be tested. A value of 0 indicates that the connection will always be tested. A negative value indicates that the connection will never be tested.
ogm.properties | Java Configuration |
---|---|
|
|
Eager connection verification
OGM by default does not connect to Neo4j server on application startup.
This allows you to start the application and database independently and Neo4j will be accessed on first read/write.
To change this behaviour set the property verify.connection
(or Builder.verifyConnection(boolean)
) to true.
This settings is valid only for Bolt drivers.
Logging
Neo4j-OGM uses SLF4J to log statements. In production, you can set the log level in a file called logback.xml to be found at the root of the classpath. Please see the Logback manual for further details.
An important logger is the BoltResponse
logger.
It has multiple "sub-logger" for Neo4j notification categories that may come up when using e.g. deprecated features.
An overview can be seen in the following list.
-
org.neo4j.ogm.drivers.bolt.response.BoltResponse.performance
-
org.neo4j.ogm.drivers.bolt.response.BoltResponse.hint
-
org.neo4j.ogm.drivers.bolt.response.BoltResponse.unrecognized
-
org.neo4j.ogm.drivers.bolt.response.BoltResponse.unsupported
-
org.neo4j.ogm.drivers.bolt.response.BoltResponse.deprecation
-
org.neo4j.ogm.drivers.bolt.response.BoltResponse.generic
-
org.neo4j.ogm.drivers.bolt.response.BoltResponse.security
-
org.neo4j.ogm.drivers.bolt.response.BoltResponse.topology
You can still use the org.neo4j.ogm.drivers.bolt.response.BoltResponse
logger as the main logger and just adjust the details in some details to your needs.
Class loading precedence
In some scenarios and environments (Spring Boot’s @Async
annotated classes/methods, CompletableFuture
usage, etc.) , it is necessary to declare the used class loading precedence for Neo4j-OGM to use.
As default, it uses the current thread’s context class loader.
To change this behaviour, the OGM_CLASS_LOADER
has to be set only once for the Configuration
class.
This can be done during configuration of your application or similar.
Configuration.setClassLoaderPrecedence(Configuration.ClassLoaderPrecedence.OGM_CLASS_LOADER);
Annotating Entities
@NodeEntity: The basic building block
The @NodeEntity
annotation is used to declare that a POJO class is an entity backed by a node in the graph database.
Entities handled by Neo4j-OGM must have one empty public constructor to allow the library to construct the objects.
Fields on the entity are by default mapped to properties of the node. Fields referencing other node entities (or collections thereof) are linked with relationships.
@NodeEntity
annotations are inherited from super-types and interfaces.
It is not necessary to annotate your domain objects at every inheritance level.
Entity fields can be annotated with annotations like @Property
, @Id
, @GeneratedValue
, @Transient
or @Relationship
.
All annotations live in the org.neo4j.ogm.annotation
package.
Marking a field with the transient modifier has the same effect as annotating it with @Transient
; it won’t be persisted to the graph database.
@NodeEntity
public class Actor extends DomainObject {
@Id @GeneratedValue
private Long id;
@Property(name="name")
private String fullName;
@Property("age") // using value attribute to have a shorter definition
private int age;
@Relationship(type="ACTED_IN", direction=Relationship.Direction.OUTGOING)
private List<Movie> filmography;
}
@NodeEntity(label="Film")
public class Movie {
@Id @GeneratedValue Long id;
@Property(name="title")
private String name;
}
The default label is the simple class name of the annotated entity. There are some rules to determine if parent classes also contribute their label to the child class:
-
the parent class is a non-abstract class (the existing of
@NodeEntity
is optional) -
the parent class is an abstract class and has a
@NodeEntity
annotation -
java.lang.Object
will be ignored -
interfaces do not create an additional label
If the label
(as you can see in the example above) or the value
attribute of the @NodeEntity
annotation is set it will replace the default label applied to the node in the database.
Saving a simple object graph containing one actor and one film using the above annotated objects would result in the following being persisted in Neo4j.
(:Actor:DomainObject {name:'Tom Cruise'})-[:ACTED_IN]->(:Film {title:'Mission Impossible'})
When annotating your objects, you can choose to NOT apply the annotations on the fields. OGM will then use conventions to determine property names in the database for each field.
public class Actor extends DomainObject {
private Long id;
private String fullName;
private List<Movie> filmography;
}
public class Movie {
private Long id;
private String name;
}
In this case, a graph similar to the following would be persisted.
(:Actor:DomainObject {fullName:'Tom Cruise'})-[:FILMOGRAPHY]->(:Movie {name:'Mission Impossible'})
While this will map successfully to the database, it’s important to understand that the names of the properties and relationship types are tightly coupled to the class’s member names. Renaming any of these fields will cause parts of the graph to map incorrectly, hence the recommendation to use annotations.
Please read Non-annotated properties and best practices for more details and best practices on this.