OrientDB Manual 1.7.8

Graph API

To use the Graph API include the following jars in your classpath:

orient-commons-*.jar
orientdb-core-*.jar
blueprints-core-*.jar
blueprints-orient-graph-*.jar / orientdb-graphdb-*.jar (depending on version)

If you're connected to a remote server (not local/plocal/memory modes) include also:

orientdb-client-*.jar
orientdb-enterprise-*.jar

To also use the TinkerPop Pipes tool include also:

pipes-*.jar

To also use the TinkerPop Gremlin language include also:

gremlin-java-*.jar
gremlin-groovy-*.jar
groovy-*.jar

NOTE: If you use OrientDB v1.4.x or major with the Deprecated Native API, set this configuration to make the new graphs compatible with the deprecated API:

alter database custom useLightweightEdges=false
alter database custom useClassForEdgeLabel=false
alter database custom useClassForVertexLabel=false
alter database custom useVertexFieldsForEdgeLabels=false

Introduction

Tinkerpop is a complete stack of projects to handle Graphs:

  • Blueprints provides a collection of interfaces and implementations to common, complex data structures. In short, Blueprints provides a one stop shop for implemented interfaces to help developers create software without being tied to particular underlying data management systems.
  • Pipes is a graph-based data flow framework for Java 1.6+. A process graph is composed of a set of process vertices connected to one another by a set of communication edges. Pipes supports the splitting, merging, and transformation of data from input to output.
  • Gremlin is a Turing-complete, graph-based programming language designed for key/value-pair multi-relational graphs. Gremlin makes use of an XPath-like syntax to support complex graph traversals. This language has application in the areas of graph query, analysis, and manipulation.
  • Rexster is a RESTful graph shell that exposes any Blueprints graph as a standalone server. Extensions support standard traversal goals such as search, score, rank, and, in concert, recommendation. Rexster makes extensive use of Blueprints, Pipes, and Gremlin. In this way its possible to run Rexster over various graph systems. To configure Rexster to work with OrientDB follow this guide: configuration.

Get started with Blueprints

OrientDB supports different kind of storages and depends by the Database URL used:

  • Persistent embedded GraphDB. OrientDB is linked to the application as JAR (No network transfer). Use plocal as prefix. Example "plocal:/tmp/graph/test"
  • In-Memory embedded GraphDB. Keeps all the data only in memory. Use memory as prefix. Example "memory:test"
  • Persistent remote GraphDB. Uses a binary protocol to send and receive data from a remote OrientDB server. Use remote as prefix. Example "remote:localhost/test". It requires a OrientDB Server instance is up and running at the specified address (localhost in this case). Remote database can be persistent or in-memory as well.

Work with GraphDB

Before to work with a graph you need an instance of OrientGraph class. The constructor gets a URL that is the location of database. If the database already exists, it will be opened, otherwise will be created. In multi-threads applications use one OrientGraph instance per thread.

Remember always to close the graph once done using the .shutdown() method.

Example:

OrientGraph graph = new OrientGraph("plocal:C:/temp/graph/db");
try {
  ...
} finally {
  graph.shutdown();
}

Use the factory

Starting from v1.7 the best way to get a Graph instance is through the OrientGraphFactory. To know more: Use the Graph Factory. Example:

// AT THE BEGINNING
OrientGraphFactory factory = new OrientGraphFactory("plocal:C:/temp/graph/db").setupPool(1,10);

// EVERY TIME YOU NEED A GRAPH INSTANCE
OrientGraph graph = factory.getTx();
try {
  ...

} finally {
   graph.shutdown();
}

Transactions

Every time the graph is modified an implicit transaction is started automatically if no previous transaction was running. Transactions are committed automatically when the graph is closed by calling the shutdown() method or by explicit commit(). To rollback changes call the rollback() method.

Changes inside a transaction will be temporary till the commit or the close of the graph instance. Concurrent threads or external clients can see the changes only when the transaction has been fully committed.

Full example:

try{
  Vertex luca = graph.addVertex(null); // 1st OPERATION: IMPLICITLY BEGIN A TRANSACTION
  luca.setProperty( "name", "Luca" );
  Vertex marko = graph.addVertex(null);
  marko.setProperty( "name", "Marko" );
  Edge lucaKnowsMarko = graph.addEdge(null, luca, marko, "knows");
  graph.commit();
} catch( Exception e ) {
  graph.rollback();
}

Surrounding the transaction between a try/catch assure that any errors will rollback the transaction to the previous status for all the involved elements.

NOTE: To work against a graph use always transactional OrientGraph instances, an never non-transactional ones to avoid graph corruption on multi-thread changes.

Work with vertexes and edges

Create a vertex

To create a new Vertex in the current Graph call the Vertex OrientGraph.addVertex(Object id)) method. Note that the id parameter is ignored since OrientDB implementation assigns a unique-id once the vertex is created. To return it use Vertex.getId()). Example:

Vertex v = graph.addVertex(null);
System.out.println("Created vertex: " + v.getId());

Create an edge

An edge links two vertexes previously created. To create a new Edge in the current Graph call the Edge OrientGraph.addEdge(Object id, Vertex outVertex, Vertex inVertex, String label )) method. Note that the id parameter is ignored since OrientDB implementation assigns a unique-id once the edge is created. To return it use Edge.getId()). outVertex is the vertex instance where the edge starts and inVertex is the vertex instance where the edge ends. label is the edge's label. Null to not assign it. Example:

Vertex luca = graph.addVertex(null);
luca.setProperty("name", "Luca");

Vertex marko = graph.addVertex(null);
marko.setProperty("name", "Marko");

Edge lucaKnowsMarko = graph.addEdge(null, luca, marko, "knows");
System.out.println("Created edge: " + lucaKnowsMarko.getId());

Retrieve all the vertices

To retrieve all the vertices use the getVertices() method:

for (Vertex v : graph.getVertices()) {
    System.out.println(v.getProperty("name"));
}

Retrieve all the edges

To retrieve all the vertices use the getEdges()) method:

for (Edge e : graph.getEdges()) {
    System.out.println(e.getProperty("age"));
}

NOTE: Starting from OrientDB v1.4.x edges by default are stored as links not as records (i.e. useLightweightEdges=true by default). This is to improve performance. As a consequence, getEdges will only retrieve records of class E. With useLightweightEdges=true, records of class E are only created under certain circumstances (e.g. if the Edge has properties) otherwise they will be links on the in and out vertices. If you really want getEdges to return all edges, disable the Lightweight-Edge feature by executing this command once: alter database custom useLightweightEdges=false. This will only take effect for new edges so you'll have to convert the links to actual edges before getEdges will return all edges. For more information look at: https://github.com/orientechnologies/orientdb/wiki/Troubleshooting#why-i-cant-see-all-the-edges.

Remove a vertex

To remove a vertex from the current Graph call the OrientGraph.removeVertex(Vertex vertex)) method. The vertex will be disconnected from the graph and then removed. Disconnection means that all the vertex's edges will be deleted as well. Example:

graph.removeVertex(luca);

Remove an edge

To remove an edge from the current Graph call the OrientGraph.removeEdge(Edge edge)) method. The edge will be removed and the two vertexes will result not connected anymore. Example:

graph.removeEdge(lucaKnowsMarko);

Set and get properties

Vertexes and Edges can have multiple properties where the key is a String and the value can be any supported OrientDB types.

Example:

vertex2.setProperty("x", 30.0f);
vertex2.setProperty("y", ((float) vertex1.getProperty( "y" )) / 2);

for (String property : vertex2.getPropertyKeys()) {
      System.out.println("Property: " + property + "=" + vertex2.getProperty(property));
}

vertex1.removeProperty("y");

Setting multiple properties

Blueprints extension OrientDB Blueprints implementation supports setting of multiple properties in one shot against Vertices and Edges. This improves performance avoiding to save the graph element at every property set: setProperties(Object ...)). Example:

vertex.setProperties( "name", "Jill", "age", 33, "city", "Rome", "born", "Victoria, TX" );

You can also pass a Map of values as first argument. In this case all the map entries will be set as element properties:

Map<String,Object> props = new HashMap<String,Object>();
props.put("name", "Jill");
props.put("age", 33);
props.put("city", "Rome");
props.put("born", "Victoria, TX");
vertex.setProperties(props);

Create Element and properties all together

If you want to create a vertex or an edge setting also the initial properties, OrientDB Blueprints implementation offers new methods to do it:

graph.addVertex( "class:Customer", "name", "Jill", "age", 33, "city", "Rome", "born", "Victoria, TX" );

This creates a new Vertex of class Customer with the properties: name, age, city, and born. The same is for Edges:

person1.addEdge("class:Friend", person2, null, null, "since", "2013-07-30");

This creates a new Edge of class Friend between vertices person1 and person2 with the property since.

Both methods accepts a Map<String, Object> as parameter to set one property per map entry (see above for the example).

These methods are specially useful if you've declared constraints in the schema, for example a property cannot be null, and only using these methods will the validation checks succeed.

Use indices

OrientDB allows execution queries against any field of vertices and edges, indexed and not-indexed. The first rule to speed up queries is to setup indexes on the key properties you use in query. For example if you have a query that is looking for all the vertices with the name 'OrientDB' you do:

graph.getVertices("name", "OrientDB");

Without an index against the property "name" this execution could take a lot of time. So let's create a new index against the "name" property:

graph.createKeyIndex("name", Vertex.class);

If the name MUST be unique you can enforce this constraint by setting the index as "UNIQUE" (this is an OrientDB only feature):

graph.createKeyIndex("name", Vertex.class, new Parameter("type", "UNIQUE"));

This constraint will be applied to all the Vertex and sub-types instances. To specify an index against a custom type like the "Customer" vertices use the additional parameter "class":

graph.createKeyIndex("name", Vertex.class, new Parameter("class", "Customer"));

You can also have both UNIQUE index against custom types:

graph.createKeyIndex("name", Vertex.class, new Parameter("type", "UNIQUE"), new Parameter("class", "Customer"));

To get a vertex or an edge by key prefix the class name to the field. For the example above use Customer.name in place of only name to use the index created against the field name of class Customer:

for (Vertex v : graph.getVertices("Customer.name", "Jay")) {
    System.out.println("Found vertex: " + v);
}

If the class name is not passed, then "V" is taken for vertices and "E" for edges:

graph.getVertices("name", "Jay");
graph.getEdges("age", 20);

For more information about indexes look at Index guide.

Use Non Transactional Graph

To speed up operation like on massive insertion you could avoid transactions at all by using a different class then OrientGraph: OrientGraphNoTx. In this case each operation is atomic and data is updated at each operation. When the method returns the underlying storage is updated. Use this for bulk insert and massive operations.

NOTE: The usage of Non-Transactional graphs could drive corruption of the graph on multi-thread changes, so use Non-Transactional graph instances only for non multi-threads operations.

Configure the Graph

Starting from v1.6 OrientDB supports configuration of the graph by setting all the properties on construction:

Name Description Default value
blueprints.orientdb.url Database URL -
blueprints.orientdb.username User name admin
blueprints.orientdb.password User password admin
blueprints.orientdb.saveOriginalIds Saves the original element IDs by using the property _id. This could be useful on import of graph to preserve original ids false
blueprints.orientdb.keepInMemoryReferences Avoid to keep records in memory but only RIDs false
blueprints.orientdb.useCustomClassesForEdges Use Edge's label as OrientDB class. If doesn't exist create it under the hood true
blueprints.orientdb.useCustomClassesForVertex Use Vertex's label as OrientDB class. If doesn't exist create it under the hood true
blueprints.orientdb.useVertexFieldsForEdgeLabels Store the edge relationships in vertex by using the Edge's class. This allow to use multiple fields and make faster traversal by edge's label (class) true
blueprints.orientdb.lightweightEdges Uses lightweight edges. This avoid to create a physical document per edge. Documents are created only when they have properties true
blueprints.orientdb.autoStartTx Auto start a transaction as soon the graph is changed by adding/remote vertices and edges and properties true

Gremlin usage

If you use GREMLIN language with OrientDB remember to initialize it with:

OGremlinHelper.global().create()

Look at these pages about GREMLIN usage:

Multi thread applications

Multi-threads application must use one OrientGraph instance per thread. For more information about multi-threading look at Java Multi Threading.

Blueprints extensions

OrientDB is a Graph Database with steroids because it merges the graph, document and object-oriented worlds together. Below are some of the features exclusive to OrientDB.

Custom types

OrientDB supports custom types for vertices and edges in an Object Oriented manner. Even if this isn't supported directly by Blueprints there are some tricks to use them. Look at the Graph Schema page to know how to create a schema and work against types.

OrientDB added few variants to the Blueprints methods to work with types.

Retrieve vertices and edges by type

To retrieve all the vertices of Person class use the special getVerticesOfClass(String className) method:

for (Vertex v : graph.getVerticesOfClass("Person")) {
    System.out.println(v.getProperty("name"));
}

All the vertices of class Person and all subclasses will be retrieved. This is because by default the polymorphism is used. If you're interested ONLY into Person vertices excluding any sub-types use the getVerticesOfClass(String className, boolean polymorphic) method specifying false in the second argument polymorphic:

for (Vertex v : graph.getVerticesOfClass("Person", false)) {
    System.out.println(v.getProperty("name"));
}

The same variants apply also to the getEdges() method as:

  • getEdgesOfClass(String className) and
  • getEdgesOfClass(String className, boolean polymorphic)

Ordered Edges

OrientDB, by default, uses Set to handle the edge collection. Sometimes it's better having an ordered List to access to the edge by offset. Example:

person.createEdgeProperty(Direction.OUT, "Photos").setOrdered(true);

Every time you access to the edge collection the edges are ordered. Below an example to print all the photos in ordered way.

for (Edge e : loadedPerson.getEdges(Direction.OUT, "Photos")) {
  System.out.println( "Photo name: " + e.getVertex(Direction.IN).getProperty("name") );
}

To access to the underlying edge list you've to use the Document Database API. Example to swap 10th photo with last one.

// REPLACE EDGE Photos
List<ODocument> photos = loadedPerson.getRecord().field("out_Photos");
photos.add(photos.remove(9));

Working on detached elements

When you work with Web Applications, it’s very common to query elements and render them to the user to let him to apply some changes. Once the user updates some fields and press the “save” button, what happens?

Before now the developer had to track the changes in a separate structure, load the vertex/edge from the database and apply the changes to the element.

Starting from OrientDB v1.7 we added 2 new methods to the Graph API against OrientElement and OrientBaseGraph classes:

  • OrientElement.detach()
  • OrientElement.attach()
  • OrientBaseGraph.detach(OrientElement)
  • OrientBaseGraph.attach(OrientElement)

Detach

Detach methods fetch all the record content in RAM and reset the connection to the Graph instance. This allow to modify the element off-line and re-attach it once finished.

Attach

Once the detached element has been modified, to be saved back to the database you need to call the attach() method. It restore back the connection between the Graph Element and the Graph Instance.

Example

The first step is load some vertex and detach them.

OrientGraph g = OrientGraph("plocal:/temp/db");
try {
    Iterable<OrientVertex> results = g.query().has("name", EQUALS, "fast");
    for (OrientVertex v : results)
        v.detach();
} finally {
    g.shutdown();
}

After a while the element is updated (from GUI or by application)

v.setProperty("name", "super fast!");

On “save” button re-attach the element and save it to the database.

OrientGraph g = OrientGraph("plocal:/temp/db");
try {
    v.attach(g);
    v.save();
} finally {
    g.shutdown();
}

FAQ

Does detach go recursively to detach all connected elements? No, it works only at the current element level.

Can I add edge against detached elements? No, you can only get/set/remove property while is detached. Any other operation that requires the database will throw an IllegalStateException.

Transactions

OrientDB supports optimistic transactions, so no lock is kept when a transaction is running, but at commit time each graph element version is checked to see if have been updated by other clients. This is the reason why you should write your code to be concurrency-proof by handling the concurrent updating case:

for (int retry = 0; retry < maxRetries; ++retry) {
    try {
        // LOOKUP FOR THE INVOICE VERTEX
        Vertex invoice = graph.getVertices("invoiceId", 2323);
        // CREATE A NEW ITEM
        Vertex invoiceItem = graph.addVertex("class:InvoiceItem");
        invoiceItem.field("price", 1000);
        // ADD IT TO THE INVOICE
        invoice.addEdge(invoiceItem);
        graph.commit();
        break;
    } catch( OTransactionException e ) {
        // SOMEONE HAVE UPDATE THE INVOICE VERTEX AT THE SAME TIME, RETRY IT
    }
}

Auto-retry

Starting from v.1.5 transactions auto retry if a timeout exception occurs. This happens in case of deadlocks or network latency. By default the AutoRetry setting is 10 but you can adjust, or disable with 0, by calling:

((OTransactionOptimistic) graph.getRawGraph().getTransaction()).setAutoRetries( 0 );

Execute commands

OrientDB Blueprints implementation allows to execute commands using SQL, Javascript and all the other supported languages.

SQL queries

for (Vertex v : (Iterable<Vertex>) graph.command(
            new OCommandSQL("select expand( out('bough') ) from Customer where name = 'Jay'")).execute()) {
    System.out.println("- Bought: " + v);
}

SQL commands

As log as queries you can execute any SQL command like CREATE VERTEX, UPDATE and DELETE VERTEX. In the example below it sets a new property called "local" to true to all the Customers lives in Rome:

int modified = graph.command(
          new OCommandSQL("UPDATE Customer SET local = true WHERE 'Rome' IN out('lives').name")).execute());

To execute asynchronous query:

graph.command(
          new OSQLAsynchQuery<Vertex>("select from Member",
            new OCommandResultListener() {
              int resultCount =0;
              @Override
              public boolean result(Object iRecord) {
                resultCount++;
                Vertex doc = graph.getVertex( iRecord );
               return resultCount < 100;
              }
            } ).execute();

SQL batch

To execute multiple SQL commands in a batch, use the OCommandScript using SQL as the language. This is recommended in case of creating edges on the server side, minimizing the network roundtrip:

String cmd = "begin\n";
cmd += "let a = create vertex set script = true\n";
cmd += "let b = select from v limit 1\n";
cmd += "let e = create edge from $a to $b retry 100\n";
cmd += "commit\n";
cmd += "return $e";

OIdentifiable edge = graph.command(new OCommandScript("sql", cmd)).execute();

For more information look at SQL Batch.

Database functions

To execute a database function, written in Javascript or any other supported languages. In the example below we imagine to have written the function updateAllTheCustomersInCity(cityName) that execute the same update like above. Note the 'Rome' attribute passed in execute() method:

graph.command(
          new OCommandFunction("updateAllTheCustomersInCity")).execute("Rome"));

Code

To execute code at the server side you can select between the supported language (by default Javascript):

graph.command(
          new OCommandScript("javascript", "for(var i=0;i<10;++i){ print('\nHello World!'); }")).execute());

This prints 10 times the line "Hello World!" in the server console, or in the local console if the database has been open in "plocal" mode.

Access to the underlying Graph

Since TinkerPop Blueprints API is quite raw and doesn't provide ad-hoc methods for very common use cases you could need to access to the underlying ODatabaseGraphTx object to better use the graph-engine under the hood. Commons operations are:

  • Count incoming and outgoing edges without browsing them all
  • Get incoming and outgoing vertexes without browsing the edges
  • Execute a query using SQL-like language integrated in the engine

The OrientGraph class provides the method .getRawGraph() to return the underlying database: [Document Database].

Example:

final OrientGraph graph = new OrientGraph("plocal:C:/temp/graph/db");
try {
  List<ODocument> result = graph.getRawGraph().query(
                                   new OSQLSynchQuery("select from V where color = 'red'"));
} finally {
  graph.shutdown();
}

Security

If you want to use the OrientDB security, use the constructor that retrieves the URL, user and password. To know more about OrientDB security visit Security. By default the "admin" user is used.

Tuning

Look at the Performance Tuning Blueprints page.