Skip to content
NielsHoogeveen edited this page Aug 9, 2011 · 16 revisions

The standard Neo4J API provides methods to manipulate the underlying graph datastore. When building applications on top of Neo4J, a little more abstraction and some added features can be useful, hence an Enhanced API.

Neo4j database elements

A Neo4J graph consists of the following element types:

  • Node
  • Relationship
  • RelationshipType
  • Property name
  • Property value

These five types of elements don't share a common interface, except for Node and Relationship, which both extend the PropertyContainer interface.

The Enhanced API unifies all Neo4j elements under the common interface Vertex.

Vertex

A Vertex is very similar to a Node in standard Neo4j API, properties can be set on a Vertex and Edges (similar to Relationships in standard Neo4j, but further generalized) can be created connecting Vertices to other Vertices.

Edge

An Edge is a Vertex that can connect to other Vertices. Each Edge has an EdgeType which determines the number and type of the connections an Edge has.

EdgeType

An EdgeType has a unique name, through which it can be addressed and contains a set of Connectors.

Connector

A Connector determines the the type of connections an EdgeType supports, through its ConnectorType

ConnectorType

A Connector type has a name, through which it can be addressed and it has a ConnectionMode.

ConnectionMode

A Connector(Type) can have one of four ConnectionModes:

Connection modes

These modes have the following meaning:

  • Unrestricted: An Edge can connect to an unlimited number of Vertices through a Connector with an unrestricted mode, and a Vertex can have an unlimited number of connected Edges with a ConnectorType with an unrestricted ConnectionMode.
  • Injective: An Edge can connect to only one Vertex through a Connector with injective mode, but a Vertex can have an unlimited number of connected Edges with a ConnectorType with an injective ConnectionMode.
  • Surjective: An Edge can connect to an unlimited number of Vertices through a Connector with a surjective mode, but a Vertex can only have one Edge connected to it with a ConnectorType with a surjective ConnectionMode.
  • Bijective: An Edge can connect to only one Vertex through a Connector with bijective mode, and a Vertex can only have one Edge connected to it with a ConnectorType with a bijective ConnectionMode.

BinaryEdge

The BinaryEdge Interface in Enhanced API mimics the behaviour of a Relationship in the standard Neo4j API. It has two connectors:

  • StartConnector
  • EndConnector

Both StartConnector and EndConnector have an injective ConnectionMode. Just like Relationship in the standard Neo4j API connects two Nodes, a BinaryEdge connects two Verices. Just like Nodes can have many other Relationships with that same RelationshipType, so can Vertices have many BinaryEdges with the same EdgeType.

Let's look at an example, where we state that John is a neighbour of Paula.

BinaryEdge example

There are two regular vertices (presented in black), denoting the persons: John and Paula. There is one Edge (presented in red), which is also a Vertex, but it has two injective connectors on top of it. The connections are presented in blue.

BinaryEdge manipulation

A Vertex has several methods to manipulate BinaryEdges. All of them very similar to the Relationship related methods on Node in the standard API:

public Vertex addEdge(Vertex vertex, RelationshipType relationshipType);

public BinaryEdge createBinaryEdgeTo(Vertex vertex, RelationshipType type);

public Iterable<BinaryEdge> getBinaryEdges();

public Iterable<BinaryEdge> getBinaryEdges(Direction dir);

public Iterable<BinaryEdge> getBinaryEdges(Direction direction, RelationshipType... types);

public Iterable<BinaryEdge> getBinaryEdges(RelationshipType... types);

public Iterable<BinaryEdge> getBinaryEdges(RelationshipType type, Direction dir);

public boolean hasBinaryEdge();

public boolean hasBinaryEdge(Direction dir);

public boolean hasBinaryEdge(Direction dir, RelationshipType... relTypes);

public boolean hasBinaryEdge(RelationshipType... relTypes);

public boolean hasBinaryEdge(RelationshipType relTypes, Direction dir);

The BinaryEdge interface defines the following methods:

public Vertex getEndVertex();

public Vertex getOtherVertex(Vertex element);

public Vertex getStartVertex();

public Vertex[] getVertices();

Properties

Properties are a special case of a general Edge, just like BinaryEdges.

A Property is a unary edge: an Edge with only one connector. That connector is bijective. After all a Vertex can have only one Property of a certain PropertyType and a Property can belong to only one Vertex (this is analogous to how properties work in the standard Neo4j API).

Let's say we want to state the fact that John is 49 years old:

Property example

There is one Vertex denoting John, and there is one Property (presented in red), which is also a Vertex, but it is an Edge on top of it, having one bijective connector.

PropertyType

Each Property has a PropertyType, which has a name, defines the Connector of the Property and parameterized is with the data type of the Property.

PropertyTypes are a closed set of classes, one for each of the data types supported by the Neo4j database:

  • BooleanPropertyType
  • BooleanArrayPropertyType
  • BytePropertyType
  • ByteArrayPropertyType
  • DoublePropertyType
  • DoubleArrayPropertyType
  • FloatPropertyType
  • FloatArrayPropertyType
  • IntegerPropertyType
  • IntegerArrayPropertyType
  • LongPropertyType
  • LongArrayPropertyType
  • ShortPropertyType
  • ShortArrayPropertyType
  • StringPropertyType
  • StringArrayPropertyType

No new PropertyType can be instantiated, nor can PropertyType be subclassed. All datatype specializations of PropertyType (BooleanPropertyType etc.) can be instantiated and can also be subclassed.

All non-array versions of PropertyType (except BooleanPropertyType) extend the ComparablePropertyType interface, which defines the following methods:

public int compare(Node node1, Node node2)
public int compare(T value, Node node)

This allows for the comparison of property values of two Vertices with the same PropertyType, and the comparison of the property value of a Vertex to a value having the same data type.

These methods are an integral part of IndexedRelationships, which is transparently supported by the Enhanced API under the name SortedBinaryRelationships.

Note

Properties in Neo4j can have different data types on different Nodes. It is legal in standard Neo4j to have one Node with a property "id", being a Long, while another Node in the database also has a property "id", being an Integer.

With Enhanced API this is no longer possible. Properies are no longer set by name, but by PropertyType. A PropertyType, just like any other EdgeType is a global definition, which contains the data type of the Property.

When using Enhanced API on an existing database, make sure that all properties with the same name have the same data type. ClassCastExceptions will be thrown if existing data does not conform to the the data type of the PropertyType.

Property manipulation

The Vertex interface supports several methods to manipulate Properties. The methods are largely based upon the PropertyContainer interface in the standard API.

public <T> Property<T> getProperty(PropertyType<T> pt);

public <T> T getPropertyValue(PropertyType<T> pt);

public <T> boolean hasProperty(PropertyType<T> pt);

public Vertex removeProperty(PropertyType<T> pt);

public Vertex setProperty(PropertyType<T> pt, T value);

public Iterable<PropertyType<?>> getPropertyTypes();

Apart from the obvious use of PropertyType instead of a name, the methods defined on Vertex differ from those defined on PropertyContainer in one more aspect. The setProperty and removeProperty return the Vertex, so it is possible to write code in fluent style:

db().createVertext
.setProperty(Name, "John")
.setAge(Age, 29)
.addEdge(NEIGHBOUR, Paula);

General Edge manipulation

The Vertex interface also supports methods for the manipulation of general edges:

public Iterable<Edge> getEdges(EdgeType... edgeTypes);

public Iterable<Edge> getEdges(EdgeType edgeType, ConnectorType<?>... role);

public boolean hasEdge(EdgeType... edgeTypes);

public boolean hasEdge(EdgeType edgeType, ConnectorType<?>... role);

While the Edge interface defines the following methods:

public Iterable<EdgeElement> getEdgeElements();

public Iterable<EdgeElement> getEdgeElements(ConnectorType<?>... connectorType);

public <T extends ConnectionMode> Iterable<Vertex> getVertices(ConnectorType<T> connectorType);

public <U extends InjectiveConnectionMode>Vertex getVertex(ConnectorType<U> connectorType);

EdgeElement

An EdgeElement represents a Connector on a specific Edge, together with all Vertices connected to it.

When we call Edge#getEdgeElements(), an iterable is returned containing an EdgeElement for each defined Connector. The EgdeElement has a method EdgeElement#getVertices which returns an Iterable, so we can retrieve all the Vertices connected to that Connector.

In the Connector has an injective connection mode (which includes bijective connection mode), a single Vertex can be returned.

A convenience method exists on the Edge interface to directly fetch the Vertex connected to a Connector with an injective connection mode, bypassing the EdgeElement step.

Nary edges

So far we have only looked at Edges with one connector (Properties), and with two connectors (BinaryEdges), but a generic Edge can have an unlimited number of connector.

Let's look at an example. Suppose we want to state that Tom, Dick and Harry give Flo and Eddie a Book and a Bicycle.

Nary edge example

There is an edge of type "GIVE", with three Connectors:

  • giver
  • recipient
  • gift

Each of these connectors has more than one Vertex connected to it.

To following code creates the example edge:

//create a Vertex for all participants
Vertex tom = graphDbExt().createVertex();
Vertex dick = graphDbExt().createVertex();
Vertex harry = graphDbExt().createVertex();
Vertex flo = graphDbExt().createVertex();
Vertex eddie = graphDbExt().createVertex();
Vertex book = graphDbExt().createVertex();
Vertex bicycle = graphDbExt().createVertex();

//create ConnectorTypes
ConnectorType<?> giver = graphDbExt().getConnectorType("giver", ConnectionMode.UNRESTRICTED);
ConnectorType<?> recipient = graphDbExt().getConnectorType("recipient", ConnectionMode.UNRESTRICTED);
ConnectorType<?> gift = graphDbExt().getConnectorType("gift", ConnectionMode.UNRESTRICTED);

Set<ConnectorType<?>> connectorTypes = new HashSet<ConnectorType<?>>();
connectorTypes.add(giver);
connectorTypes.add(recipient);
connectorTypes.add(gift);

//Create the edge
EdgeType edgeType = db.getEdgeType("GIVES", connectorTypes);


//Create EdgeElement for the "givers" Connector
ArrayList<Vertex> gv = new ArrayList<Vertex>();
gv.add(tom);
gv.add(dick);
gv.add(harry);
EdgeElement givers = new EdgeElement(giver, gv);

//Create EdgeElement for the "recipient" Connector
ArrayList<Vertex> rp = new ArrayList<Vertex>();
rp.add(flo);
rp.add(eddie);
EdgeElement recipients = new EdgeElement(recipient, rp);

//Create EdgeElement for the "gift" Connector
ArrayList<Vertex> gf = new ArrayList<Vertex>();
gf.add(book);
gf.add(bicycle);
EdgeElement gifts = new EdgeElement(gift, gf);

//Create the edge
Edge edge = graphDbExt().createEdge(egdeType, givers, recipients, gifts);

Generalizations of database elements

The Vertex interface support methods for the manipulation of Properties and Edges, thereby providing all methods normally associated with Nodes. Properties and Edges (including their Types) are Vertices too. This allows for the generalization of all Neo4j database elements as if they were Nodes.

Due to generalization it is possible to create Edges involving regular Vertices, Edges of any kind, including BinaryEdges and Properties.

The generalization also makes it possible to set Properties on all Vertices. So it even becomes possible to set a Property on a Property.

Clone this wiki locally