OrientDB Manual
OrientDB Manual
OrientDB Manual
Past releases:
v1.7.8
Welcome to OrientDB - the first Multi-Model Open Source NoSQL DBMS that brings
together the power of graphs and the flexibility of documents into one scalable, high-
performance operational database. OrientDB is sponsored by Orient Technologies, LTD.
OrientDB has features of both Document and Graph DBMSs. Written in Java and
designed to be exceptionally fast: it can store up to 220,000 records per second on
common hardware. Not only can it embed documents like any other Document
database, but it manages relationships like Graph Databases with direct connections
among records. You can traverse parts of or entire trees and graphs of records in a few
milliseconds.
To learn some key advantages of using OrientDB, take a look at Why OrientDB?
2
Is OrientDB really FREE?
OrientDB is free for any use including commercial with its Apache 2 Open Source
License.
3
OrientDB Community
Start learning about OrientDB with the OrientDB Manual. For any questions, visit the
OrientDB Community Group. Need help? Go to Online Support. Do you want to hear
about OrientDB at a conference or meetup? Take a look at Events.
4
Need Further Assistance?
If you have any questions or need assistance with OrientDB, please let us know. Check
out our Get in Touch page for different ways of getting in touch with us.
Every effort has been made to ensure the accuracy of this manual. However, Orient
Technologies, LTD. makes no warranties with respect to this documentation and
disclaims any implied warranties of merchantability and fitness for a particular purpose.
The information in this document is subject to change without notice.
5
Getting Started
In the last few years, there's been an explosion of many NoSQL solutions and products.
The meaning of the word "NoSQL" is not a campaign against the SQL language. In fact,
OrientDB allows for SQL syntax! NoSQL is probably best described by the following:
Alternatives to relational database management systems have existed for many years,
but they have been relegated primarily to niche use cases such as telecommunications,
medicine, CAD and others. Interest in NoSQL alternatives like OrientDB is increasing
dramatically. Not surprisingly many of the largest web companies like Google, Amazon,
Facebook, Foursquare, and Twitter are using NoSQL based solutions in production
environments.
What motivates companies to leave the comfort of a well established relational database
world? It all surrounds the fact that you can better solve today's data problems with a
modern database. Specifically, there are a few key areas:
Performance
Scalability (often extreme)
Smaller footprint
Developer productivity
Schema flexibility
Most of these areas also happen to be requirements of modern web applications. A few
years ago, developers designed systems that could handle hundreds of concurrent
users. Today it is not uncommon to have a potential target of thousands or millions of
users connected and served at the same time.
Changing technology requirements have been taken into account on the application front
by creating frameworks, introducing standards and leveraging best practices. However,
in the database world, the situation has remained more or less the same for over 30
years. From the 1970s until recently, relational DBMSs have played the dominant role.
Programming languages and methodologies have evolved, but the concept of data
persistence and DBMS have remained unchanged for the most part: tables, records and
joins.
6
NoSQL Models
NoSQL-based solutions in general provide a powerful, scalable, and flexible way to
solve data needs and use cases which have previously been managed by relational
databases. To summarize the NoSQL options, we'll examine the most common models
or categories:
Key / Value databases: data model is reduced to a simple hash table which
consists of key / value pairs. It is often easily distributed across multiple servers.
The most recognized products of this group include Redis, Dynamo, and Riak.
Column-oriented databases: data is stored in sections of columns offering more
flexibility and easy aggregation. Facebook's Cassandra, Google's BigTable, and
Amazon's SimpleDB are some examples of column-oriented databases.
Document databases: data model consists of document collections where
individual documents can have multiple fields without necessarily defining a
schema. The best known products of this group are MongoDB and CouchDB.
Graph databases: domain model consists of vertices interconnected by edges
creating a rich graph structure. The best known products of this group are OrientDB
and Neo4j.
Each of these categories or models has its own peculiarities, strengths and limitations.
There is not a single category or model which is better than all the others, however
certain types of databases are better at solving specific problems. This leads to the
motto of NoSQL: choose the best tool for your specific use case.
The goal of Orient Technologies in building OrientDB was to create a robust, highly
performant database that can perform optimally in the widest possible set of use cases.
Our product is designed to be the best "go to" solution for data persistence. In the
following parts of this tutorial, we will look closely at OrientDB, the original open-source,
multi-model, next generation NoSQL product.
7
Multi-Model
The OrientDB engine supports Graph, Document, Key/Value, and Object models, so
you can use OrientDB as a replacement for a product in any of these categories.
However the main reason why users choose OrientDB is its ability to act as a true Multi-
Model DBMS by combining all the features of the four models into one. These are not
just interfaces to the database engine, but the engine, itself, was built to support all four
models. This is also the main difference with other DBMSs that claim to be Multi-Model
since they just implement an additional layer with an API that mimics additional models,
but under the hood they're truly one model therefore limiting speed and scalability.
8
Document Model
The data in this model is stored inside documents. A document is a set of key/value
pairs (also referred to as fields or properties) where a key allows access to its value.
Values can hold primitive data types, embedded documents, or arrays of other values.
Documents are not typically forced to have a schema which can be a benefit because
they remain flexible and easy to modify. Documents are stored in collections enabling
developers to group data as they decide. OrientDB uses the concepts of "classes" and
"clusters" instead of "collections" for grouping documents. This provides several benefits
that we will discuss in further sections of the documentation. OrientDB's Document
model adds the concept of a "LINK" as a relationship between documents. With
OrientDB you can decide whether to embed documents or link to them directly. When
you fetch the document all the links are automatically resolved by OrientDB. This is the
most important difference with any other Document Database like MongoDB.
The table below illustrates the comparison between the relational model, the document
model, and the OrientDB document model:
9
Graph Model
A graph represents a network-like structure consisting of Vertices (also known as
Nodes) interconnected by Edges (also known as Arcs). OrientDB's graph model is
represented by the concept of a property graph, which defines the following:
Vertex - an entity that can be linked with other Vertices and has the following
mandatory properties:
unique identifier
set of incoming Edges
set of outgoing Edges
Edge - an entity that links two Vertices and has the following mandatory properties:
unique identifier
link to incoming Vertex (also known as head)
link to outgoing Vertex (also known as tail)
label that defines the type of connection/relationship between head and tail
vertex
In addition to mandatory properties, each vertex or edge can also hold a set of custom
properties. These properties can be defined by users, which can make vertices and
edges appear similar to documents. In the table below, you can find a comparison
between the graph model, the relational data model, and the OrientDB graph model:
Relational
Model Graph Model OrientDB Graph Model
Vertex and Edge Class that extends "V" (for Vertex) and
Table
Class "E" (for Edges)
10
Key/Value Model
This is the simplest model of the three. Everything in the database can be reached by a
key, where the values can be simple and complex types. OrientDB supports Documents
and Graph Elements as values allowing a richer model than the classic Key/Value one.
The Key/Value model provides "buckets" to group key/value pairs in different containers.
The most classic use cases with Key/Value Model are:
The table below illustrates the comparison between the relational model, the Key/Value
model, and the OrientDB Key/Value model:
11
Object Model
This model has been inherited by Object Oriented programming and supports
Inheritance between types (sub-types extends the super-types), Polymorphism when
you refer to a base class, and Direct binding from/to Objects used in programming
languages.
The table below illustrates the comparison between the relational model, the Object
model, and the OrientDB Object model:
12
Installation
OrientDB is available in two editions:
Community Edition This edition is released as an open source project under the
Apache 2 license. This license allows unrestricted free usage for both open source
and commercial projects.
Enterprise Edition OrientDB Enterprise edition is commercial software built on top
of the Community Edition. Enterprise is developed by the same team that developed
the OrientDB engine. It serves as an extension of the Community Edition by
providing Enterprise features such as:
Query Profiler
Distributed Clustering configuration
Metrics Recording
Live Monitoring with configurable Alerts
Prerequisites
Both editions run on every operating system that has an implementation of the Java
Virtual Machine (JVM), for example:
This means the only requirement for using OrientDB is to have Java version 1.6 or
higher installed.
Download Binaries
The easiest and fastest way to start using OrientDB is to download binaries from the
Official OrientDB Download Page.
13
Alternatively, you can clone the Community Edition project from GitHub and compile it.
This allows you access to the latest functionality without waiting for a distribution binary.
To build the Community Edition, you must first install the Apache Ant tool and follow
these steps:
After the compilation, all the binaries are placed under the ../releases directory.
Change Permissions
The Mac OS X, Linux, and UNIX based operating systems typically require you to
change the permissions to execute scripts. The following command will apply the
necessary permissions for these scripts in the bin directory of the OrientDB distribution:
Other Resources
To learn more about how to install OrientDB on specific environments, please refer to
the guides below:
14
Install with Docker
Install on Linux Ubuntu
Install on JBoss AS
Install on GlassFish
Install on Ubuntu 12.04 VPS (DigitalOcean)
Install on Vagrant
15
Run the server
After you have downloaded the binary distribution of OrientDB and unpacked it, you are
now able to start the server. This is done by executing server.sh (or server.bat on
Windows) located in bin directory:
> cd bin
> ./server.sh
.
.` `
, `:.
`,` ,:`
.,. :,,
.,, ,,,
. .,.::::: ````
,` .::,,,,::.,,,,,,`;; .:
`,. ::,,,,,,,:.,,.` ` .:
,,:,:,,,,,,,,::. ` ` `` .:
,,:.,,,,,,,,,: `::, ,, ::,::` : :,::` ::::
,:,,,,,,,,,,::,: ,, :. : :: : .:
:,,,,,,,,,,:,:: ,, : : : : .:
` :,,,,,,,,,,:,::, ,, .:::::::: : : .:
`,...,,:,,,,,,,,,: .:,. ,, ,, : : .:
.,,,,::,,,,,,,: `: , ,, : ` : : .:
...,::,,,,::.. `: .,, :, : : : .:
,::::,,,. `: ,, ::::: : : .:
,,:` `,,.
,,, .,`
,,. `, S E R V E R
`` `.
``
`
The log messages explain what happens when the server starts:
16
know more about this step, look into OrientDB Server
2. By default, a "temp" database is always loaded into memory. This is a volatile
database that can be used to store temporary data
3. Binary connections are listening on port 2424 for all configured networks (0.0.0.0). If
you want to change this configuration edit the config/orientdb-server-config.xml file
and modify port/ip settings
4. HTTP connections are listening on port 2480 for all configured networks (0.0.0.0). If
you want to change this configuration edit the config/orientdb-server-config.xml file
and modify port/ip settings
OrientDB server listens on 2 different ports by default. Each port is dedicated to binary
and HTTP connections respectively:
binary port is used by the console and clients/drivers that support the network
binary protocol
HTTP port is used by OrientDB Studio web tool and clients/drivers that support the
HTTP/REST protocol or tools like CURL
17
Run the console
OrientDB provides a command line interface. It can be used to connect to and work with
remote or local OrientDB servers.
You can start the command line interface by executing console.sh (or console.bat on
Windows) located in the bin directory:
> cd bin
> ./console.sh
orientdb>
Type the "help" or "?" command to see all available console commands:
orientdb> help
AVAILABLE COMMANDS:
Some console commands such as list databases or create database can be run while
only connected to a server instance (you do not have to be connected to a database).
Other commands require you to be connected to a database. Before you can connect to
a fresh server instance and fully control it, you need to know the root password. The root
password is located in config/orientdb-server-config.xml (just search for the users
element). If you want to change it, modify the XML file and then restart the server.
If you have the required credentials, you should now be able to connect using the
following command:
18
orientdb> connect remote:localhost root someUglyPassword
Connecting to remote Server instance [remote:localhost] with user 'root'...OK
Next, you can (for example) list databases using the command:
Found 1 databases:
* GratefulDeadConcerts (plocal)
To connect to another database we can again use the connect command from the
console and specify the server URL, username, and password. By default each
database has an "admin" user with password "admin" (change the default password on
your real database). To connect to the GratefulDeadConcerts database on the local
server execute the following:
Let's analyze the URL we have used: remote:localhost/GratefulDeadConcerts . The first part
is the protocol, "remote" in this case, which contacts the server using the TCP/IP
protocol. "localhost" is the host name or IP address where the server resides; in this
case it is on the same machine. "GratefulDeadConcerts" is the name of the database to
which we want to connect.
For more detailed information about the commands see the console page.
19
Classes
It's easier to introduce OrientDB's basic concepts by outlining the Document Database
API. It is more similar to Relational DBMS concepts and therefore a little more natural to
follow for many developers. These basic concepts are shared between all of OrientDB's
APIs: Document, Object, and Graph.
As with the relational DBMS, OrientDB has the concept of records as an element of
storage. There are different types of records, but for the next examples we will always
use the document type. A document is composed of attributes and can belong to one
class. Going forward we will also refer to the attributes with the terms "fields" and
"properties".
The concept of class is well known to those who program using object-oriented
languages. Classes are also used in OrientDB as a type of data model according to
certain rules. To learn more about Classes in general take a look at Wikipedia.
To list all the configured classes, type the classes command in the console:
orientdb> classes
CLASSES:
----------------------------------------------+---------------------+-----------+
NAME | CLUSTERS | RECORDS |
----------------------------------------------+---------------------+-----------+
AbstractPerson | -1 | 0 |
Account | 11 | 1126 |
Actor | 91 | 3 |
Address | 19 | 166 |
Animal | 17 | 0 |
.... | .... | .... |
Whiz | 14 | 1001 |
----------------------------------------------+---------------------+-----------+
TOTAL 22775 |
--------------------------------------------------------------------------------+
20
However, properties are mandatory if you define indexes or constraints. To create a new
property use the create property command. Here is an example of creating three
properties against the Student class:
Class................: Student
Default cluster......: student (id=96)
Supported cluster ids: [96]
Properties:
-------------------------------+-------------+-------------------------------+-----------+----------+----
NAME | TYPE | LINKED TYPE/CLASS | MANDATORY | READONLY | NOT
-------------------------------+-------------+-------------------------------+-----------+----------+----
birthDate | DATE | null | false | false | fal
name | STRING | null | false | false | fal
surname | STRING | null | false | false | fal
-------------------------------+-------------+-------------------------------+-----------+----------+----
To add a constraint, use the alter class command. For example, let's specify that the
name field should be at least 3 characters:
To see all the records in a class, use the browse class command:
21
In this case we are listing all of the users of the database. This is not particularly secure.
You should further deepen the OrientDB security system, but for now OUser is a class
like any other. For each query the console always shows us the number of the records in
the result set and the record's ID.
---+---------+--------------------+--------------------+--------------------+--------------------
#| RID |name |password |status |roles
---+---------+--------------------+--------------------+--------------------+--------------------
0| #5:0|admin |{SHA-256}8C6976E5B5410415BDE908BD4DEE15DFB167A9C873FC4BB8A81F6F2AB448A
1| #5:1|reader |{SHA-256}3D0941964AA3EBDCB00CCEF58B1BB399F9F898465E9886D5AEC7F31090A0F
2| #5:2|writer |{SHA-256}B93006774CBDD4B299389A03AC3D88C3A76B460D538795BC12718011A909F
---+---------+--------------------+--------------------+--------------------+--------------------
The first column is a number used as an identifier to display the record's detail. To show
the first record in detail, it is necessary to use the display record command with the
number of the record, in this case 0:
22
Clusters
We've already talked about classes. A class is a logical concept in OrientDB. Clusters
are also an important concept in OrientDB. Records (or documents/vertices) are stored
in clusters.
23
What is a cluster?
A cluster is a place where a group of records are stored. Perhaps the best equivalent in
the relational world would be a Table. By default, OrientDB will create one cluster per
class. All the records of a class are stored in the same cluster which has the same name
as the class. You can create up to 32,767 (2^15-1) clusters in a database.
Understanding the concepts of classes and clusters allows you to take advantage of the
power of clusters while designing your new database.
Even though the default strategy is that each class maps to one cluster, a class can rely
on multiple clusters. You can spawn records physically in multiple places, thereby
creating multiple clusters. For example:
The default cluster (in this case, the USA_customers cluster) is used by default when the
generic class "Customer" is used. Example:
24
When querying the "Customer" class, all the involved clusters are scanned:
If you know the location of a customer you're looking for you can query the target cluster
directly. This avoids scanning the other clusters and optimizes the query:
25
To add a new cluster to a class, use the ALTER CLASS command. To remove a cluster
use REMOVECLUSTER in ALTER CLASS command. Example to create the cluster
"USA_Customers" under the "Customer" class:
faster queries against clusters because only a sub-set of all the class's clusters
must be searched
good partitioning allows you to reduce/remove the use of indexes
parallel queries if on multiple disks
sharding large data sets across multiple disks or server instances
For most cases physical clusters are preferred because the database must be
26
persistent. OrientDB creates physical clusters by default so you don't have to worry too
much about it for now.
To view all clusters, from the console run the clusters command:
orientdb> clusters
CLUSTERS:
----------------------------------------------+------+---------------------+-----------+
NAME | ID | TYPE | RECORDS |
----------------------------------------------+------+---------------------+-----------+
account | 11| PHYSICAL | 1107 |
actor | 91| PHYSICAL | 3 |
address | 19| PHYSICAL | 166 |
animal | 17| PHYSICAL | 0 |
animalrace | 16| PHYSICAL | 2 |
.... | ....| .... | .... |
----------------------------------------------+------+---------------------+-----------+
TOTAL 23481 |
---------------------------------------------------------------------------------------+
Since by default each class has its own cluster, we can query the database's users by
class or by cluster:
---+---------+--------------------+--------------------+--------------------+--------------------
#| RID |name |password |status |roles
---+---------+--------------------+--------------------+--------------------+--------------------
0| #5:0|admin |{SHA-256}8C6976E5B5410415BDE908BD4DEE15DFB167A9C873FC4BB8A81F6F2AB448A
1| #5:1|reader |{SHA-256}3D0941964AA3EBDCB00CCEF58B1BB399F9F898465E9886D5AEC7F31090A0F
2| #5:2|writer |{SHA-256}B93006774CBDD4B299389A03AC3D88C3A76B460D538795BC12718011A909F
---+---------+--------------------+--------------------+--------------------+--------------------
The result is identical to browse class ouser executed in the classes section because
there is only one cluster for the OUser class in this example.
The strategy where OrientDB selects the cluster when inserts a new record is
configurable and pluggable. For more information take a look at Cluster Selection.
27
Record ID
In OrientDB each record has its own self-assigned unique ID within the database called
Record ID or RID. It is composed of two parts:
#<cluster-id>:<cluster-position>
cluster-id is the id of the cluster. Each database can have a maximum of 32,767
clusters (2^15-1)
cluster-position is the position of the record inside the cluster. Each cluster can
handle up to 9,223,372,036,854,780,000 (2^63) records, namely 9,223,372 Trillion
of records!
A RID (Record ID) is the physical position of the record inside the database. This means
that loading a record by its RID is blazing fast, even with a growing database. With
document and relational DBMS the more data you have, the slower the database will be.
Joins have a heavy runtime cost. OrientDB handles relationships as physical links to the
records. The relationship is assigned only once when the edge is created O(1). Compare
this to an RDBMS that computes the relationship every single time you query a
database O(LogN). Traversing speed is not affected by the database size in OrientDB. It
is always constant, whether for one record or 100 billion records. This is critical in the
age of Big Data!
To load a record directly via the console, use the load record command. Below, we load
the record #12:4 of the "demo" database.
28
salary2 : 0.0
checkpoint : true
created : Sat Dec 29 23:13:49 CET 2012
The load record command returns some useful information about this record:
It's a document. OrientDB supports different types of records. This tutorial covers
documents only.
The class is "Company"
The current version is 8. OrientDB has a MVCC system. It will be covered at a later
point. Just know that every time you update a record its version is incremented by 1.
We have different field types: "salary" and "salary2" are floats, "employees" and "id"
are integers, "name" is a string, "initialized" and "checkpoint" are booleans and
"created" is a date-time
The field "addresses" has been NOT LOADED. It is also a LINK to another record
#19:159. This is a relationship. (More explanation to follow)
29
SQL
Most NoSQL products have a custom query language. OrientDB focuses on standards
when it comes to query languages. Instead of inventing "Yet Another Query Language",
we started from the widely used and well understood SQL. We then extended it to
support more complex graph concepts like Trees and Graphs. Why SQL? SQL
ubiquitous in the database developer world, it is familiar. Also, it is more readable and
concise than Map Reduce scripts.
Select
To start, let's write a query that returns the same result as the previous browse cluster
ouser and browse class ouser :
This query has no projections. This stands for "the entire record" like using the star
(*).
OUser is a class. By default queries are executed against classes.
an index, by prefixing with "index:". For example: select value from index:dictionary
where key = 'Jay'
Similar to standard SQL, OrientDB supports WHERE conditions to filter the returning
records by specifying one or more conditions. For example:
Returns all OUser records where the name starts with 'l'. For more information, look at all
the supported operators and functions: SQL-Where.
30
OrientDB also supports the ORDER BY clause to order the result set by one or more fields.
For example:
select from Employee where city = 'Rome' order by surname asc, name asc
This will return all of the Employees who live in Rome, ordered by surname and name in
ascending order. You can also use the GROUP BY clause to group results. For example:
This returns the sum of the salaries of all the employees with age under 40 grouped by
job type. To limit the result set you can use the LIMIT keyword. For example, to limit the
result set to maximum of 20 items:
Thanks to the SKIP keyword you can easily manage pagination. Use SKIP to pass over
records from the result set. For example, to divide the result set in 3 pages you could do
something like:
Now that we have the basic skills to execute queries, let's discuss how to manage
relationships.
Insert
insert into Employee (name, surname, gender) values ('Jay', 'Miner', 'M')
31
insert into Employee set name = 'Jay', surname = 'Miner', gender = 'M'
Since OrientDB was created for the web, it can natively ingest JSON data:
insert into Employee content {name : 'Jay', surname : 'Miner', gender : 'M'}
Update
Also using JSON with the "merge" keyword to merge the input JSON with current record:
Delete
32
Relationships
The most important feature of a graph database is the management of relationships.
Many users come to OrientDB from MongoDB or other document databases because
they lack efficient support of relationships.
33
Relational Model
The relational model (and RDBMS - relational database management systems) has long
been thought to be the best way to handle relationships. Graph databases suggest a
more modern approach to this topic.
Most database developers are familiar with the relational model given it's 30+ years of
dominance, spreading over generations of developers. Let's review how these systems
manage relationships. As an example, we will use the relationships between the
Customer and Address tables.
1-to-1 relationship
RDBMSs store the value of the target record in the "address" column of the Customer
table. This is called a foreign key. The foreign key points to the primary key of the
related record in the Address table:
To retrieve the address pointed to by customer "Luca", the query in a RDBMS would be:
SELECT B.location FROM Customer A, Address B WHERE A.name = 'Luca' AND A.address = B.id
34
This is a JOIN! A JOIN is executed at run-time every time you retrieve a relationship.
1-to-Many relationship
Since RDBMS have no concept of collections the Customer table cannot have multiple
foreign keys. The way to manage a 1-to-Many relationship is by moving the foreign key
to the Address table.
SELECT B.location FROM Customer A, Address B WHERE A.name = 'Luca' AND B.customer = A.id
Many-to-Many relationship
The most complex case is the Many-to-Many relationship. To handle this type of
association, RDBMSs need a separate, intermediary table that matches both Customer
and Addresses in all required combinations. This results in a double JOIN per record at
runtime;
35
To extract all addresses of Customer 'Luca's the query in RDBMS becomes:
SELECT B.location FROM Customer A, Address B, CustomerAddress C WHERE A.name = 'Luca' AND B.id = A.id
With document and relational DBMS, the more data you have, the slower the database
will perform. Joins have heavy runtime costs. In comparison, OrientDB handles
relationships as physical links to the records, assigned only once when the edge is
created O(1). Compare this to an RDBMS that computes the relationship every single
time you query a database O(LogN). With OrientDB, speed of traversal is not affected by
the database size. It is always constant regardless if it has one record or 100 billion
records. This is critical in the age of Big Data.
Searching for an ID at runtime each time you execute a query, for every record could be
very expensive! The first optimization with RDMS is using indexes. Indexes speed up
searches but they slow down INSERT , UPDATE and DELETE operations. In addition, they
occupy substantial space on disk and in memory. You also need to qualify - are you sure
the lookup into an index is actually fast? Let's try to understand how indexes work.
36
The database industry has plenty of indexing algorithms. The most common in both
Relational and NoSQL DBMS is the B+Tree. All balanced trees work in similar ways.
Here is and example of how it would work when you're looking for "Luca": after only 5
hops the record is found.
But what if there were millions or billions of records? There would be many, many more
hops. And this operation is executed on every JOIN per record! Imagine joining 4 tables
with thousands of records: the number of JOINS could be in the millions!
37
Relations in OrientDB
OrientDB doesn't use JOINs. Instead it uses LINKs. A LINK is a relationship managed by
storing the target RID in the source record. It's much like storing a pointer between 2
objects in memory. When you have Invoice -> Customer, then you have a pointer to
Customer inside Invoice as an attribute. It's exactly the same. In this way it's like your
database was in memory, a memory of several exabytes.
38
Working with Graphs
We already met the Graph Model a few pages ago. Now we have all the basic
knowledge needed to work with OrientDB as a GraphDB! This requires the graph edition
of OrientDB. Connect to the GratefulDeadConcerts database for experimentation. It
contains the concerts performed by the "Grateful Dead" band.
OrientDB comes with a generic Vertex persistent class called "V" (OGraphVertex in
previous releases) and "E" (OGraphEdge in the past) for Edge. You can create a new
Vertex with:
In effect, the GraphDB model works on top of the underlying Document model, so all the
stuff you have learned until now (Records, Relationships, etc.) remains valid. But in
order to simplify the management of the graph we've created special commands, so
don't use the SQL Insert command anymore to create a new vertex. Instead, use the ad-
hoc "create vertex" command:
By using graph commands, OrientDB takes care of ensuring that the graph remains
always consistent. All the Graph commands are:
CREATE VERTEX
DELETE VERTEX
CREATE EDGE
DELETE EDGE
Even though you can work with Vertices and Edges, OrientDB provides the possibility to
extend the V and E classes. The pros of this approach are:
39
better understanding about meaning of entities
optional constraints at class level
performance: better partitioning of entities
object-oriented inheritance among graph elements
So from now on, we will avoid using plain V and E and will always create custom
classes. Let's develop an example graph to model a social network based on
restaurants:
Now that the schema has been created let's populate the graph with some vertices:
Before we connect them using edges, let's go create a new Edge type:
This will represent the relationship from Person to Restaurant. The orientation is
important when you create an edge because it gives the meaning of the relationship. If
we wanted to model the edge in the opposite orientation, from Restaurant to Person, we
might call the Edge class "Attendee", or something similar.
Now let's create a connection between person "Luca" and restaurant "Dante":
orientdb> create edge Eat from (select from Person where name = 'Luca') to (select from Restaurant where
40
If you know the RID of vertices you can connect them with a shorter and faster
command. Below we will connect "Bill" with the same "Dante" Restaurant and 'Jay' to
'Charlie' Restaurant:
Now that our small graph has been created let's play with queries. To cross edges we
can use special graph functions like:
To know all the people who eat in the "Dante" restaurant (RID = #12:0), we can get
Dante's record and then traverse the incoming edges to discover the Person records
connected:
+-------+----------------+
| @RID | in |
+-------+----------------+
| #-2:1 | [#11:0, #11:1] |
+-------+----------------+
Those are the RIDs of the Person instances connected. In these cases the expand()
special function becomes very useful to transform the collection of vertices in the
resultset by expanding it:
+-------+-------------+-------------+---------+
| @RID | @CLASS | Name | out_Eat |
+-------+-------------+-------------+---------+
| #11:0 | Person | Luca | #12:0 |
| #11:1 | Person | Bill | #12:0 |
+-------+-------------+-------------+---------+
Much better! Now let's create the new relationship "Friend" to connect people:
41
orientdb> create class Friend extends E
"Friend" relationship is one of these edge types where the orientation is not important: if
"Luca" is a friend of "Jay" the opposite is usually true, so the orientation looses
importance. To discover Luca's friends, we should use the both() function:
+-------+-------------+-------------+---------+-----------+
| @RID | @CLASS | Name | out_Eat | in_Friend |
+-------+-------------+-------------+---------+-----------+
| #11:2 | Person | Jay | #12:1 | #11:0 |
+-------+-------------+-------------+---------+-----------+
In this case I've passed the Edge's class "Friend" as argument of the both() function to
cross only the relationships of kind "Friend" (so skip the "Eat" this time). Note also in the
result set that the relationship with "Luca" (RID = #11:0) is in the "in_" field.
Now let's make things more complicated. Get all the restaurants where Luca's friends
go.
+-------+-------------+-------------+-------------+---------+
| @RID | @CLASS | Name | Type | in_Eat |
+-------+-------------+-------------+-------------+---------+
| #12:1 | Restaurant | Charlie | French | #11:2 |
+-------+-------------+-------------+-------------+---------+
42
Lightweight edges
Starting from OrientDB v1.4.x edges, by default, are managed as lightweight edges:
they don't have own identities as record, but are physically stored as links inside
vertices. OrientDB automatically uses Lightweight edges only when edges have no
properties, otherwise regular edges are used. From the logic point of view, lightweight
edges are edges at all the effects, so all the graph functions work correctly. This is to
improve performance and reduce the space on disk. But as a consequence, since
lightweight edges don't exist as separate records in the database, the following query will
not return the lightweight edges:
SELECT FROM E
In most of the cases Edges are used from Vertices, so this doesn't cause any particular
problem. In case you need to query Edges directly, even those with no properties,
disable lightweight edge feature by executing this command once:
This will only take effect for new edges. For more information look at:
https://github.com/orientechnologies/orientdb/wiki/Troubleshooting#why-i-cant-see-all-
the-edges.
43
Using Schema with Graphs
OrientDB is a Graph Database "on steroids" because it supports concepts taken from
both the Document Database and Object-Oriented worlds. This Tutorial step shows the
power of Graphs used in conjunction with schema and constraints.
Take a look at this use case: Creating a graph to map the relationships between Person
and Cars.
Let's open a shell (or command prompt in Windows) and launch the OrientDB Console
(use console.bat on Windows):
> cd $ORIENTDB_HOME/bin
> ./console.sh
Now we're going to use the console to create a brand new local database:
Ok, now let's create the first graph schema with "Person" and "Car" as 2 new Vertex
types and "Owns" as an Edge type:
And let's go populate the database with the first Graph elements:
orientdb> create edge Owns from (select from Person) to (select from Car)
44
Ok, now we can traverse vertices. For example, what is Luca's car? Traverse from Luca
vertex to the outgoing vertices following the "Owns" relationships:
orientdb> select name from ( select expand( out('Owns') ) from Person where name = 'Luca' )
----+-----+--------------
# |@RID |name
----+-----+--------------
0 |#-2:1|Ferrari Modena
----+-----+--------------
Perfect. Now we want to have the location of each Person. We need another Vertex type
called "Country" to connect to the Person with a new "Lives" Edge type:
orientdb> create edge Lives from (select from Person) to (select from Country)
So far so good. Our graph has been extended. Now, try to search the country where
there are "Ferrari" cars in our database.
orientdb> select name from ( select expand( in('Owns').out('Lives') ) from Car where name like '%Ferrari%
----+-----+----
# |@RID |name
----+-----+----
0 |#-2:1|UK
----+-----+----
45
Setting constraints on Edges
Now we've modeled our graph using a schema without any constraints. But it would be
useful to require an Owns relationship to exist only between the Person and Car
vertices. So, let's create these constraints:
The MANDATORY setting against a property prevents OrientDB from using a lightweight
edge (no physical document is created). Be sure to pay attention and not put spaces
between MANDATORY=true .
If we want to prohibit a Person vertex from having 2 edges against the same Car vertex,
we have to define a UNIQUE index against out and in properties.
Unfortunately, the index tells us 0 entries are indexed. Why? We have already created
the Owns relationships between "Luca" and "Ferrari Modena." In that case, OrientDB
had already created a lightweight edge before we set the rule to force creation
documents for Owns instances. So, you need to drop and recreate the edge.
----+-----+-----+-----
# |@RID |out |in
----+-----+-----+-----
46
0 |#13:0|#11:0|#12:0
----+-----+-----+-----
So far so good. The constraints works. Now try to create a "Owns" edge between Luca
and UK (Country vertex):
orientdb> create edge Owns from (select from Person) to (select from Country)
47
Setup a Distributed Database
OrientDB can run in a Distributed Architecture by sharing a database across multiple
server instances.
For the purpose of this tutorial we're going to run 2 servers. There are 2 ways to share
the same database across multiple nodes:
Prior to startup, the database directory must be copied to all the servers. Copy &
Paste-ing the database directory under the "databases" folder is enough.
Alternately, keep the database on the first node running. The default configuration
automatically shares the database with new servers that join.
48
Start the first server node
To start OrientDB in distributed mode, don't use bin/server.sh (or .bat on Windows),
but rather the bin/dserver.sh (or bin/dserver.bat ) script:
> cd bin
> ./dserver.sh
Note that the configuration file isn't orientdb-server-config.xml but the distributed version
of it: orientdb-dserver-config.xml . For more information, look at Distributed Configuration.
49
}
}
By reading the last piece of log we should notice that by default the nodeId is empty in
config/orientdb-dserver-config.xml , so it's automatically assigned to random value:
"node1383734730415" in this case. You should set a more familiar name like "europe0"
or "production1".
Upon starting, OrientDB loads all the databases in the "databases" directory and
configures them to run in distributed mode. For this reason, on the first load the default
distributed configuration contained in config/default-distributed-db-config.json is copied
into the database's directory. On subsequent starts, the file
databases/GratefulDeadConcerts/default-distributed-db-config.json will be used instead of
default configuration. This is because the shape of the cluster of servers changes every
time nodes join or leave, and the configuration is kept updated by OrientDB on each
server node.
To know more about the meaning of the configuration contained in the config/default-
distributed-db-config.json file look at Distributed Configuration.
50
Start the second server node
Now start the second server like the first one. Make sure that both servers have the
same Hazelcast's credentials to join the same cluster in the config/hazelcast.xml file. The
fastest way to do this is to copy & paste the OrientDB directory from the first node to the
other ones. If you run multiple server instances in the same host (makes sense only for
testing purpose) remember to change the port in config/hazelcast.xml .
Once the other node is online, both nodes see each other and dump a message like this:
In this case 2 server nodes were started on the same machine (ip=10.37.129.2), but with
2 different ports (2434 and 2435 where the current is "this"). The rest of the log is relative
51
to the distribution of the database to the second server.
This means that the database "GratefulDeadConcerts" has been correctly installed from
the first node (node1383734730415) through the network.
52
Working with Distributed Graphs
Once a server has joined the distributed cluster, all the clients are constantly notified
about it so that in case of failure they will switch transparently to the next available
server. Check this by using the console. When OrientDB runs in distributed
configuration, the current cluster shape is visible with the info command.
$ cd bin
$ ./console.sh
Cluster configuration:
{
"members":[{
"name":"node1384015873680",
"listeners":[{"protocol":"ONetworkProtocolBinary","listen":"192.168.1.179:2425"},{"protocol
"id":"3bba4280-b285-40ab-b4a0-38788691c4e7",
"startedOn":"2013-11-09 17:51:13",
"databases":[]
},{
"name":"node1383734730415",
"listeners":[{"protocol":"ONetworkProtocolBinary","listen":"192.168.1.179:2424"},{"protocol
"id":"5cb7972e-ccb1-4ede-bfda-c835b0c2e5da",
"startedOn":"2013-11-09 17:30:56",
"databases":[]
}],
"localName":"_hzInstance_1_orientdb",
"localId":"5cb7972e-ccb1-4ede-bfda-c835b0c2e5da"
}
Now let's create a new vertex by connecting with the console against Node1:
53
Now from another shell (Command Prompt on Windows) connect to the node2 and
execute this command:
The vertex has been correctly replicated on Node2. Cool! Now kill the node1 process.
You will see these messages in the console of node2:
Node2 recognizes that Node1 is unreachable. Let's see if the console connected to the
node1 reports the failure. Test it by executing a query:
WARN Caught I/O errors from /192.168.1.179:2425 (local socket=0.0.0.0/0.0.0.0:51512), trying to reconnect
WARN Connection re-acquired transparently after 30ms and 1 retries: no errors will be thrown at applicati
----+----+--------------+---------+------------+----+---------------+--------------+-----------+---------
# |@RID|name |song_type|performances|type|out_followed_by|out_written_by|out_sung_by|in_follow
----+----+--------------+---------+------------+----+---------------+--------------+-----------+---------
1 |#9:1|HEY BO DIDDLEY|cover |5 |song|[5] |#9:7 |#9:8 |[4]
2 |#9:2|IM A MAN |cover |1 |song|[2] |#9:9 |#9:9 |[2]
----+----+--------------+---------+------------+----+---------------+--------------+-----------+---------
Wow! The console auto switched to the next available node2. The warning reports that
everything happens in a transparent way, so the application doesn't need to manage
this.
Now, from the console connected to the Node2, create a new vertex:
54
orientdb> create vertex V set node = 2
Created vertex 'V#9:816{node:2} v1' in 0,014000 sec(s).
The operation has been journaled to be synchronized to the Node1 once it comes online
again. Now let's restart Node1 and see if auto re-alignment succeeds. Connect with the
console against Node1 to check if the node has been aligned after the restart:
Aligned! You can do the same with N servers where every server is a Master. There are
no limits on the number of running servers. With many servers across a not-fast network,
you could tune the network timeouts to be more permissive and let a big, distributed
cluster of servers do the work properly.
55
Java Tutorial
If you're only used to working with traditional RDBMS databases, you'll find that
OrientDB is a very different beast. Since OrientDB is able to support document mode,
graph mode, and object-oriented mode, different Java APIs are required. But there are
some similarities too: in a roughly similar way to JDBC, a Blueprints API exists, made by
Tinkerpop, which supports the basic operations on a graph database. There is an
OrientDB "driver" (or, better, "adapter") which makes it possible to operate without
having to deal with OrientDB classes, and the resulting code should be mainly portable
(Blueprints offers more adapters for other graph database products).
In any case, if you need to tweak the database configuration, you need to use the
OrientDB APIs directly. It's a good idea to use a mix: Blueprints when you can and the
OrientDB APIs when you need them.
OrientDB comes with 3 different APIs. Pick your based on your model (for more
information look at Java API):
Graph API
Document API
Object API
Graph API
Connecting to a database
The first object you need is a Graph or a TransactionalGraph (which supports transaction
demarcation):
import com.tinkerpop.blueprints.TransactionalGraph;
import com.tinkerpop.blueprints.impls.orient.OrientGraph;
56
Another possibility is to create the database connection with the OrientDB APIs (this
would make it possible to call tuning APIs, for instance), and then "wrap" it into an
OrientGraph :
import com.orientechnologies.orient.core.db.graph.OGraphDatabase;
import com.tinkerpop.blueprints.TransactionalGraph;
import com.tinkerpop.blueprints.impls.orient.OrientGraph;
In any case, from a TransactionalGraph (or a Graph ) it's always possible to get a
reference to the OrientDB API:
import com.tinkerpop.blueprints.impls.orient.OrientGraph;
import com.orientechnologies.orient.core.db.graph.OGraphDatabase;
Even though OrientDB can work with the generic class "V" for Vertices and "E" for
Edges, it's much more powerful to define custom types for both Vertices and Edges:
odb.setUseCustomTypes(true);
odb.createVertexType("Person");
odb.createVertexType("Address");
The Blueprint adapter is thread-safe and will automatically create a transaction when
needed (e.g. at the first operation if a transaction hasn't been explicitly started). You
have to specify where the transaction ends (commit or rollback) - see below for more
details.
import com.tinkerpop.blueprints.Graph;
import com.tinkerpop.blueprints.Vertex;
57
Vertex vAddress = graph.addVertex("class:Address");
vAddress.setProperty("street", "Van Ness Ave.");
vAddress.setProperty("city", "San Francisco");
vAddress.setProperty("state", "California");
Note the specific Blueprints syntax "class:<class name>" that you must use in the creation
of an object to specify its class. It is not mandatory: it is also possible to specify a null
value, which means that a vertex will be created with the class OGraphVertex , as it's the
superclass of all vertices in OrientDB):
import com.tinkerpop.blueprints.Graph;
import com.tinkerpop.blueprints.Edge;
We passed null to addEdge() , so we created an edge with the OGraphEdge class, which
is the superclass of all edges in OrientDB. A consequence is that in a query we won't be
able to distinguish it from other edges (except for its label).
The Blueprints adapter automatically saves changes to the database (in contrast to
the native OrientDB API, which requires an explicit call to save() ). Please remember
that saving is a different operation than committing.
Please note that, in this example, we have used a partially schema-full mode, as we
defined the vertex types, but not their properties. OrientDB will dynamically accept
everything.
58
More on Tutorials
This is a collection of tutorials about OrientDB.
Video tutorials
59
External tutorials
Miscellaneous
Italian
http://java.html.it/articoli/leggi/4039/nosql-in-java-introduzione-ad-orientdb/
Japanese
http://d.hatena.ne.jp/tm8r/20120416/1334581009
1. Part 1: http://fungoing.jp/2011/08/379
60
Part 1: http://snakemanshow.blogspot.com/2010/09/nosql-orientdb-1.html
Part 2: http://snakemanshow.blogspot.com/2010/09/nosql-orientdb-2.html
Part 3: http://snakemanshow.blogspot.com/2011/04/nosql-orientdb-3.html
61
Presentations
Slides
Video Graph databases and PHP: time for serious stuff by Alessandro Nadalin
and David Funaro at PHPcon Poland on October 21, 2011
Slides
62
Slides
Video : Switching from the relational to the graph model by Luca Garulli at
NoSQL Matters in Barcelona (Spain) on October 6th 2012
Slides
Video : NoSQL adoption: what's the next step? by Luca Garulli at NoSQL Matters
in Cologne (Germany) on May 30th 2012
63
Slides
Slides (English)
Video (English): Works with persistent graphs using OrientDB by Luca Molino at
FOSDEM on February 2012 in Bruxelles (Belgium) on Video
Slides (English)
64
65
Presentations in English
Slides (English): OrientDB distributed architecture 1.1
Slides (English): OrientDB the database for the Web 1.1
What to select between the Document database and the Graph one?
A walk in Graph Databases
66
Videos in Italian, Presentations in English
Video (Italian): Graph databases: time for the serious stuff by Alessandro
Nadalin and David Funaro at Codemotion in Rome on March 2012
Video
Slides (English)
Slides (English)
67
Basic Concepts
Record
RecordID
Record version
Class
Abstract Class
When to use class or cluster in queries?
Relationships
Referenced relationships
1-1 and N-1 referenced relationships
1-N and N-M referenced relationships
Embedded relationships
1-1 and N-1 embedded relationships
1-N and N-M embedded relationships
Inverse Relationships
Database
Database URL
Database Usage
68
Record
A record is the smallest unit that can be loaded from and stored into the database.
Record types
Document
Documents are the most flexible record available in OrientDB. They are softly typed and
are defined by schema classes with defined constraints, but can also be used in
schema-less mode. Documents handle fields in a flexible way. A Document can be
easily imported and exported in JSON format. Below is an example of a Document in
JSON format:
{
"name": "Jay",
"surname": "Miner",
"job": "Developer",
"creations": [
{ "name": "Amiga 1000",
"company": "Commodore Inc."
},
{ "name": "Amiga 500",
"company": "Commodore Inc."
}
]
}
Flat
RecordID
In OrientDB, each record has an auto assigned Unique ID. The RecordID (or RID) is
composed in this way:
69
#[<cluster>:<position>]
Where:
cluster is the cluster id. Positive numbers mean persistent records. Negative
numbers mean temporary records, like those used in result sets for queries that use
projections.
position is the absolute position of the record inside a cluster.
The record never loses its identity unless it is deleted. Once deleted its identity is never
recycled (but with "local" storage). You can access a record directly by its RecordID. For
this reason you don't need to create a field as a primary key like in a Relational DBMS.
Record version
Each record maintains its own version number that is incremented at every update. In
optimistic transactions the version is checked in order to avoid conflicts at commit time.
70
Class
A Class is a concept taken from the Object Oriented paradigm. In OrientDB it defines a
type of record. It's the closest concept to a Relational DBMS Table. Classes can be
schema-less, schema-full, or mixed.
A class can inherit from another, creating a tree of classes. Inheritance means that a
sub-class extends a parent class, inheriting all its attributes.
Each class has its own clusters. A class must have at least one cluster defined (its
default cluster), but can support multiple ones. When you execute a query against a
class, it's automatically propagated to all the clusters that are part of the class. When a
new record is created, the cluster that is selected to store it is picked by using a
configurable strategy.
When you create a new class by default a new persistent cluster is created with the
same name of the class in lowercase.
Abstract Class
If you know Object-Orientation you already know what an abstract class is. For all the
rest:
http://en.wikipedia.org/wiki/Abstract_type
http://docs.oracle.com/javase/tutorial/java/IandI/abstract.html For our purpose, we
can sum up an abstract class as:
A class used as a foundation for defining other classes (eventually, concrete
classes)
A class that can't have instances
Abstract classes are essential to support Object Orientation without the typical
spamming of the database with always empty auto-created clusters. NOTE: available
since 1.2.0
Let's use an example: Let's assume you created a class "Invoice" and two clusters
"invoice2011" and "invoice2012".
71
You can now query all the invoices by using the class as a target in the SQL select:
If you want to filter per year (2012) and you've created a "year" field in the Invoice class
do this:
You may also query specific objects from a single cluster (so, by splitting the Class
Invoice in multiple clusters, e.g. one per year, you narrow your candidate objects):
This query may be significantly faster because OrientDB can narrow the search to the
targeted cluster.
The combination of Classes and Clusters is very powerful and has many use cases.
72
Relationships
OrientDB supports two kinds of relationships: referenced and embedded. OrientDB can
manage relationships in a schema-full or in schema-less scenario.
Referenced relationships
customer
Record A -------------> Record B
CLASS=Invoice CLASS=Customer
RID=5:23 RID=10:2
Record A will contain the reference to Record B in the property called "customer". Note
that both records are reachable by other records since they have a RecordID.
These kinds of relationships are expressed using the collection of links such as:
Embedded relationships
Embedded records, instead, are contained inside the record that embeds them. It's a
kind of relationship that's stronger than the reference. It can be represented like the UML
Composition relationship. The embedded record will not have its own RecordID, since it
can't be directly referenced by other records. It's only accessible through the container
record. If the container record is deleted, then the embedded record will be deleted too.
73
Example:
address
Record A <>----------> Record B
CLASS=Account CLASS=Address
RID=5:23 NO RID!
Record A will contain the entire Record B in the property called "address". Record B
can be reached only by traversing the container record.
Example:
These kinds of relationships are expressed using a collection of links such as:
Inverse relationships
In OrientDB, all Graph Model edges (connections between vertices) are bi-directional.
This differs from the Document Model where relationships are always mono-directional,
thus requiring the developer to maintain data integrity. In addition, OrientDB
automatically maintains the consistency of all bi-directional relationships (aka edges).
74
Database
A database is an interface to access the real Storage. The database understands high-
level concepts like Queries, Schemas, Metadata, Indices, etc. OrientDB also provides
multiple database types. Take a look at the Database types to learn more about them.
Each server or JVM can handle multiple database instances, but the database name
must be UNIQUE. So you can't manage two databases named "customer" in two
different directories at the same time. To handle this case use the $ (dollar) as a
separator instead of / (slash). OrientDB will bind the entire name, so it will be unique,
but at the file system level it will convert $ with / allowing multiple databases with the
same name in different paths. Example:
Database URL
<engine>:<db-name>
Where:
db-name is the database name and depends on the engine used (see below)
engine can be:
75
memory Open a database memory:petshop
completely in memory
Database usage
The database must always be closed once you've finished working with it.
NOTE: OrientDB automatically closes all opened databases when the process dies
gracefully (not by killing it by force). This is assured if the Operating System allows a
graceful shutdown.
76
Supported Types
OrientDB supports several types natively. Below is the complete table.
Decimal
5 Double numbers with java.lang.Double or 2-1074
high double (2-2-52)*21023
precision
Any string as
alphanumeric -
7 String java.lang.String
sequence of -
chars
Can contain 0
8 Binary any value as byte[]
byte array 2,147,483,647
The Record
is contained
inside the -
9 Embedded owner. The ORecord
-
contained
Record has
no RecordId
The Records
are
contained
inside the
77
owner. The
contained 0
10 Embedded records have List<Object> 41,000,000
list no RecordIds items
and are
reachable
only by
navigating
the owner
record
The Records
are
contained
inside the
owner. The
contained
Embedded Records 0
11 set have no Set<Object> 41,000,000
RecordId and items
are
reachable
only by
navigating
the owner
record
The Records
are
contained
inside the
owner as
values of the
entries, while
the keys can
Embedded only be 0
12 map Strings. The Map<String, ORecord> 41,000,000
contained items
ords e no
RecordIds
and are
reachable
only by
navigating
the owner
Record
Link to
another
13 Link Record. It's a ORID , <? extends 1:-1
common ORecord> 32767:2^63-1
one-to-one
relationship
Links to other
Records. It's
a common
one-to-many List<? extends
0
14 Link list relationship ORecord
41,000,000
where only items
the
RecordIds
are stored
78
Links to other
Records. It's 0
Set<? extends
15 Link set a common ORecord>
41,000,000
one-to-many items
relationship
Links to other
Records as
value of the
entries, while
keys can
only be Map<String, 0
16 Link map Strings. It's a ? extends 41,000,000
common Record> items
One-to-Many
Relationship.
Only the
RecordIds
are stored
Single byte.
Useful to java.lang.Byte or -128
17 Byte store small 8- byte +127
bit signed
integers
Any value
18 Transient not stored on
database
Any date as
19 Date year, month java.util.Date --
and day
used to store
a custom
type 0
20 Custom providing the OSerializableStream
X
marshall and
unmarshall
methods
Decimal
21 Decimal numbers java.math.BigDecimal
?
without ?
rounding
List of
22 LinkBag RecordIds as ORidBag
?
spec RidBag ?
Not
determinated
type, used to
23 Any specify - -
Collections of
mixed type,
and null
79
Inheritance
OrientDB doesn't split Documents between different classes (as many OR-Mapping tools
do). Each Document will reside in the cluster of its most base class. When you execute a
query against a class that has sub-classes, OrientDB will search into the clusters of the
target class and all its sub-classes. To know more see How it works.
80
Declare in schema
OrientDB needs to know the relationships between the class inheritance. Note that this
is an abstract concept that applies to both POJOs and Documents.
Example:
81
Polymorphic Queries
By default all the queries are polymorphics. Using the example above with this SQL
query:
Will be returned all the instances of Account and Company classes that has the property
name equals to "Google".
82
How it works
Consider this example. We have 3 classes, with the cluster-id between parenthesis:
This cluster is indicated by the "defaultClusterId" property in OClass class and indicates
the cluster used by default when not specified. However the OClass has the property
"clusterIds" (as int[]) that contains all the clusters able to host the records of that class.
When you execute a query against a class, OrientDB limits the result sets only to the
records of the clusters contained in the "clusterIds" property.
Will return all the records for "GOOGLE" contained in all the three classes because for
the class "Account" OrientDB searches inside the clusters 10, 13 and 27 following the
inheritance specified in the schema.
83
Schema
Although OrientDB can work in schema-less mode, sometimes you need to enforce your
data model using a schema. OrientDB supports schema-full or schema-hybrid solutions
where the second one means to set such constraints only for certain fields and leave the
user to add custom fields to the records. This mode is at class level, so you can have the
"Employee" class as schema-full and "EmployeeInformation" class as schema-less.
Schema-Full: enable the strict-mode at class level and set all the fields as
mandatory
Schema-Less: create classes with no properties. Default mode is non strict-mode
so records can have arbitrary fields
Schema-Hybrid, called also Schema-Mixed is the most used: create classes and
define some fields but leave the record to define own custom fields
NOTE: Changes to the schema are not transactional, so execute them outside a
transaction.
To gain access to the schema APIs you need in the Schema instance of the database
you're using.
84
Class
A Class is a concept taken from the Object Oriented paradigm. In OrientDB defines a
type of record. It's the closest concept to a Relational DBMS Table. Class can be
schema-less, schema-full or mixed.
A class can inherit from another, shaping a tree of classes. This means that the sub-
class extends the parent one inheriting all the attributes.
Each class has its clusters that can be logical (by default) or physical. A class must have
at least one cluster defined (as its default cluster), but can support multiple ones. In this
case by default OrientDB will write new records in the default cluster, but reads will
always involve all the defined clusters.
When you create a new class by default a new physical cluster is created with the same
name of the class in lower-case.
Each class contains one or more properties. This mode is similar to the classic
Relational DBMS approach where you define tables before storing records.
To retrieve a persistent class use the getClass(String) method. If the class not exists
NULL is returned.
85
database.getMetadata().getSchema().dropClass("Account");
The records of the removed class will be not deleted unless you explicitly delete them
before to drop the class. Example:
Constraints
To work in schema-full mode set the strict mode at class level by calling the
setStrictMode(true) method. In this case record of that class can't have not-defined
properties.
86
Property
Properties are the fields of the class. In this guide Property is synonym of Field.
Once the class has been created, you can define fields (properties). Below an example:
Please note that each field must belong to one of supported types.
database.getMetadata().getSchema().getClass("Account").dropProperty("name");
The dropped property will not be removed from records unless you explicitly delete them
using the SQL UPDATE + REMOVE statement. Example:
database.getMetadata().getSchema().getClass("Account").dropProperty("name");
database.command(new OCommandSQL("UPDATE Account REMOVE name")).execute();
Define relationships
Referenced relationships
OrientDB uses a direct link to the referenced record(s) without the need of costly JOINs
of the Relational world. Example:
customer
Record A -------------> Record B
87
CLASS=Invoice CLASS=Customer
RID=5:23 RID=10:2
Record A will contain the reference to the Record B in the property called "customer".
Note that both records are reachable by any other records since they have a RecordID.
1-1 and N-1 referenced relationships are expressed using the LINK type.
In this case records of class "Invoice" will link to a record of class "Customer" using the
field "customer".
1-N and N-M referenced relationships are expressed using the collection of links such
as:
88
Embedded relationships
Embedded records, instead, are contained inside the record that embeds them. It's a
kind of relationship stronger than the reference. The embedded record will not have a
own RecordID since it can't be directly referenced by other records. It's only accessible
via the container record. If the container record is deleted, then the embedded record will
be deleted too. Example:
address
Record A <>----------> Record B
CLASS=Account CLASS=Address
RID=5:23 NO RID!
Record A will contain the entire Record B in the property called "address". Record B
can be reached only by traversing the container record.
Example:
1-1 and N-1 embedded relationships are expressed using the EMBEDDED type.
In this case, records of class "Account" will embed a record of class "Address".
1-N and N-M embedded relationships are expressed using the collection of links such
as:
89
EMBEDDEDMAP, as an ordered map of records as value with key a String. It
doesn't accepts duplicated keys
Constraints
Minimum value, accepts a string because works also for date ranges setMin()
Maximum value, accepts a string because works also for date ranges setMax()
Mandatory, it must be specified setMandatory()
Readonly, it may not be updated after record is created setReadonly()
Not Null, can't be NULL setNotNull()
Unique, doesn't allow duplicates and speedup searches.
Regexp, it must satisfy the Regular expression.
profile.createProperty("nick", OType.STRING).setMin("3").setMax("30").setMandatory(true).setNotNull(
profile.createIndex("nickIdx", OClass.INDEX_TYPE.UNIQUE, "nick"); // Creates unique constraint
profile.createProperty("name", OType.STRING).setMin("3").setMax("30");
profile.createProperty("surname", OType.STRING).setMin("3").setMax("30");
profile.createProperty("registeredOn", OType.DATE).setMin("2010-01-01 00:00:00");
profile.createProperty("lastAccessOn", OType.DATE).setMin("2010-01-01 00:00:00");
Indexes as constraints
90
To let to a group of properties to be UNIQUE create a composite index made of multiple
fields:
91
Cluster Selection
When you create a new record specifying its Class, OrientDB automatically selects the
Class where to store the physical record, by using configurable strategies.
default, uses always the Class's defaultClusterId property. This was the default
before 1.7
round-robin, put the Class's configured clusters in a ring and returns a different
cluster every time restarting from the first when the ring is completed
balanced, checks the records in all the clusters and returns the smaller cluster. This
allows the cluster to have all the underlying clusters balanced on size. On adding a
new cluster to an existent class, the new empty cluster will be filled before the
others because more empty then the others. Calculation of cluster size is made
every 5 or more seconds to avoid to slow down insertion
local. This is injected when OrientDB is running in distributed mode. With this
strategy the cluster that is the master on current node is always preferred. This
avoids conflicts and reduces network latency with remote calls between nodes.
92
Create custom strategy
To create your custom strategy follow the following steps:
package mypackage;
public class RandomSelectionStrategy implements OClusterSelectionStrategy {
public int getCluster(final OClass iClass, final ODocument doc) {
final int[] clusters = iClass.getClusterIds();
Note that the method getCluster() receives also the ODocument to insert. This is useful
if you want to assign the clusterId based on the Document content.
mypackage.RandomSelectionStrategy
com.orientechnologies.orient.core.metadata.schema.clusterselection.ORoundRobinClusterSelectionStrategy
com.orientechnologies.orient.core.metadata.schema.clusterselection.ODefaultClusterSelectionStrategy
com.orientechnologies.orient.core.metadata.schema.clusterselection.OBalancedClusterSelectionStrategy
93
3) Assign it
To assign your new strategy to a class, use the ALTER CLASS command. Example:
94
Fetching Strategies
OrientDB supports fetching strategies by using the Fetch Plans. Fetch Plans are used
to customize how OrientDB must load linked records.
Example:
Invoice
3:100
|
| customer
+---------> Customer
| 5:233
| address city country
+---------> Address---------> City ---------> Country
| 10:1 11:2 12:3
|
| orders
+--------->* [OrderItem OrderItem OrderItem]
[ 8:12 8:19 8:23 ]
By default OrientDB loads all the linked records in lazy way. So in this example the
linked "customer", "city" and "orders" fields are not loaded until are traversed. If you
need the entire tree it could be slow the lazy loading of every single linked record. In this
case it would need 7 different loads. If the database is open on a remote server they are
7 different network calls.
This is the reason why OrientDB supports custom fetching strategies using the Fetch
Plans. The aim of fetch plans is to pre-load connected records in one shot.
95
Remote connection
When a client executes a query (or load directly one single record) setting a fetch plan
with level different to 0, then the server traverses all the records of the returning result
set and sends them to the client in the same call.
The client avoid to connect directly them to the record by using always the lazy
collections (i.e.: OLazyRecordList). Instead, loads all the connected records into the
local client. In this ways the collections remain lazy but when you're accessing to the
content, the record is early loaded from the local cache avoiding other connections.
96
Format
The fetch plan comes in form of a String and can be used at run-time on:
query
record loading
[[levels]]<fieldPath>:<depth-level>*
Where:
levels, optional, tells at which levels the rules must apply. Levels starts from 0.
Since 2.1. Supported syntax is:
level, example [0] to apply only at first level
ranges, example [0-3] form 0 to 3th level. Ranges can be also partial, like
[-3] means 0-3 and [3-] means form 3rd to infinite
any, by using * . Example [*] to apply at any level
fieldPath, is the field name path, expected in dot notation, starting from the root
record or the wildcard for "any" field. The wildcard can be also at the end of the
path to specify all the paths that starts for a name
depth-level, is the deep level requested:
0 = Load only current record,
1-N = load only the first-Nth connected record,
-1 = unlimited,
-2 = exclude it
97
"[*]in_*:-2 out_*:-2" : returns all the properties, but edges (at any level)
98
Circular dependencies
OrientDB handles circular dependencies to avoid any loop while fetches linking records.
99
Example using the Java APIs
invoice.toJSON("fetchPlan:customer:1");
invoice.toJSON("fetchPlan:customer:1 orders:2");
Export an invoice and all the connected records up to 3rd level of depth:
invoice.toJSON("fetchPlan:*:3");
From SQL:
Export path in outgoing direction by removing all the incoming edges by using wildcards
(Since 2.0):
NOTES::
To avoid looping, the record already traversed by fetching are exported only by their
100
RIDs (RecordID) form
"fetchPlan" setting is case sensitive
NOTE: fetching Object will mean their presence inside your domain entities. So if you
load an object using fetchplan *:0 all LINK type references won't be loaded.
101
Indexes
OrientDB supports 4 kinds of indexes:
Works like a
HashMap so
it's faster on
punctual
lookup
(select from
xxx where
salary =
Super 1000) and
fast consumes
Hash YES YES no lookup, less
very resources,
light on but you
disk cannot use it
for range
queries
(select from
xxx where
salary
between
1000 and
2000)
Good on Lucene
full-text indexes can
Lucene YES YES YES and be used
spatial only for full-
text and
indexes spatial
102
What's an index?
Indexes can be handled like classes (or tables for RDBMS users) using the SQL
language and prefixing with "index:" the index name. The index is like a class (or table)
with 2 properties:
103
Index target
Indexes can be updated:
104
Index types
The index type cannot be changed once created. The supported index types are the
following:
SB-Tree algorithm:
UNIQUE, doesn't allow duplicates. For composite index means uniqueness of
composite keys.
NOTUNIQUE, allows duplicates
FULLTEXT, by indexing any single word of the text. It's used in query with the
operator CONTAINSTEXT
DICTIONARY, like UNIQUE but in case the key already exists replace the
record with the new one
HashIndex algorithm:
UNIQUE_HASH_INDEX, doesn't allow duplicates. For composite index means
uniqueness of composite keys.
NOTUNIQUE_HASH_INDEX, allows duplicates
FULLTEXT_HASH_INDEX, by indexing any single word of the text. It's used in
query with the operator CONTAINSTEXT
DICTIONARY_HASH_INDEX, like UNIQUE but in case the key already exists
replace the record with the new one
Lucene engine:
FULLTEXT, it uses Lucene to index the string content. Use the LUCENE
operator to retrieve it.
SPATIAL, it uses Lucene to index the geo spatial coordinates.
Dictionary
Every single database has a default manual index of type "DICTIONARY" called
dictionary with Strings as keys. This is very useful to:
105
Operations against indexes
Create an index
Creates a new index. To create an automatic index bound to a schema property use
section "ON" of create index command or use as name the <class.property> notation.
But assure to have created the schema for it before the index. See the example below.
Syntax:
Where:
106
key-type, is the type of key (Optional). On automatic indexes is auto-determined by
reading the target schema property where the index is created. If not specified for
manual indexes, at run-time during the first insertion the type will be auto
determined by reading the type of the class.
metadata is a json representing all the additional metadata as key/value
Drop an index
107
DROP INDEX <name>
Where:
Lookup
Example:
Put an entry
Example:
108
Query range
Example:
Example:
Remove an entry
Deletes an entry by passing key and rid. Returns true if removed, otherwise false if the
entry wasn't found.
Example:
109
Removes all the entries with the rid passed.
Example:
Example:
Example:
Retrieves all the entries of the index as pairs key and rid.
110
Example:
Removes all the entries. The index will be empty after this call. This removes all the
entries of an index.
Example:
111
Null values
Indexes by default ignore null values. For such reason queries against NULL value that
use indexes return no entries.
If you want to index also null values set { ignoreNullValues : false } as metadata.
Example:
112
Composite keys
You can do the same operations with composite indexes.
author,
title and
publication year
select from index:books where key = ["Donald Knuth", "The Art of Computer Programming", 1968]
select from index:books where key between ["Donald Knuth", "The Art of Computer Programming",
This is a mechanism that allows searching index record by several first fields of its
composite key. In this case the remaining fields with undefined value can match any
value in result.
Composite indexes are used for partial match search only when the declared fields in
composite index are used from left to right. Using the example above, if you search only
for title, the composite index cannot be used, but it will be used if you search for author +
title.
For example, if we don't care when books have been published, we can throw away the
publication year field from the query. So, the result of the following query will be all
books with this author and title and any publication year
select from index:books where key = ["Author", "The Art of Computer Programming"]
113
If we also don't know title, we can keep only author field in query. Result of following
query will be all books of this author.
Or equivalent
Range Queries
In case of range queries, the field subject to the range must be the last one. Example:
Unsupported yet.
114
Custom keys
OrientDB since release 1.0 supports custom keys for indexes. This could give a huge
improvement if you want to minimize memory used using your own serializer.
Below an example to handle SHA-256 data as binary keys without using a STRING to
represent it saving disk space, cpu and memory.
115
public void serialize(final ComparableBinary object, final byte[] stream, final int startPosition)
final byte[] buffer = object.toByteArray();
System.arraycopy(buffer, 0, stream, startPosition, buffer.length);
}
Usage
116
Tips and Tricks
117
Create your index engine
Here a guide how to create a custom index engine.
118
SB-Tree index
This index is based on B-Tree index with several optimizations related to data insertion
and range queries. As any other tree based indexes they have log(N) complexity, but
base of this logarithm is about 500.
There is an issue about replacement of B-Tree based index by COLA Tree based index
to avoid slowdown introduced by random I/O operations Issue #1756.
119
Hash Index
Hash index allows to perform index read operations for 1 (one) I/O operation, and index
write for 3 (three) I/O operations as maximum. Hash index algorithm is based on
extendible hashing Extendible Hashing algorithm. Hash index does not support range
queries, but it's noticeable faster (about 2 times on 10M records) than SB-Tree index.
120
Full Text
Full Text indexes allow to index text as single word and its radix. Full text indexes are
like a search engine on your database. If you are using the Lucene engine, please refer
to Lucene Full-Text index.
Example:
This will create a FullText index on the property name of the class City, with default
configuration.
Word prefixes
indexRadix true will be also
index
ignoreChars "
Chars to skip
when indexing
separatorChars \r\n\t:;,.|+*/\=!?[](.md)
Minimum word
minWordLength 3 length to index
create index City.name on City (name) FULLTEXT METADATA {"indexRadix" : true, "ignoreChars" : "&" , "sepa
121
Example with Java;
122
Lucene Full Text Index
Full text index can be created using the OrientDB SQL syntax as written here. Specify
the index engine to use the lucene full text capabilities.
Syntax:
Example
Example:
This will create a basic lucene index on the properties specified. If the analyzer is not
specified, the default will be the StandardAnalyzer. To use a different analyzer use the
field analyzer in the metadata JSON object in the CREATE INDEX syntax.
Example:
create index City.name on City (name) FULLTEXT ENGINE LUCENE METADATA {"analyzer":"org.apache.lucene.anal
The Index can also be created with the Java Api. Example:
123
How to query a Full Text Index
The full text index can be queried using the custom operator LUCENE using the Query
Parser Syntax of Lucene. Example:
If query is a plain string the engine will parse the query using MultiFieldQueryParser on
each indexed field.
To execute a more complex query on each fields surround your query with ()
parenthesis, to address specific field.
Example:
With this syntax the engine parse the query using the QueryParser.
124
Lucene Spatial
For now the Index Engine can only index Points. Other Shapes like rectangles and
polygons will be added in the future.
125
How to create a Spatial Index
The index can be created on a Class that has two fields declared as Double
(latitude,longitude) that are the coordinates of the Point.
For example we have a Class Place with 2 double fields latitude and longitude . To
create the spatial index on City use this syntax.
The Index can also be created with the Java Api. Example:
126
How to query the Spatial Index
Two custom operators has been added to query the Spatial Index:
NEAR operator
Syntax
The 'maxDistance' field has to be in kilometers, not radians. Results are sorted from
nearest to farthest.
To know the exact distance between your Point and the Points matched, use the special
variable in the context $distance.
Examples
Let's take the example we have written before. We have a Spatial Index on Class Place
on properties latitude and longitude .
127
select *,$distance from Place where [latitude,longitude,$spatial] NEAR [51.507222,-0.1275,{"maxDistance"
WITHIN operator
Syntax
select from Class where [<lat field>,<long field>] WITHIN [ [ <lng1>, <lat1> ] , [ <lng2>, <lat2> ] ...
Examples
This query will return all Places within the given Bounding Box.
128
Future Plans
Index All types of shape
Adding more operators such as INTERSECT
Extend the WITHIN operator to support not only Bounding Box
129
Security
The security model of OrientDB is based on well known concepts built on users and
roles. A database has "users". Each User has one or more "roles". Role is compound
by the mode of working (more later) and the set of permission rules.
130
Database security
131
Users
A User is an actor of the database. When you open a database you need to specify the
user name and password used. Each user has own credentials and permissions.
By convention 3 users are always created by default every time you create a new
database. Passwords are the same as the user name. Default users are:
admin, with default password "admin", has access to all the functions without
limitation
reader, with default password "reader", is the classic read-only user. Can read any
records but can't modify or delete them. Can't access to internal information such as
user and role themselves.
writer, with the default password "writer", is like the "reader" but can also create,
update and delete records.
Users are themselves records stored inside the cluster "OUser". The passwords are
stored in hash format using the strong algorithm SHA-256.
The user status is stored in the field "status" and can be: "SUSPENDED" and "ACTIVE".
Only ACTIVE users can log in.
To create a new user use the SQL INSERT remembering to assign the status 'ACTIVE'
and a valid role as in this example:
insert into ouser set name = 'jay', password = 'JaY', status = 'ACTIVE', roles = (select from
132
In the same way to change the user password use:
The password will be saved in hash format using the algorithm SHA-256. The trigger
"OUserTrigger" will encrypt the password transparently before the record is saved.
To disable a user change the status from 'ACTIVE' to 'SUSPENDED'. In this example we
disable all the users but "admin":
133
Roles
A role decides if it's allowed to execute an operation against a resource. Mainly this
decision depends by the "working mode" and by the "rules". Rules work differently based
on the "working mode".
To create a new role use the SQL INSERT remembering to assign the status 'ACTIVE'
and a valid role as in this example:
Inherited roles
Roles can inherit permissions from other roles in a Object Oriented fashion. To let a role
extend another one add the parent role in the "inheritedRole" attribute. Example to let
"appuser" role to inherit the "writer" role settings:
update orole set inheritedRole = (select from orole where name = 'writer') where name = 'appuser'
Working modes
By default is a super user and exceptions are enlisted in the rules. If no rule is found for
the requested resource, then it's allowed to execute the operation. Use this mainly for
power users. "Admin" default role uses this mode and has no exception rules. This mode
is written as "1" in database.
By default it can't make nothing but the exceptions enlisted in the rules. This should be
134
the default mode for all classic users. "Reader" and "Writer" default roles use this mode.
This mode is written as "0" in database.
Operations
( C )reate
( R )ead
( U )pdate
( D )elete
A role can have none or all the permissions above. Each permission is internally
represented by a flag of a 4 digit bitmask. So the above permissions are:
NONE: #0000 - 0
CREATE: #0001 - 1
READ: #0010 - 2
UPDATE: #0100 - 4
DELETE: #1000 - 8
ALL: #1111 - 15
Of course you could make a combination of them. For example, if you want to allow only
the Read and Update permissions, you could use
READ: #0010 - 1
UPDATE: #0100 - 4
Permission to use: #0110 - 5
Resources
Resources are strings bound to OrientDB concepts. Note: resources are case sensitive:
database
database.class
database.class.<class-name>
database.cluster
database.cluster.<cluster-name>
database.query
database.command
database.config
135
database.hook.record
server.admin
Example:
Enable to the role "motorcyclist" the access to all the classes but the "Car" class:
136
Grant and revoke permissions
To grant and revoke permissions use the SQLGrant and SQLRevoke commands.
137
Record level security
This is also called "horizontal security" because it doesn't act at schema level (vertically),
but per each record. Due to this, we can totally separate the database records as sand-
boxes where each "Restricted" records can't be accessed by non authorized users.
To activate this kind of advanced security, let the classes you want extend the
ORestricted super class. If you're working with a Graph Database you should let V
(Vertex) and E (Edge) classes extend ORestricted class:
In this way, all the vertices and edges will inherit the record level security.
Every time a class extends the ORestricted class, OrientDB, by a hook, injects a check
before each CRUD operation:
CREATE new document: set the current database's user in the _allow field. To
change this behavior look at Customize on creation
READ a document: check if the current user or its roles are enlisted in the _allow or
_allowRead fields. If not the record is skipped. This let each queries to work per user
basis
UPDATE a document: check if the current user or its roles are enlisted in the
_allow or _allowUpdate field. If not a OSecurityException is thrown
DELETE a document: check if the current user or its roles are enlisted in the _allow
or _allowDelete field. If not a OSecurityException is thrown
The "allow" fields ( _allow , _allowRead , _allowUpdate , _allowDelete ) can contain instances
of OUser and ORole records (both classes extends OIdentity). Use OUser to allow
single users and ORole to allow all the users that are part of these roles.
Customize on creation
By default everytime someone creates a Restricted record (when its class extends the
ORestricted class) the current user is inserted in the " _allow " field. This can be changed
by setting custom properties in the class schema supporting these properties:
onCreate.fields, to specify the names of the fields to set. By default is " _allow " but
138
you can specify here " _allowRead ", " _allowUpdate " and " _allowDelete " or a
combination of them. Use the comma to separate multiple fields
onCreate.identityType, to specify if the user's object will be inserted or its role (the
first one). By default is set "user", but you can also use "role"
Example to assign its role instead of user to the new Post instances created:
Sometimes you need to create a role that can bypass such restrictions, such as backup
or administrative operations. For such reason we've created the special permission
database.bypassRestricted to READ. By default, the "admin" role has such permission.
This permission is not inheritable, so if you need to give such high privilege to other roles
set it to each role.
Use case
You want to enable this security in a BLOG like application. First create the document
class, like "Post" that extends "ORestricted". Then if the user "Luke" creates a new post
and the user "Steve" does the same, each user can't access the Post instances created
by each other.
The user "Luke", registered as OUser "luke" having RID #5:5, logs in and create a new
Post:
139
Created document #18:0
Then the user Steve, registered as OUser "steve" having RID #5:6, logs in too and
create a new Post:
Each user can see only the record where they have access. Now try to allow the user
Steve (rid #5:6) to access to the first Luke's post adding the Steve's RID in the _allow
field:
Now if Steve executes the same query as before, the result changes:
Now we would like to let Steve only read posts by Luke, without the rights to modify
them. So we're going to remove Steve from the generic "_allow" field to insert into the
"_allowRead":
140
orientdb> connect remote:localhost/blog luke luke
orientdb> update #18:0 remove _allow = #5:6
orientdb> update #18:0 add _allowRead = #5:6
Now if Steve connects and displays all the Post instances he will continue to display the
Luke's post but can't update or delete them.
You can enable this feature even on graphs. Follow this tutorial to look how to create a
partitioned graph.
141
OrientDB Server security
A single OrientDB server can manage several databases per time, each one with its
users. In HTTP protocol is handled by using different realms. This is the reason why
OrientDB Server instance has its own users to handle the server instance itself.
When the OrientDB Server starts check if there is configured the "root" user. If not
creates it into the config/orientdb-server-config.xml file with an automatic generated very
long password. Feel free to change the password, but restart the server to get the
changes.
Since the passwords are in clear, who is installing OrientDB have to protect the entire
directory (not only config folder) to avoid any access to the not authorized users.
142
Server's resources
This section contains all the available server's resources. Each user can declare which
resources have access. Wildcard means any resources. *root server user, by default,
has all the privileges, so it can access to all the managed databases.
Resource Description
143
SSL Secure connections
Starting from v1.7 OrientDB support secure SSL connections.
144
Restore admin user
If the class OUser has been dropped or the "admin" user has been deleted, you can
follow this procedure to restore your database:
2) Open the Console or Studio and login into the database using "root" and the
password contained in file $ORIENTDB_HOME/config/orientdb-server-config.xml
6) Now execute:
8) If the role "admin" doesn't exist, create it by executing the following command:
145
insert into ORole set name = 'admin', mode = 1, rules = {"database.bypassrestricted":15}
9) If the user "admin" doesn't exist, create it by executing the following command:
insert into OUser set name = 'admin', password = 'admin', status = 'ACTIVE',
roles = (select from ORole where name = 'admin')
146
SSL
Starting from v1.7, OrientDB provides the ability to secure is HTTP and BINARY
protocols using SSL (For Distributed SSL see the HazelCast Documentation).
147
Setting up the Key and Trust Stores
OrientDB uses the JAVA Keytool to setup and manage certificates. This tutorial shows
how to create key and trust stores that reference a self signed cert. Use of CA signed
certs is outside the scope of this document. For more details on using the java Keytool
please visit http://docs.oracle.com/javase/7/docs/technotes/tools/index.html#security and
for more information.
keytool -genkey -alias server -keystore orientdb.ks -keyalg RSA -keysize 2048 -validity
3650
keytool -genkey -alias console -keystore orientdb-console.ks -keyalg RSA -keysize 2048 -
validity 3650
4. Create a trust-store for the client, and import the server's certificate. This
establishes that the client "trusts" the server:
NOTE: You will need to repeat steps 3 and 4 for each remote client vm you wish to
connect to the server. Remember to change the alias and keystore and trust-store
filenames accordingly.
148
Configuring the Server
The OrientDB server config ($ORIENTDB_HOME/config/orientdb-server-config.xml)
does not enable SSL by default. To enable SSL on a protocol listener you simply change
the "socket" attribute of the from "default" to one of your configured definitions.
There are two default definitions named "ssl" and "https". These should be sufficient for
most uses cases, however more can be defined if you want to secure different listeners
with there own certificates or want custom socket factory implementations. When using
the "ssl" implementation keep in mind that the default port for OrientDB SSL is 2434 and
that your port-range should be changed to 2434-2440.
By default, the OrientDB Server looks for its keys and trust stores in
$ORIENTDB_HOME/config/cert. This is configured using the parameters. Make sure
that all of the key and trust stores created in the previous setup are in the correct
directory and that the passwords used are also correct.
Note that paths are relative to $ORIENTDB_HOME. Absolute paths are supported.
Example Configuration
<sockets>
<socket implementation="com.orientechnologies.orient.server.network.OServerSSLSocketFactory"
<parameters>
<parameter value="false" name="network.ssl.clientAuth"/>
<parameter value="config/cert/orientdb.ks" name="network.ssl.keyStore"/>
<parameter value="password" name="network.ssl.keyStorePassword"/>
<!-- NOTE: We are using the same store for keys and trust.
This will change if client authentication is enabled. See Configuring Client section -->
...
149
Configuring the Console
To enable SSL for remote connections using the console, a few changes to the console
script are required.
150
Configuring Client
Configuring remote clients can be done using standard java system property patterns.
Properties:
Use steps 3 and 4 from the "Setting up the Key and Trust Stores" section to create client
certificates and trust of the server. Paths to the stores will be client specific and do not
need to be the same as the server.
If you would like to use key and/or truststores other that the default JVM they should use
instead:
151
If you want to verify/authenticate client certificates, you need to take a few extra steps on
the server:
2. Create a truststore for the server if one does not exist, and import the client's
certificate. This establishes that the server "trusts" the client:
In the server config make sure that client authentication is enabled for the and that the
trust-store path and password are correct:
Example
<sockets>
<socket implementation="com.orientechnologies.orient.server.network.OServerSSLSocketFactory"
<parameters>
<parameter value="true" name="network.ssl.clientAuth"/>
<parameter value="config/cert/orientdb.ks" name="network.ssl.keyStore"/>
<parameter value="password" name="network.ssl.keyStorePassword"/>
<!-- NOTE: We are using the trust store with the imported client cert. You can import as many cli
<parameter value="config/cert/orientdb.ts" name="network.ssl.trustStore"/>
<parameter value="password" name="network.ssl.trustStorePassword"/>
</parameters>
</socket>
152
Caching
OrientDB has several caching mechanisms that act at different levels. Look at this
picture:
Local cache is one per database instance (and per thread in multi-thread
environment)
Storage, depending by the implementation could cache. This is the case for the
Local Storage (disk based) that caches file reads to reduce I/O requests
153
How cache works?
154
Client-Server Mode (remote database)
155
Record cache
Local cache
Local cache acts at database level. Each database instance has a Local cache enabled
by default. This cache keeps the used records. Records will be removed from heap if 2
conditions will be satisfied:
156
Empty Local cache
To remove all the records in Local cache you can invoke the invalidate() method:
db.getLocalCache().invalidate();
Disabling of local cache may lead to situation when 2 different instances of the same
record will be loaded and OConcurrentModificationException may be thrown during
record update even in single thread mode.
OGlobalConfiguration.CACHE_LOCAL_ENABLED.setValue(false);
157
Functions
A Function is an executable unit of code that can take parameters and return a result.
Using Functions you can perform Functional programming where logic and data are all
together in a central place. Functions are similar to the Stored Procedures of RDBMS.
NOTE: This guide refers to the last available release of OrientDB. For past revisions look
at Compatibility.
OrientDB Functions:
are persistent
can be written in SQL or Javascript (Ruby, Scala, Java and other languages are
coming)
can be executed via SQL, Java, REST and Studio
can call each other
supports recursion
have automatic mapping of parameters by position and name
plugins can inject new objects to being used by functions
158
Create your first function
To start using Functions the simplest way is using the Studio. Open the database and go
to the "Functions" panel. Then write as name "sum", add 2 parameters named "a" and
"b" and now write the following code in the text area:
return a + b;
Click on the "Save" button. Your function has been saved and will appear on the left
between the available functions.
Now let's go to test it. On the bottom you will find 2 empty boxes. This is where you can
insert the parameters when invoking the function. Write 3 and 5 as parameters and click
"Execute" to see the result. "8.0" will appear in the output box below.
159
Where are my functions saved?
Functions are saved in the database using the OFunction class and the following
properties:
Concurrent editing
Since OrientDB uses 1 record per function, the MVCC mechanism is used to protect
against concurrent record updates.
160
Usage
Using OrientDB's functions from Java is straightforward. First get the reference to the
Function Manager, get the right function and execute it passing the parameters (if any).
In this example parameters are passed by position:
If you're using the Blueprints Graph API get the reference to the Function in this way:
161
Usage via HTTP REST
Each function is exposed as a REST service allowing the receiving of parameters.
parameters are passed by position.
http://localhost:2480/function/demo/sum/3/5
This will return an HTTP 202 OK with an envelope containing the result of the
calculation:
{"result":[{"@type":"d","@version":0,"value":2}]}
You can call with HTTP GET method only functions declared as "idempotent". Use
HTTP POST to call any functions.
If you're executing the function using HTTP POST method, encode the content and set
the HTTP request header to: "Content-Type: application/json" .
For more information, see HTTP REST protocol. To learn how to write server-side
function for web applications, see Server-Side functions.
162
Function return values in HTTP calls
When calling a function as a REST service, OrientDB encapsulates the result in a JSON
and sends it to the client via HTTP. The result can be slightly different depending on the
return value of the function. Here are some details about different cases:
return 31;
result:
{"result":[{"@type":"d","@version":0,"value":31}]}
result:
{"result":[{"@type":"d","@version":0,"value":{"a":1,"b":"foo"}}]}
return [1, 2, 3]
result:
{"result":[{"@type":"d","@version":0,"value":[1,2,3]}]}
result:
163
{
"result": [
{
"@type": "d",
"@rid": "#6:0",
"@version": 1,
"@class": "OUser",
"name": "admin",
"password": "...",
"status": "ACTIVE",
"roles": [
"#4:0"
],
"@fieldTypes": "roles=n"
},
{
"@type": "d",
"@rid": "#6:1",
"@version": 1,
"@class": "OUser",
"name": "reader",
"password": "...",
"status": "ACTIVE",
"roles": [
"#4:1"
],
"@fieldTypes": "roles=n"
}
]
}
164
Access to the databases from Functions
OrientDB always binds a special variable "orient" to use OrientDB services from inside
the functions. The most important methods are:
Execute a query
Create a new function with name "getyUserRoles" with the parameter "user". Then write
this code:
The name parameter is bound as variable in Javascript. You can use this variable to
build your query.
Execute a command
SQL Command
165
166
Write your own repository classes
Functions are the perfect place to write the logic for your application to access to the
database. You could adopt a DDD approach allowing the function to work as a
Repository or a DAO.
This mechanism provides a thin (or thick if you prefer) layer of encapsulation which may
protect you from database changes.
Furthermore each function is published and reachable via HTTP REST protocol allowing
the automatic creation of a RESTful service.
Example
function user_getAll(){
function user_getAdmin(){
return user_getByName("admin");
var db = orient.getDatabase();
167
var role = db.query("select from ORole where name = ?", roleName);
if( role == null ){
response.send(404, "Role name not found", "text/plain", "Error: role name not found" );
} else {
db.begin();
try{
var result = db.save({ "@class" : "OUser", name : "Luca", password : "Luc4", roles : role});
db.commit();
return result;
}catch ( err ){
db.rollback();
response.send(500, "Error on creating new user", "text/plain", err.toString() );
}
}
168
Recursive calls
Create the new function with name "factorial" with the parameter "n". Then write this
code:
if (num === 0)
return 1;
else
return num * factorial( num - 1 );
This function calls itself to find the factorial number for <num> as parameter. The result is
3628800.0 .
169
Server-Side functions
Server-Side functions can be used as Servlet replacement. To know how to call a
Server-Side function, see Usage via HTTP REST. When server-side functions are called
via HTTP REST protocol, OrientDB embeds a few additional variables:
Request object
170
found between those passed
Response object
var db = orient.getDatabase();
var roles = db.query("select from ORole where name = ?", roleName);
if( roles == null || roles.length == 0 ){
response.send(404, "Role name not found", "text/plain", "Error: role name not found" );
} else {
db.begin();
try{
var result = db.save({ "@class" : "OUser", name : "Luca", password : "Luc4", "roles" : roles});
db.commit();
return result;
}catch ( err ){
db.rollback();
response.send(500, "Error on creating new user", "text/plain", err.toString() );
}
}
getHttpVersion() String
171
writeStatus(int httpCode, String Sets the response's status as Request
reason) HTTP code and reason object
Util object
172
Refer to this object as "util". Example:
if( util.exists(year) ){
print("\nYes, the year was passed!");
}
173
Native functions
OrientDB's SQL dialect supports many functions written in native language. To obtain
better performance you can write you own native functions in Java language and register
them to the engine.
174
Compatibility
175
Transactions
A transaction comprises a unit of work performed within a database management
system (or similar system) against a database, and treated in a coherent and reliable
way independent of other transactions. Transactions in a database environment have
two main purposes:
to provide reliable units of work that allow correct recovery from failures and keep a
database consistent even in cases of system failure, when execution stops
(completely or partially) and many operations upon a database remain
uncompleted, with unclear status
to provide isolation between programs accessing a database concurrently. If this
isolation is not provided, the program's outcome are possibly erroneous.
NOTE: OrientDB keeps the transaction on client RAM, so the transaction size is
affected by the available RAM (Heap memory) on JVM. For transactions involving
many records, consider to split it in multiple transactions.
176
ACID properties
Atomicity
"Atomicity requires that each transaction is 'all or nothing': if one part of the transaction
fails, the entire transaction fails, and the database state is left unchanged. An atomic
system must guarantee atomicity in each and every situation, including power failures,
errors, and crashes. To the outside world, a committed transaction appears (by its
effects on the database) to be indivisible ("atomic"), and an aborted transaction does not
happen." - WikiPedia
Consistency
"The consistency property ensures that any transaction will bring the database from one
valid state to another. Any data written to the database must be valid according to all
defined rules, including but not limited to constraints, cascades, triggers, and any
combination thereof. This does not guarantee correctness of the transaction in all ways
the application programmer might have wanted (that is the responsibility of application-
level code) but merely that any programming errors do not violate any defined rules." -
WikiPedia
OrientDB uses the MVCC to assure consistency. The difference between the
management of MVCC on transactional and not-transactional cases is that with
transactional, the exception rollbacks the entire transaction before to be caught by the
application.
1 Begin of
Transaction
2 read(x) 10
3 Begin of
Transaction
4 read(x) 10
5 write(x) 10
6 commit 10 -> 11
7 write(x) 10
177
10 -> 11 = Error, in
8 commit database x already is at 11
Isolation
"The isolation property ensures that the concurrent execution of transactions results in a
system state that would be obtained if transactions were executed serially, i.e. one after
the other. Providing isolation is the main goal of concurrency control. Depending on
concurrency control method, the effects of an incomplete transaction might not even be
visible to another transaction." - WikiPedia
READ COMMITTED, the default and the only one available with remote protocol
REPEATABLE READS, allowed only with plocal and memory protocols. This mode
consumes more memory than READ COMMITTED, because any read, query, etc.
keep the records in memory to assure the same copy on further access
db.begin()
db.getTransaction().setIsolationLevel(OTransaction.ISOLATION_LEVEL.REPEATABLE_READ);
Using remote access all the commands are executed on the server, so out of transaction
scope. Look below for more information.
1 Begin of Transaction
2 read(x)
3 Begin of Transaction
4 read(x)
5 write(x)
6 commit
7 read(x)
8 commit
178
At operation 7 the client 1 continues to read the same version of x read in operation 2.
1 Begin of Transaction
2 read(x)
3 Begin of Transaction
4 read(y)
5 write(y)
6 commit
7 read(y)
8 commit
At operation 7 the client 1 reads the version of y which was written at operation 6 by
client 2. This is because it never reads y before.
Transactions are client-side only until the commit. This means that if you're using the
"remote" protocol the server can't see local changes
In this scenario you can have different isolation levels with commands.
Durability
179
"Durability means that once a transaction has been committed, it will remain so, even in
the event of power loss, crashes, or errors. In a relational database, for instance, once a
group of SQL statements execute, the results need to be stored permanently (even if the
database crashes immediately thereafter). To defend against power loss, transactions
(or their effects) must be recorded in a non-volatile memory." - WikiPedia
Fail-over
You can use the OrientDB engine directly in the same process of your application. This
gives superior performance due to the lack of inter-process communication. In this case,
should your application crash (for any reason), the OrientDB Engine also crashes.
If you're using an OrientDB Server connected remotely, if your application crashes the
engine continue to work, but any pending transaction owned by the client will be rolled
back.
Auto-recovery
At start-up the OrientDB Engine checks to if it is restarting from a crash. In this case, the
auto-recovery phase starts which rolls back all pending transactions.
OrientDB has different levels of durability based on storage type, configuration and
settings.
180
Transaction types
No Transaction
Optimistic Transaction
This mode uses the well known Multi Version Control System (MVCC) by allowing
multiple reads and writes on the same records. The integrity check is made on commit. If
the record has been saved by another transaction in the interim, then an
OConcurrentModificationException will be thrown. The application can choose either to
repeat the transaction or abort it.
NOTE: OrientDB keeps the transaction on client RAM, so the transaction size is
affected by the available RAM (Heap) memory on JVM. For transactions involving
many records, consider to split it in multiple transactions.
With Graph API transaction begins automatically, with Document API is explicit by using
the begin() method. Example with Document API:
db.open("remote:localhost:7777/petshop");
try{
db.begin(TXTYPE.OPTIMISTIC);
...
// WRITE HERE YOUR TRANSACTION LOGIC
...
db.commit();
}catch( Exception e ){
db.rollback();
} finally{
db.close();
}
In Optimistic transaction new records take temporary RecordIDs to avoid to ask to the
server a new RecordID every time. Temporary RecordIDs have Cluster Id -1 and Cluster
Position < -1. When a new transaction begun the counter is reset to -1:-2. So if you
create 3 new records you'll have:
-1:-2
181
-1:-3
-1:-4
At commit time, these temporary records RecordIDs will be converted in the final ones.
Pessimistic Transaction
182
Nested transactions and propagation
OrientDB doesn't support nested transaction. If further begin() are called after a
transaction is already begun, then the current transaction keeps track of call stack to let
to the final commit() call to effectively commit the transaction. Look at Transaction
Propagation more information.
183
Record IDs
OrientDB uses temporary RecordIDs with transaction as scope that will be transformed
to finals once the transactions is successfully committed to the database. This avoid to
ask for a free slot every time a client creates a record.
184
Tuning
In some situations transactions can improve performance, typically in the client/server
scenario. If you use an Optimistic Transaction, the OrientDB engine optimizes the
network transfer between the client and server, saving both CPU and bandwidth.
185
Distributed environment
Transactions can be committed across a distributed architecture. Look at Distributed
Transactions for more information.
Transaction-propagation
186
Hooks (Triggers)
Hook works like a trigger. Hook lets to the user application to intercept internal events
before and after each CRUD operation against records. You can use to write custom
validation rules, to enforce security or even to orchestrate external events like the
replication against a Relational DBMS.
Depends by your goal: Java Hooks are the fastest hooks. Write a Java Hook if you need
the best performance on execution. Dynamic Hooks are more flexible, can be changed
at run-time and can run per document if needed, but are slower than Java Hooks.
187
Dynamic Hooks
Dynamic Hooks are more flexible than Java Hooks, because can be changed at run-time
and can run per document if needed, but are slower than Java Hooks. Look at Hooks for
more information.
To execute hooks against your documents, let your classes to extend OTriggered base
class. Then define a custom property for the event you're interested on. The available
events are:
188
Class level hooks
Class level hooks are defined for all the documents that rely to a class. Below an
example to setup a hook that acts at class level against Invoice documents.
Now let's create the function "invoiceCreated" in Javascript that print to console the
invoice number created.
189
Document level hook
You could need to define a special action only against one or more documents. To do
this, let your class to extend OTriggered class.
Example to execute a trigger, as Javascript function, against an existent Profile class, for
all the documents with property account = 'Premium'. The trigger will be called to prevent
deletion of documents:
CREATE FUNCTION preventDeletion "throw new java.lang.RuntimeException('Cannot delete Premium profile ' +
190
(Native) Java Hooks
Java Hooks are the fastest hooks. Write a Java Hook if you need the best performance
on execution. Look at Hooks for more information.
When you want to catch event from Document only, the best way to create a hook is to
extend the ODocumentHookAbstract abstract class. You can specify what classes you're
interested in. In this way the callbacks will be called only to the document of specified
classes. Classes are polymorphic so filtering works against specified classes and all
191
sub-classes.
You can specify only the class you're interested or the classes you want to exclude.
Example to include only the Client and Provider classes:
Example to get called for all the changes on documents of any class but Log :
In Hook methods, you can access to the dirty fields and the original values. Example:
Self registration
Hooks could be installed only to certain database instances, but in most of the cases
you'd need to register it for each instance. To do this programmatically you can intercept
the onOpen() and onCreate() callbacks from OrientDB to install hooks. All you need is to
implement the ODatabaseLifecycleListener interface. Example:
192
public void onOpen(final ODatabase iDatabase) {
// REGISTER THE HOOK
((ODatabaseComplex<?>)iDatabase).registerHook(this);
}
@Override
public void onCreate(final ODatabase iDatabase) {
// REGISTER THE HOOK
((ODatabaseComplex<?>)iDatabase).registerHook(this);
}
@Override
public void onClose(final ODatabase iDatabase) {
// REGISTER THE HOOK
((ODatabaseComplex<?>)iDatabase).unregisterHook(this);
}
...
public RESULT onRecordBeforeCreate(final ODocument iDocument) {
// DO SOMETHING BEFORE THE DOCUMENT IS CREATED
...
}
...
}
Hook example
In this example the events before-create and after-delete are called during the save()
of the Profile object where:
...
p = new Profile("Luca");
p.setAge(10000);
database.save(p);
...
}
/**
* Custom validation rules
*/
@Override
193
public void onRecordBeforeCreate(ORecord<?> iRecord){
if( iRecord instanceof ODocument ){
ODocument doc = (ODocument) iRecord;
Integer age = doc .field( "age" );
if( age != null && age > 130 )
throw new OValidationException("Invalid age");
}
}
/**
* On deletion removes the reference back.
*/
@Override
public void onRecordAfterDelete(ORecord<?> iRecord){
if( iRecord instanceof ODocument ){
ODocument doc = (ODocument) iRecord;
To let a hook to be executed in the Server space you've to register it in the server
orientdb-server-config.xml configuration file.
switch( iType ){
case BEFORE_CREATE:
194
case BEFORE_UPDATE: {
if( doc.getClassName().equals("Customer") ){
Integer age = doc .field( "age" );
if( age != null && age > 130 )
throw new OValidationException("Invalid age");
}
break;
}
case BEFORE_DELETE: {
if( doc.getClassName().equals("Customer") ){
final ODatabaseRecord db = ODatabaseRecordThreadLocal.INSTANCE.get();
if( !db.getUser().getName().equals( "admin" ) )
throw new OSecurityException("Only admin can delete customers");
}
break;
}
}
}
}
Once implemented create a .jar file containing your class and put it under the
$ORIENTDB_HOME/lib directory.
Change the orientdb-server-config.xml file adding your hook inside the <hooks> tag. The
position can be one of following values FIRST , EARLY , REGULAR , LATE , LAST :
Configurable hooks
If your hook must be configurable with external parameters write the parameters in the
orientdb-server-config.xml file:
And in your Java class implement the config() method to read the parameter:
195
private String userCanDelete;
...
public void config(OServer oServer, OServerParameterConfiguration[] iParams) {
for (OServerParameterConfiguration param : iParams) {
if (param.name.equalsIgnoreCase("userCanDelete")) {
userCanDelete = param.value;
}
}
}
...
196
API
OrientDB supports 3 kinds of drivers:
Native binary remote, that talks directly against the TCP/IP socket using the binary
protocol
HTTP REST/JSON, that talks directly against the TCP/IP socket using the HTTP
protocol
Java wrapped, as a layer that links in some way the native Java driver. This is
pretty easy for languages that run into the JVM like Scala, Groovy and JRuby
This is the list of the known drivers to use OrientDB through different languages:
To execute Gremlin
Gremlin-Node queries against a
remote OrientDB server
Uses
Doctrine ODM OrientDB- High level framework to
use OrientDB from PHP
PHP
197
.NET driver for Binary Official Driver
OrientDB
Compass HTTP
Binary protocol
OrientDB-C Binary compatibles with C++
and other languages
that supports C calls
OrientDB4R HTTP
To help Scala
Scala utilities and tests Native developers using
OrientDB
Clojure binding of
Blueprints API
OrientDB-Android is a
198
OrientDB Android Porting the Android platform by
David Wu
199
Supported standards
This is the list of the library to use OrientDB by using such standard:
TinkerPop Blueprints
TinkerPop Blueprints, the standard for Graph Databases. OrientDB is 100% compliant
with latest version
JDO
JDO 2.2 and JPA 2 by using the Data Nucleus adapter: datanucleus
200
Graph or Document API?
In OrientDB, we created 2 different APIs: Document API and Graph API. The Graph API
works on top of the Document API. The Document API contains the Document,
Key/Value and Object Oriented models.
|| ||
_||_ ||
\ / ||
\/ _||_
+-------------+ \ /
| Graph API | \/
+-------------+-----------------+
| Document API |
+-------------------------------+
| Key/Value and Object Oriented |
+-------------------------------+
201
Graph API
With OrientDB 2.0, we improved our Graph API to support all models in just one Multi-
Model API. This API usually covers 80% of use cases, so this could be the default API
you should use if you're starting with OrientDB.
In this way:
Your Data ('records' in the RDBMS world) is modeled as Vertices and Edges. You
can store properties on both.
You can still work in Schema-Less, Schema-Full or Hybrid modes.
Relationships are modeled as Bidirectional Edges. If Lightweight edge setting is
active, OrientDB uses Lightweight Edges in cases where edges have no properties,
so it has the same impact on speed and space as with Document LINKs, but with
the additional bonus to have bidirectional connections. This means you can use the
MOVE VERTEX command to refactor your graph with no broken LINKs. For more
information how Edges are managed look at Lightweight Edges.
202
Document API
What about the remaining 20%? In the case where you need a Document Database
(keeping the additional OrientDB features, like LINKs) or you come from the Document
Database world, using the Document API could be the right choice.
203
SQL
When it comes to query languages, SQL is the mostly widely recognized standard. The
majority of developers have experience and are comfortable with SQL. For this reason
Orient DB uses SQL as it's query language and adds some extensions to enable graph
functionality. There are a few differences between the standard SQL syntax and that
supported by OrientDB, but for the most part, it should feel very natural. The differences
are covered in the OrientDB SQL dialect section of this page.
Many SQL commands share the WHERE condition. Keywords and class names in
OrientDB SQL are case insensitive. Field names and values are case sensitive. In the
following examples keywords are in uppercase but this is not strictly required.
For example, if you have a class MyClass with a field named id , then the following SQL
statements are equivalent:
The following is NOT equivalent. Notice that the field name 'ID' is not the same as 'id'.
204
Automatic usage of indexes
OrientDB allows you to execute queries against any field, indexed or not-indexed. The
SQL engine automatically recognizes if any indexes can be used to speed up execution.
You can also query any indexes directly by using index: as a target. Example:
205
Extra resources
SQL expression syntax
Where clause
Operators
Functions
Pagination
Pivoting-With-Query
SQL batch
206
OrientDB SQL dialect
OrientDB supports SQL as a query language with some differences compared with SQL.
Orient Technologies decided to avoid creating Yet-Another-Query-Language. Instead we
started from familiar SQL with extensions to work with graphs. We prefer to focus on
standards.
If you want learn SQL, there are many online courses such as:
207
JOINs
The most important difference between OrientDB and a Relational Database is that
relationships are represented by LINKS instead of JOINs.
For this reason, the classic JOIN syntax is not supported. OrientDB uses the "dot ( . )
notation" to navigate LINKS . Example 1 : In SQL you might create a join such as:
SELECT *
FROM Employee A, City B
WHERE A.city = B.id
AND B.name = 'Rome'
This is much more straight forward and powerful! If you use multiple JOINs, the
OrientDB SQL equivalent will be an even larger benefit. Example 2: In SQL you might
create a join such as:
SELECT *
FROM Employee A, City B, Country C,
WHERE A.city = B.id
AND B.country = C.id
AND C.name = 'Italy'
208
Projections
In SQL projections are mandatory and you can use the star character * to include all of
the fields. With OrientDB this type of projection is optional. Example: In SQL to select all
of the columns of Customer you would write:
209
DISTINCT
In SQL, DISTINCT is a keyword but in OrientDB it is a function, so if your query is:
210
HAVING
OrientDB does not support the HAVING keyword, but with a nested query it's easy to
obtain the same result. Example in SQL:
This groups all of the salaries by city and extracts the result of aggregates with the total
salary greater than 1,000 dollars. In OrientDB the HAVING conditions go in a select
statement in the predicate:
SELECT FROM (
SELECT city, SUM(salary) AS salary
FROM Employee
GROUP BY city
) WHERE salary > 1000
211
Select from multiple targets
OrientDB allows only one class (classes are equivalent to tables in this discussion) as
opposed to SQL, which allows for many tables as the target. If you want to select from 2
classes, you have to execute 2 sub queries and join them with the UNIONALL function:
SELECT FROM E, V
In OrientDB, you can accomplish this with a few variable definitions and by using the
expand function to the union:
212
SQL - Filtering
The Where condition is shared among many SQL commands.
213
Syntax
[<item>] <operator> <item>
214
Items
And item can be:
Available
What Description Example since
where
Document field part. To tags[name='Hi'] or
know more about field tags[0-3] IN
field<indexes> part look at the full ('Hello') and 1.0rc5
syntax: employees IS
Document_Field_Part
NOT NULL
where distance(x,
functions Any function between y, 52.20472, 0.9.25
the defined ones 0.14056 ) <= 30
215
Record attributes
select
@this returns the record it self @this.toJSON() 0.9.25
from Account
@size returns the record size in bytes @size > 1024 0.9.21
216
Operators
Conditional Operators
any = Equals to
record,
string (as INSTANCEOF Used to check if the record extends a
class class
name)
used with
89cd72a14eb5493801e99a43c5034685.
Current limitation is that it must be the
unique condition of a query. When used
217
string CONTAINSTEXT against an indexed field, a lookup in the
index will be performed with the text
specified as key. When there is no index
a simple Java indexOf will be performed.
So the result set could be different if you
have an index or not on that field
218
Logical Operators
Not
NOT true if the condition is not name = 'Luke' supported
false yet
219
Mathematics Operators
Starting from v1.4 OrientDB supports the eval() function to execute complex
operations. Example:
220
Methods
Also called "Field Operators", are are treated on a separate page.
221
Functions
All the SQL functions are treated on a separate page.
222
Variables
OrientDB supports variables managed in the context of the command/query. By default
some variables are created. Below the table with the available variables:
223
SQL - Functions
SQL Functions are all the functions bundled with OrientDB SQL engine. You can create
your own Database Functions in any language supported by JVM. Look also to SQL
Methods.
SQL Functions can work in 2 ways based on the fact that receive 1 or more parameters:
224
Aggregated mode
When only one parameter is passed. They aggregate the result in only one record. The
classic example is the sum():
This will always return 1 record with the sum of salary field.
225
Inline mode
When two or more parameters are passed:
This will return the sum of the field "salary", "extra" and "benefits" as "total". In case you
need to use a function as inline when you've only one parameter, then add a second one
like "null":
In this case first() function doesn't aggregate everything in only one record, but
returns one record per Profile where the firstFriend is the first item of the collection
received as parameter.
226
Bundled functions
Functions by category
shortestPath() variance()
dijkstra() stddev()
Functions by name
ifnull() |in() | inE() | inV() | | intersect() |list() | map() | min() | | max() | median() | mode() |
out() | | outE() | outV() | percentile() | set() | | shortestPath() |stddev()|sum()|sysdate()| |
traversedElement() | traversedEdge() | traversedVertex() | union() | | uuid()| variance() |
out()
Get the adjacent outgoing vertices starting from the current record as Vertex.
227
Syntax: out([<label-1>][,<label-n>]*)
Example
Get all the outgoing vertices from all the Vehicle vertices:
Get all the incoming vertices connected with edges with label (class) "Eats" and
"Favorited" from all the Restaurant vertices in Rome:
in()
Get the adjacent incoming vertices starting from the current record as Vertex.
Syntax: in([<label-1>][,<label-n>]*)
Example
Get all the incoming vertices from all the Vehicle vertices:
Get all the incoming vertices connected with edges with label (class) "Friend" and
"Brother":
228
both()
Get the adjacent outgoing and incoming vertices starting from the current record as
Vertex.
Syntax: both([<label1>][,<label-n>]*)
Example
Get all the incoming and outgoing vertices from vertex with rid #13:33:
Get all the incoming and outgoing vertices connected with edges with label (class)
"Friend" and "Brother":
outE()
Get the adjacent outgoing edges starting from the current record as Vertex.
Syntax: outE([<label1>][,<label-n>]*)
Example
Get all the outgoing edges of type "Eats" from all the SocialNetworkProfile vertices:
229
SELECT outE('Eats') from SocialNetworkProfile
inE()
Get the adjacent incoming edges starting from the current record as Vertex.
Syntax: inE([<label1>][,<label-n>]*)
Example
Get all the incoming edges of type "Eats" from the Restaurant 'Bella Napoli':
bothE()
Get the adjacent outgoing and incoming edges starting from the current record as
Vertex.
Syntax: bothE([<label1>][,<label-n>]*)
Example
Get both incoming and outgoing edges from all the vertices:
Get all the incoming and outgoing edges of type "Friend" from the Profile with nick 'Jay'
230
SELECT bothE('Friend') from Profile where nick = 'Jay'
outV()
Syntax: outV()
Example
inV()
Syntax: inV()
Example
eval()
Syntax: eval('<expression>')
Example
231
coalesce()
Returns the first field/value not null parameter. If no field/value is not null, returns null.
Syntax: coalesce(<field|value>)
Example
if()
Evaluates a condition (first parameters) and returns the second parameter if the
condition is true, the third one otherwise
Example:
select if(eval("name = 'John'"), "My name is John", "My name is not John") from Person
ifnull()
Example
232
expand()
Syntax: expand(<field>)
Example
flatten()
Syntax: flatten(<field>)
Example
first()
Retrieves only the first item of multi-value fields (arrays, collections and maps). For non
multi-value types just returns the value.
Syntax: first(<field>)
233
Available since: 1.2.0
Example
last()
Retrieves only the last item of multi-value fields (arrays, collections and maps). For non
multi-value types just returns the value.
Syntax: last(<field>)
Example
count()
Counts the records that match the query condition. If * is not used as a field, then the
record will be counted only if the field content is not null.
Syntax: count(<field>)
Example
min()
234
Returns the minimum value. If invoked with more than one parameters, the function
doesn't aggregate, but returns the minimum value between all the arguments.
Example
Returns the minimum value between 'salary1', 'salary2' and 'salary3' fields.
max()
Returns the maximum value. If invoked with more than one parameters, the function
doesn't aggregate, but returns the maximum value between all the arguments.
Example
Returns the maximum value between 'salary1', 'salary2' and 'salary3' fields.
235
avg()
Syntax: avg(<field>)
Example
sum()
Syntax: sum(<field>)
Example
date()
Returns a date formatting a string. <date-as-string> is the date in string format, and
<format> is the date format following these rules. If no format is specified, then the
default database format is used.
Example
236
select from Account where created <= date('2012-07-02', 'yyyy-MM-dd')
sysdate()
Example
format()
Formats a value using the String.format() conventions. Look here for more information.
Example
select format("%d - Mr. %s %s (%s)", id, name, surname, address) from Account
dijkstra()
237
Available since: 1.3.0
Example
shortestPath()
Returns the shortest path between two vertices. Direction can be OUT (default), IN or
BOTH.
Example
distance()
Returns the distance between two points in the globe using the Haversine algorithm.
Coordinates must be as degrees.
Example
distinct()
238
Syntax: distinct(<field>)
Retrieves only unique data entries depending on the field you have specified as
argument. The main difference compared to standard SQL DISTINCT is that with
OrientDB, a function with parenthesis and only one field can be specified.
Example
union()
Works as aggregate or inline. If only one argument is passed than aggregates, otherwise
executes, and returns, a UNION of the collections received as parameters. Works also
with no collection values.
Example
intersect()
Works as aggregate or inline. If only one argument is passed than aggregates, otherwise
executes, and returns, the INTERSECTION of the collections received as parameters.
239
Available since: 1.0rc2
Example
difference()
Works as aggregate or inline. If only one argument is passed than aggregates, otherwise
executes, and returns, the DIFFERENCE between the collections received as
parameters.
Example
```sql
select difference(inEdges, outEdges) from OGraphVertex
set()
Adds a value to a set. The first time the set is created. If <value> is a collection, then is
merged with the set, otherwise <value> is added to the set.
Syntax: set(<field>)
Example
240
SELECT name, set(roles.name) as roles FROM OUser
list()
Adds a value to a list. The first time the list is created. If <value> is a collection, then is
merged with the list, otherwise <value> is added to the list.
Syntax: list(<field>)
Example
map()
Adds a value to a map. The first time the map is created. If <value> is a map, then is
merged with the map, otherwise the pair <key> and <value> is added to the map as new
entry.
Example
traversedElement()
241
Where:
<index> is the starting item to retrieve. Value >= 0 means absolute position in the
traversed stack. 0 means the first record. Negative values are counted from the end:
-1 means last one, -2 means the record before last one, etc.
<items> , optional, by default is 1. If >1 a collection of items is returned
Example
SELECT traversedElement(-1) FROM ( TRAVERSE out() from #34:3232 WHILE $depth <= 10 )
SELECT traversedElement(-1, 3) FROM ( TRAVERSE out() from #34:3232 WHILE $depth <= 10 )
traversedEdge()
Where:
<index> is the starting edge to retrieve. Value >= 0 means absolute position in the
traversed stack. 0 means the first record. Negative values are counted from the end:
-1 means last one, -2 means the edge before last one, etc.
<items> , optional, by default is 1. If >1 a collection of edges is returned
Example
242
SELECT traversedEdge(-1) FROM ( TRAVERSE outE(), inV() from #34:3232 WHILE $depth <= 10 )
SELECT traversedEdge(-1, 3) FROM ( TRAVERSE outE(), inV() from #34:3232 WHILE $depth <= 10 )
traversedVertex()
Where:
<index> is the starting vertex to retrieve. Value >= 0 means absolute position in the
traversed stack. 0 means the first vertex. Negative values are counted from the end:
-1 means last one, -2 means the vertex before last one, etc.
<items> , optional, by default is 1. If >1 a collection of vertices is returned
Example
SELECT traversedVertex(-1) FROM ( TRAVERSE out() from #34:3232 WHILE $depth <= 10 )
SELECT traversedVertex(-1, 3) FROM ( TRAVERSE out() from #34:3232 WHILE $depth <= 10 )
mode()
243
Returns the values that occur with the greatest frequency. Nulls are ignored in the
calculation.
Syntax: mode(<field>)
Example
median()
Returns the middle value or an interpolated value that represent the middle value after
the values are sorted. Nulls are ignored in the calculation.
Syntax: median(<field>)
Example
percentile()
Returns the nth percentiles (the values that cut off the first n percent of the field values
when it is sorted in ascending order). Nulls are ignored in the calculation.
Examples
244
select percentile(salary, 25, 75) as IQR from Account
variance()
Returns the middle variance: the average of the squared differences from the mean.
Nulls are ignored in the calculation.
Syntax: variance(<field>)
Example
stddev()
Returns the standard deviation: the measure of how spread out values are. Nulls are
ignored in the calculation.
Syntax: stddev(<field>)
Example
uuid()
Generates a UUID as a 128-bits value using the Leach-Salz variant. For more
information look at: http://docs.oracle.com/javase/6/docs/api/java/util/UUID.html.
245
Syntax: uuid()
Example
246
Custom functions
The SQL engine can be extended with custom functions written with a Scripting
language or via Java.
Database's function
247
SQL Methods are similar to SQL functions but they apply to values. In Object Oriented
paradigm they are called "methods", as functions related to a class. So what's the
difference between a function and a method?
As you can see the method is executed against a field/value. Methods can receive
parameters, like functions. You can concatenate N operators in sequence. Note:
operators are case-insensitive.
248
Bundled methods
Methods by category
asInteger() trim()
asList() replace()
asLong() length()
asMap() subString()
asSet() toLowerCase()
asString() toUpperCase()
normalize() hash()
format()
Methods by name
[]
249
Execute an expression against the item. An item can be a multi-value object like a map,
a list, an array or a document. For documents and maps, the item must be a string. For
lists and arrays, the index is a number.
Syntax: <value>[<expression>]
document,
map,
list,
array
Examples
History
.append()
Syntax: <value>.append(<value>)
string
Examples
250
select name.append(' ').append(surname) from Employee
History
.asBoolean()
Transforms the field into a Boolean type. If the origin type is a string, then "true" and
"false" is checked. If it's a number then 1 means TRUE while 0 means FALSE.
Syntax: <value>.asBoolean()
string,
short,
int,
long
Examples
History
.asDate()
Syntax: <value>.asDate()
251
string,
long
Examples
Time is stored as long type measuring milliseconds since a particular day. Returns all
the records where time is before the year 2010:
History
.asDateTime()
Transforms the field into a Date type but parsing also the time information.
Syntax: <value>.asDateTime()
string,
long
Examples
Time is stored as long type measuring milliseconds since a particular day. Returns all
the records where time is before the year 2010:
History
252
.asDecimal()
Transforms the field into an Decimal type. Use Decimal type when treat currencies.
Syntax: <value>.asDecimal()
any
Examples
History
.asFloat()
Syntax: <value>.asFloat()
any
Examples
History
253
.asInteger()
Syntax: <value>.asInteger()
any
Examples
History
.asList()
Transforms the value in a List. If it's a single item, a new list is created.
Syntax: <value>.asList()
any
Examples
History
254
.asLong()
Syntax: <value>.asLong()
any
Examples
History
.asMap()
Transforms the value in a Map where even items are the keys and odd items are values.
Syntax: <value>.asMap()
collections
Examples
History
255
.asSet()
Transforms the value in a Set. If it's a single item, a new set is created. Sets doesn't
allow duplicates.
Syntax: <value>.asSet()
any
Examples
History
.asString()
Syntax: <value>.asString()
any
Examples
History
256
0.9.14: First version
.charAt()
Returns the character of the string contained in the position 'position'. 'position' starts
from 0 to string length.
Syntax: <value>.charAt(<position>)
string
Examples
History
.convert()
Syntax: <value>.convert(<type>)
any
Examples
257
History
.exclude()
Syntax: <value>.exclude(<field-name>[,]*)
document record
Examples
.format()
Returns the value formatted using the common "printf" syntax. For the complete
reference goto Java Formatter JavaDoc.
Syntax: <value>.format(<format>)
any
Examples
History
258
0.9.8: First version
.hash()
Returns the hash of the field. Supports all the algorithms available in the JVM.
string
Example
History
.include()
Syntax: <value>.include(<field-name>[,]*)
document record
Examples
259
History
.indexOf()
string
Examples
History
.javaType()
Syntax: <value>.javaType()
any
Examples
260
Prints the Java type used to store dates:
History
.keys()
Returns the map's keys as a separate set. Useful to use in conjunction with IN,
CONTAINS and CONTAINSALL operators.
Syntax: <value>.keys()
maps
documents
Examples
History
.left()
Returns a substring of the original cutting from the begin and getting 'len' characters.
Syntax: <value>.left(<length>)
261
string
Examples
History
.length()
Returns the length of the string. If the string is null 0 will be returned.
Syntax: <value>.length()
string
Examples
History
.normalize()
Form can be NDF, NFD, NFKC, NFKD. Default is NDF. pattern-matching if not defined is
"\p{InCombiningDiacriticalMarks}+". For more information look at Unicode Standard.
262
string
Examples
History
263
- 1.4.0: First version
.prefix()
Syntax: <value>.prefix('<string>')
string
Examples
History
.remove()
Syntax: <value>.remove(<item>*)
collection
Examples
History
264
.removeAll()
Syntax: <value>.removeAll(<item>*)
collection
Examples
History
.replace()
string
Examples
History
265
.right()
Returns a substring of the original cutting from the end of the string 'lenght' characters.
Syntax: <value>.right(<length>)
string
Examples
History
.size()
Syntax: <value>.size()
collection
Examples
History
266
0.9.7: First version
.subString()
Returns a substring of the original cutting from 'begin' and getting 'length' characters.
'begin' starts from 0 to string length - 1.
string
Examples
Get all the items where the name begins with an "L":
History
.trim()
Returns the original string removing white spaces from the begin and the end.
Syntax: <value>.trim()
string
Examples
267
History
.toJSON()
Syntax: <value>.toJSON([<format>])
Where:
format optional, allows custom formatting rules. Rules are the following:
type to include the fields' types in the "@fieldTypes" attribute
rid to include records's RIDs as attribute "@rid"
version to include records' versions in the attribute "@version"
class to include the class name in the attribute "@class"
attribSameRow put all the attributes in the same row
indent is the indent level as integer. By Default no ident is used
fetchPlan is the FetchPlan to use while fetching linked records
alwaysFetchEmbedded to always fetch embedded records (without
considering the fetch plan)
dateAsLong to return dates (Date and Datetime types) as long numers
prettyPrint indent the returning JSON in readeable (pretty) way
record
Examples
History
268
.toLowerCase()
Syntax: <value>.toLowerCase()
string
Examples
History
269
- 0.9.7: First version
.toUpperCase()
Syntax: <value>.toUpperCase()
string
Examples
History
.type()
Syntax: <value>.type()
any
Examples
History
270
1.0rc1: First version
.values()
Returns the map's values as a separate collection. Useful to use in conjunction with IN,
CONTAINS and CONTAINSALL operators.
Syntax: <value>.values()
maps
documents
Examples
History
271
- 1.0rc1: First version
272
SQL Batch
OrientDB allows execution of arbitrary scripts written in Javascript or any scripting
language installed in the JVM. OrientDB supports a minimal SQL engine to allow a batch
of commands.
Batch of commands are very useful when you have to execute multiple things at the
server side avoiding the network roundtrip for each command.
SQL Batch supports all the OrientDB SQL commands, plus the following:
begin
273
See also
Javascript-Command
274
Optimistic transaction
Example to create a new vertex in a Transaction and attach it to an existent vertex by
creating a new edge between them. If a concurrent modification occurs, repeat the
transaction up to 100 times:
begin
let account = create vertex Account set name = 'Luke'
let city = select from City where name = 'London'
let edge = create edge Lives from $account to $city
commit retry 100
return $edge
275
Pessimistic transaction
This script above used an Optimistic approach: in case of conflict it retries up top 100
times by re-executing the entire transaction (commit retry 100). To follow a Pessimistic
approach by locking the records, try this:
begin
let account = create vertex Account set name = 'Luke'
let city = select from City where name = 'London' lock record
let edge = create edge Lives from $account to $city
commit
return $edge
Note the "lock record" after the select. This means the returning records will be locked
until commit (or rollback). In this way concurrent updates against London will wait for this
transaction to complete.
NOTE: locks inside transactions works ONLY against MEMORY storage, we're working
to provide such feature also against plocal. Stay tuned (Issue
https://github.com/orientechnologies/orientdb/issues/1677)
276
Java API
This can be used by Java API with:
database.open("admin", "admin");
Remember to put one command per line (postfix it with \n) or use the semicolon (;) as
separator.
277
HTTP REST API
And via HTTP REST interface
(https://github.com/orientechnologies/orientdb/issues/2056). Execute a POST against
/batch URL by sending a payload in this format:
{ "transaction" : false,
"operations" : [
{
"type" : "script",
"language" : "sql",
"script" : <text>
}
]
}
Example:
{ "transaction" : false,
"operations" : [
{
"type" : "script",
"language" : "sql",
"script" : [ "begin;let account = create vertex Account set name = 'Luke';let city =select from Cit
}
]
}
To separate commands use semicolon (;) or linefeed (\n). Starting from release 1.7 the
"script" property can be an array of strings to put each command on separate item,
example:
{ "transaction" : false,
"operations" : [
{
"type" : "script",
"language" : "sql",
"script" : [ "begin",
"let account = create vertex Account set name = 'Luke'",
"let city =select from City where name = 'London'",
"create edge Lives from $account to $city",
"commit retry 100" ]
}
]
}
278
Hope this new feature will simplify your development improving performance.
What about having more complex constructs like IF, FOR, etc? If you need more
complexity, we suggest you to use Javascript as language that already support all these
concepts.
279
OrientDB supports pagination natively. Pagination doesn't consume server side
resources because no cursors are used. Only RecordIDs are used as pointers to the
physical position in the cluster.
280
Use the SKIP-LIMIT
The first and simpler way to do pagination is to use the SKIP / LIMIT approach. This is
the slower way because OrientDB repeats the query and just skips the first X records
from the result. Syntax:
Where:
Example
281
Use the RID-LIMIT
This method is faster than the SKIP - LIMIT because OrientDB will begin the scan from
the starting RID. OrientDB can seek the first record in about O(1) time. The downside is
that it's more complex to use.
The trick here is to execute the query multiple times setting the LIMIT as the page size
and using the greater than > operator against @rid . The lower-rid is the starting point
to search, for example #10:300 .
Syntax:
SELECT FROM <target> WHERE @rid > <lower-rid> ... [LIMIT <max-records>]
Where:
In this way, OrientDB will start to scan the cluster from the given position lower-rid + 1.
After the first call, the lower-rid will be the rid of the last record returned by the previous
call. To scan the cluster from the beginning, use #-1:-1 as lower-rid .
Handle it by hand
database.open("admin", "admin");
final OSQLSynchQuery<ODocument> query = new OSQLSynchQuery<ODocument>("select from Customer where @rid >
ORID last = new ORecordId();
while (!resultset.isEmpty()) {
last = resultset.get(resultset.size() - 1).getIdentity();
resultset = database.query(query, last);
}
database.close();
Automatic management
In order to simplify the pagination, the OSQLSynchQuery object (usually used in queries)
282
keeps track of the current page and, if executed multiple times, it advances page to page
automatically without using the > operator.
Example:
283
Usage of indexes
This is the faster way to achieve pagination with large clusters.
If you've defined an index, you can use it to paginate results. An example is to get all the
names next to Jay limiting it to 20:
284
Sequences and auto-increment
OrientDB doesn't support serial (autoincrement), so you can manage your own counter
in this way (example using SQL):
And then every time you need a new number you can do:
BEGIN
let $counter = UPDATE counter INCREMENT value = 1 WHERE name = 'mycounter' return after
INSERT INTO items SET id = $counter.value, qty = 10, price = 1000
COMMIT
285
SQL Commands
Create
Alter Database
Traverse Property (console Revoke
only)
Drop
Truncate Drop Database Create
Class Property (console function
only)
Truncate
Cluster
Truncate
Record
286
SQL - SELECT
Orient supports the SQL language to execute queries against the databas engine. Take
a look at the operators and Functions. To learn the main differences in comparison to
the SQL-92 standard, take a look at: OrientDB SQL.
287
Syntax
Projections, optionally, is the data you want to extract from the query as the result
set. Look at Projections. Available since 0.9.25.
Target can be a class, cluster, single RID, set of RIDs or index values sorted by
ascending or descending key order (index values were added in 1.7.7). Class is the
class name on which to execute the query. Similarly, specifying cluster with the
cluster: prefix executes the query within that cluster only. You can fetch records
not from a cluster but instead from an index using the following prefixes:
indexvalues: , indexvaluesasc: or indexvaluesdesc: . If you are using indexvalues: or
indexvaluesasc: prefix records will be sorted in ascending order of index keys. If you
are using indexvaluesdesc: prefix records will be sorted in descending order of index
keys. Use one or more RIDs to specify one or a small set of records. This is a useful
in order to specify a starting point when navigating graphs.
WHERE condition is common to the other SQL commands and is described in a
dedicated section of the documentation.
LET is the part that binds context variables to be used in projections, conditions or
sub-queries
GROUP BY is in accordance to the standard SQL syntax specifying the field to
perform the grouping. The current release supports only 1 field.
ORDER BY is in accordance to the standard SQL syntax specifying fields with an
optional ASC or DESC (default is ASCending). If you are using a projection in your
query, ensure the ORDER BY field is included in this projection.
SKIP skips <SkipRecords> the specified number of records starting at the beginning
of the result set. This is useful for Pagination when used in conjunction with LIMIT .
LIMIT sets the maximum number of records returned by the query to <MaxRecords> .
This is useful for Pagination when used in conjunction with SKIP.
FETCHPLAN sets the fetchplan. Example: FETCHPLAN out:3 to pre-fetch up to 3rd
level under out field. Since v1.5.
TIMEOUT sets the maximum timeout in milliseconds for the query. By default the
288
query has no timeout. If you don't specify the strategy, the default strategy
EXCEPTION is used. Strategies are:
RETURN , truncate the result set returning the data collected up until the timeout
EXCEPTION , default one, throws an exception if the timeout has been reached
LOCK manage the locking strategy. By default is "default", that means release the
lock once the record is read, while "record" means to keep the record locked in
exclusive mode in current transaction till the transaction has been finished by a
commit or rollback operation.
PARALLEL execute the query against X concurrent threads, where X is the number
of processors/cores found on the host OS of the query (since 1.7). PARALLEL
execution is useful on long running queries or queries that involve multiple clusters.
On simple queries using PARALLEL could cause a slow down due to the overhead
inherent with using multiple threads
NOTE: Starting from 1.0rc7 the RANGE keyword has been removed. To execute range
queries use the BETWEEN operator against @rid as explained in Pagination.
289
Projections
In the standard SQL, projections are mandatory. In OrientDB if it's omitted, the entire
record set is returned. It is the equivalent of the * keyword. Example:
With all projections except the wildcard "*", a new temporary document is created and
the @rid and @version of the original record will not be included.
If the target field already exists, a progressive number is used as a prefix. Example:
By using the dollar ( $ ) as a prefix, you can access context variables. Each time you run
a command, OrientDB accesses the context to read and write variables. Here's an
example to display the path and depth level of the traversal on all the movies, up to the
5th level of depth:
SELECT $path, $depth FROM ( TRAVERSE * FROM Movie WHERE $depth <= 5 )
290
Examples
Get all the records of type Person where the name starts with Luk :
or
or
Get all the records of type !AnimalType where the collection races contains at least one
entry where the first character of the name, ignoring the case, is equal to e :
Get all the records of type !AnimalType where the collection races contains at least one
entry with name European or Asiatic :
Get all the records of type Profile where any field contains the word danger :
Get any record at any level that has the word danger :
291
Get all the records where up to the 3rd level of connections has some field that contains
the word danger ignoring the case:
select from Profile where any() traverse( 0,3 ) ( any().toUpperCase().indexOf( 'danger' ) > -
Select the name field in upper-case and the country name of the linked city of the
address:
Order by record creation. Starting from 1.7.7, using the expression "order by @rid desc",
allows OrientDB to open an Inverse cursor against clusters. This is extremely fast and
292
doesn't require classic ordering resources (RAM and CPU):
293
LET block
The LET block contains the list of context variables to assign each time a record is
evaluated. These values are destroyed once the query execution ends. Context
variables can be used in projections, conditions and sub-queries.
294
Assign fields to reuse multiple times
OrientDB allows crossing relationships, but if in a single query you need to evaluate the
same branch of nested relationship, it's definitely better using a context variable that
refers to the full relationship.
Example:
Using LET becomes shorter and faster, because the relationships are traversed only
once:
295
Sub-query
LET block allows you to assign a context variable the result of a sub-query. Example:
296
Usage in projection
Context variables can be part of result set used in Projections. The example below
displays the city name of the previous example:
297
Conclusion
To know more about other SQL commands, take a look at SQL commands.
298
History
1.7.7
1.7
299
SQL - INSERT
The Insert command creates a new record in the database. Records can be schema-
less or conform to rules you specify in your model.
300
Syntax
Where:
301
Examples
SQL-92 syntax:
insert into Profile cluster profile_recent (name, surname) values ('Jay', 'Miner' )
insert into Profile cluster profile_recent set name = 'Jay', surname = 'Miner'
302
insert into Employee SET name = 'jack', boss = #11:99
Sub-selects
insert into Diver SET name = 'Luca', buddy = (select from Diver where name = 'Marko')
Sub-inserts
insert into Diver SET name = 'Luca', buddy = (insert into Diver name = 'Marko')
But note that the document will have no class assigned. To create a document of a
certain class but in a different cluster than the default one use:
That will insert the document of type 'employee' in the cluster 'asiaemployee'.
303
insert into Profile (name, address) values ('Luca', { "@type" : "d", "street" : "Melrose Avenue"
insert into GermanyClient from ( select from Client where country = 'Germany' )
Will insert all the records from Client where the country is "Germany".
insert into GermanyClient from ( select *, true as copied from Client where country = 'Germany'
Will insert all the records from Client where the country is "Germany" and will add an
additional field called "copied" with value true.
304
SQL - UPDATE
Update one or more records in the current database. Remember that OrientDB can work
also in schema-less mode, so you can create any field on-the-fly. Furthermore, OrientDB
works on collections. This is the reason why OrientDB SQL has some extensions to
handle collections.
305
Syntax
UPDATE <class>|cluster:<cluster>|<recordID>
[SET|INCREMENT|ADD|REMOVE|PUT <field-name> = <field-value>[,]*]|[CONTENT|MERGE <JSON>]
[UPSERT]
[RETURN <returning> [<returning-expression>]]
[WHERE <conditions>]
[LOCK default|record]
[LIMIT <max-records>] [TIMEOUT <timeout>]
Where:
UPSERT updates a record if it already exists, or inserts a new record if it does not,
all in a single statement. This avoids the need to execute 2 commands, one for the
query and a conditional insert/update. UPSERT requires a WHERE clause and a
class target
RETURN specifies what to return as <returning> . If <returning-expression> is
specified (optional) and returning is BEFORE or AFTER, then the expression value
is returned instead of record. <returning> can be a value between:
COUNT, the default, returns the number of updated records
BEFORE, returns the records before the update
AFTER, returns the records after the update
306
TIMEOUT, if any limits the update operation to a timeout
307
Examples
308
> UPDATE Account SET address={"street":"Melrose Avenue", "city":{"name":"Beverly Hills"}}
In case a single field is returned, the result is wrapped in a record storing value in "result"
field (Just to avoid introducing new serialization there is no primitive-values collection
serialization in binary protocol). Additionally to that, useful fields like version and rid of
original record is provided in corresponding fields. New syntax will allow optimizing
client-server network traffic.
To know more about the SQL syntax used in Orient, take a look at: SQL-Query.
309
SQL - DELETE
The Delete command deletes one or more records from the database. The set of
records involved are taken by the WHERE clause.
NOTE: Don't use SQL DELETE to remove Vertices or Edges but use the DELETE
VERTEX and DELETE EDGE commands that assure the integrity of the graph.
310
Syntax
Where:
LOCK specifies how the record is locked between the load and the delete. It can be
a value between:
DEFAULT, no lock. In case of concurrent delete, the MVCC throws an
exception
RECORD, locks the record during the delete
311
Examples
Delete all the records with surname equals to 'unknown' ignoring the case:
312
SQL - ALTER CLASS
The Alter Class command alters a class in the schema.
313
Syntax
Where:
314
See also
create class
drop class
alter cluster
SQL commands
Console commands
315
Examples
Change the name of the class 'Account':
Adds a cluster by name to a class. If the cluster didn't exist, it's created automatically:
Add custom properties (in this case used in Record level security):
Create a new cluster to the class and set the cluster-selection strategy as "balanced":
316
History
1.7
Added support for CLUSTERSELECTION that sets the strategy used on selecting
the cluster where to create new records
317
SQL - ALTER CLUSTER
The Alter Cluster command updates a cluster.
318
Syntax
Where:
319
automerge , merges the changes
320
See also
create cluster
drop cluster
alter class
SQL commands
Console commands
321
Examples
To know more about other SQL commands, take a look at SQL commands.
322
SQL - ALTER DATABASE
The Alter Database command update database settings.
323
Syntax
324
clusters/files improves read/write performance
CONFLICTSTRATEGY, (since 2.0) is the name of the strategy used to handle
conflicts when OrientDB's MVCC finds an update or delete operation executed
against an old record. The strategy is applied for the entire database, but single
clusters can have own strategy (use ALTER CLUSTER command for this). While it's
possible to inject custom logic by writing a Java class, the out of the box modes are:
version , the default, throw an exception when versions are different
content , in case the version is different checks if the content is changed,
otherwise use the highest version and avoid throwing exception
automerge , merges the changes
325
See also
Console Command Create Database
Console Command Drop Database
326
Examples
Starting from v 1.4, OrientDB can use Lightweight Edges. After v2.0 this is disabled by
default with new databases. To maintain the compatibility with OrientDB 1.4 or minor
execute this commands:
327
History
1.7
Added support for CLUSTERSELECTION that sets the strategy used on selecting
the cluster where to create new records
Added MINIMUMCLUSTERS to pre-create X clusters every time a new class is
created
328
SQL - ALTER PROPERTY
The Alter Property command alters a class's property in the schema.
329
Syntax
Where:
LINKEDCLASS, the linked class name. Accepts a string as value. NULL to remove
it
LINKEDTYPE, the linked type name between those supported:Types. Accepts a
string as value. NULL to remove it
MIN, the minimum value as constraint. Accepts strings, numbers or dates as value.
NULL to remove it
MANDATORY, true if the property is mandatory. Accepts "true" or "false"
MAX, the maximum value as constraint. Accepts strings, numbers or dates as
value. NULL to remove it
NAME, the property name. Accepts a string as value
NOTNULL, the property can't be null. Accepts "true" or "false"
REGEXP the regular expression as constraint. Accepts a string as value. NULL to
remove it
TYPE, the type between those supported:Types Accepts a string as value
COLLATE, set the collate to define the strategy of comparison. By default is case
sensitive. By setting it yo "ci", any comparison will be case-insensitive
CUSTOM Set custom properties. Syntax is <name> = <value> . Example: stereotype =
icon
330
Examples
Set a regexp
To create a property use the Create Property command, to remove a property use the
Drop Property command.
This is a command of the Orient console. To know all the commands go to Console-
Commands.
331
SQL - CREATE CLASS
The Create Class command creates a new class in the schema. NOTE: If a cluster with
the same name exists in the database will be used as default cluster.
332
Syntax
Where:
class is the class name to create. The first character must be alphabetic and others
can be any alphanumeric characters plus underscore _ and dash -.
super-class, optional, is the super-class to extend
clusterId can be a list separated by comma (,)
By default OrientDB creates 1 cluster per class, but this can be changed by setting the
property minimumclusters at database level.
333
Cluster selection strategy
OrientDB, by default, inherits the cluster selection by the database. By default is round-
robin, but you can always change it after creation with alter class command. The
supported strategies are:
default, uses always the Class's defaultClusterId property. This was the default
before 1.7
round-robin, put the Class's configured clusters in a ring and returns a different
cluster every time restarting from the first when the ring is completed
balanced, checks the records in all the clusters and returns the smaller cluster. This
allows the cluster to have all the underlying clusters balanced on size. On adding a
new cluster to an existent class, the new empty cluster will be filled before the
others because more empty then the others. In distributed configuration when
configure clusters on different servers this setting allows to keep the server
balanced with the same amount of data. Calculation of cluster size is made every 5
or more seconds to avoid to slow down insertion
334
See also
alter class
drop class
create cluster
SQL commands
Console commands
335
Examples
Create the class 'Account':
336
Abstract class
Create the class 'Person' as ABSTRACT:
337
SQL - CREATE CLUSTER
The Create Cluster command creates a new cluster in database. Once created, the
cluster can be used to save records by specifying its name during save. If you want to
add the cluster to a class, use rather the Alter Class command using ADDCLUSTER
property.
338
Syntax
Where:
name is the cluster name to create. The first character must be alphabetic and
others can be any alphanumeric characters plus underscore _ and dash -.
position, optional, is the position where to add the cluster. If omitted or it's equals to
'default' the cluster is appended at the end
339
Examples
Create the cluster 'Account':
This is a command of the Orient console. To know all the commands go to Console-
Commands.
340
SQL - CREATE EDGE
This command creates a new Edge into the database. Edges, together with Vertices, are
the main components of a Graph. OrientDB supports polymorphism on edges. The base
class is "E" (before 1.4 was called "OGraphEdge"). Look also how to Create Vertex.
341
Syntax
Where:
class, is the Edge's class name, or "E" if you don't use sub-types
cluster, is the cluster name where to physically store the edge
JSON, is the JSON content to set as record content, instead of field by field
retry, is the number of retries in case of conflict (optimistic approach)
pauseBetweenRetriesInMs, are the milliseconds of delay between retries
342
Examples
Create a new edge type and a new edge of the new type
create edge E1 from #10:3 to #11:4 set brand = 'fiat', name = 'wow'
create edge Watched from (select from account where name = 'Luca') to (select from movies where
343
create edge E from #22:33 to #22:55 content { "name" : "Jay", "surname" : "Miner" }
344
History and compatibility
1.1: first version
1.2: the support for query and collection of RIDs in FROM/TO
1.4: the command uses the Blueprints API under the hood, so if you're working in
Java using the OGraphDatabase API you could experience in some difference how
edges are managed. To force the command to work with the "old" API change the
GraphDB settings described in Graph backward compatibility
2.0: New databases have Lightweight Edges disabled by default, so this command
creates regular edges.
345
SQL - CREATE FUNCTION
The Create Function command creates a new Server-Side function. Functions can be
executed from SQL, HTTP and Java.
346
Syntax
Where:
347
See also
Functions
SQL commands
Console commands
348
Examples
Create function 'test' in Javascript with no parameters:
CREATE FUNCTION allUsersButAdmin "select from ouser where name <> 'admin'" LANGUAGE SQL
349
SQL - CREATE INDEX
Creates a new index. To create an automatic index bound to a schema property use
section "ON" of create index command or use as name the <class.property> notation.
But assure to have created the schema for it before the index. See the example below.
350
Syntax
Where:
If "ON" and key-type sections both exist database validate types of specified properties.
And if types of properties not equals to types specified in key-type list, exception will be
thrown.
List of key types can be used for creation manual composite indexes, but such indexes
don't have fully support yet.
351
See also
SQL Drop Index
Indexes
SQL commands
352
Examples
You can create an index against the edge class if it's containing the begin/end date
range of validity. This is a very common use case with historical graphs. Consider this
File system example:
353
CREATE PROPERTY Has.started DATETIME
CREATE PROPERTY Has.ended DATETIME
CREATE INDEX Has.started_ended ON Has (started, ended) NOTUNIQUE
And then you can retrieve all the edge that existed in 2014:
SELECT FROM Has Where started >= '2014-01-01 00:00:00.000' and ended < '2015-01-01 00:00:00.000'
SELECT outV() FROM Has Where started >= '2014-01-01 00:00:00.000' and ended < '2015-01-01 00:00:00.000'
SELECT inV() FROM Has Where started >= '2014-01-01 00:00:00.000' and ended < '2015-01-01 00:00:00.000'
Null values
Indexes by default ignore null values. For such reason queries against NULL value that
use indexes return no entries.
If you want to index also null values set { ignoreNullValues : false } as metadata.
Example:
354
SQL - CREATE LINK
The Create Link transform two simple values in a link. This is very useful when you're
importing data from a Relational database. In facts in the Relational world relationships
are resolved as foreign keys.
This is not the way to create links in general, but a way to convert two values in two
different classes in a link. To create a link in OrientDB look at Relationships. For more
information about importing a Relational Database into OrientDB look at Import from
RDBMS to Document Model.
Consider this example where the class "Post" has a relationship 1-N to "Comment":
Table Post
+----+----------------+
| Id | Title |
+----+----------------+
| 10 | NoSQL movement |
| 20 | New OrientDB |
+----+----------------+
Table Comment
+----+--------+--------------+
| Id | PostId | Text |
+----+--------+--------------+
| 0 | 10 | First |
| 1 | 10 | Second |
| 21 | 10 | Another |
| 41 | 20 | First again |
| 82 | 20 | Second Again |
+----+--------+--------------+
Using OrientDB, instead, you have direct relationship as in your object model. So the
navigation is from Post to Comment and not viceversa as for Relational model. For this
reason you need to create a link as INVERSE.
355
Syntax
CREATE LINK <link-name> TYPE [<link-type>] FROM <source-class>.<source-property> TO
<destination-class>.<destination-property> [INVERSE]
Where:
link-name is the name of the property for the link. If not expressed will be
overwritten the destination-property field
link-type, optional, is the type to use for the link. In case of inverse relationships
(the most commons) you can specify LINKSET or LINKLIST for 1-N relationships
source-class, is the source class
source-property, is the source property
destination-class, is the destination class
destination-property, is the destination property
INVERSE, tells to create the connection on the opposite direction. This is common
when you've imported 1-N relationships from a RDBMS where they are mapped at
the opposite direction
356
Examples
357
SQL - CREATE PROPERTY
The Create Property command creates a new property in the schema. An existing class
is required to perform this command.
358
Syntax
Where:
359
boolean
integer
short
long
float
double
date
string
binary
embedded
link
byte
360
Examples
Create the property 'name' of type 'STRING' in class 'User':
Create a list of Strings as property 'tags' of type 'EMBEDDEDLIST' in class 'Profile'. The
linked type is 'STRING':
Create the property 'friends' of type 'EMBEDDEDMAP' in class 'Profile'. The linked class
is profile itself (circular references):
361
SQL - CREATE VERTEX
This command creates a new Vertex into the database. Vertices, together with Edges,
are the main components of a Graph. OrientDB supports polymorphism on vertices. The
base class is "V" (before 1.4 was called "OGraphVertex"). Look also how to Create
Edges.
362
Syntax
363
Examples
create vertex
Create a new vertex type and a new vertex of the new type
364
History and Compatibility
1.1: first version
starting from v.1.4 the command uses the Blueprints API under the hood, so if
you're working in Java using the OGraphDatabase API you could experience in
some difference how edges are managed. To force the command to work with the
"old" API change the GraphDB settings described in Graph backward compatibility
365
SQL - MOVE VERTEX
366
Syntax
Where:
source are the vertices to move. This could be one of the following values:
A single vertex by RID. Example: MOVE VERTEX #34:232 TO CLASS:Provider
An array of vertices by RIDs. Example: MOVE VERTEX [#34:232,#34:444] TO
CLASS:Provider
A subquery with vertices as result. All the returning vertices will be moved.
Example: MOVE VERTEX (SELECT FROM V WHERE city = 'Rome') TO CLASS:Provider
destination is the location where to move vertices. Can be one of the followings:
Class, by using the syntax CLASS:<class-name> . Use this to refactor your graph
assigning a new class to vertices
Cluster, by using the syntax CLUSTER:<cluster-name> . Use this to move your
vertices on different clusters in the same class. This is useful on Distributed
Configuration where you can move vertices on other servers
SET optional block contains the pairs of values to assign during the moving. The
syntax is the same as SQL UPDATE. Example: MOVE VERTEX (SELECT FROM V WHERE type
= 'provider') TO CLASS:Provider SET movedOn = Date()
MERGE optional block gets a JSON containing the pairs of values to assign during
the moving. The syntax is the same as SQL UPDATE. Example: MOVE VERTEX (SELECT
FROM V WHERE type = 'provider') TO CLASS:Provider MERGE { author : 'Jay Miner' }
367
See also
Create Vertex
Create Edge
368
History and Compatibility
2.0: first version
369
Examples
It's very common the case when you start modeling your domain in a way, but then you
need more flexibility. On this example we want to split all the "Person" vertices under 2
new sub-types called "Customer" and "Provider" respectively. At the end we declare
Person as abstract class.
OrientDB allows you to scale up by just adding servers. As soon as you add a new
server, OrientDB creates automatically a new cluster with the name of the class plus the
node name. Example: "customer_europe". Partitioning is a best practice when you need
to scale up, specially on writes. If you have a graph with "Customer" vertices and you
want to move some vertices to other server you can move them to the cluster owned by
the server where you want your vertices are moved.
With this example, we're moving all the customers that live in Italy, Germany or UK to
the "customer_europe" cluster assigned to the node "Europe". In this way all the access
to European customers will be faster to the applications connected to the European
node:
370
SQL - DELETE EDGE
This command deletes one or more edges from the database. Use this command if you
work against graphs. The "Delete edge" command takes care to remove all the cross
references to the edge in both "in" and "out" vertices.
371
Syntax
372
History and Compatibility
1.1: first version
1.4: the command uses the Blueprints API under the hood, so if you're working in
Java using the OGraphDatabase API you could experience in some difference how
edges are managed. To force the command to work with the "old" API change the
GraphDB settings described in Graph backward compatibility
373
Examples
Delete edges where date is a property which might exist in one of more edges between
the two vertices:
DELETE EDGE FROM #11:101 TO #11:117 WHERE @class = 'owns' and comment like "regex of forbidden words"
This is the faster alternative to DELETE EDGE WHERE @class = 'owns' and date < "2011-11" :
Deletes edges where in.price shows the condition on 'to vertex' for the edge
DELETE EDGE Owns WHERE date < "2011-11" and in.price >= 202.43
374
Deleting Edge using Java Code:
When User follow a company We create edge between User and company of type
followCompany and CompanyFollowedBy class
375
SQL - DELETE VERTEX
This command deletes one or more vertices from the database. Use this command if
you work against graphs. The "Delete Vertex" (like the Delete Edge) command takes
care to remove all the cross references to the vertices in all the edges involved.
376
Syntax
377
History and Compatibility
1.1: first version
starting from v.1.4 the command uses the Blueprints API under the hood, so if
you're working in Java using the OGraphDatabase API you could experience in
some difference how edges are managed. To force the command to work with the
"old" API change the GraphDB settings described in Graph backward compatibility
378
Examples
Deletes the vertex, and disconnects all vertices pointing towards it:
Deletes all user accounts which are marked with an incoming edge of class
BadBehaviorInForum:
Deletes all those EmailMessages which are marked as spam by isSpam property
Deletes every vertex of class 'Attachment', which has an edge towards it of class
'HasAttachment', with a property 'date' of condition to be all (HasAttachment edges)
which are older than 1990, and secondly, the vertex 'Email' which is connected to class
Attachment has a condition on its property 'from' to be '[email protected]':
DELETE VERTEX Attachment Where in[@Class = 'HasAttachment'].date <= "1990" and in.out[@Class =
379
SQL - DROP CLASS
The Drop Class command removes a class from the schema. NOTE: Pay attention to
maintain the schema coherent. For example avoid to remove classes that are super
classes of others. The associated cluster won't be deleted.
380
Syntax
Where:
381
See also
create class
alter class
alter cluster
SQL commands
Console commands
382
Examples
Remove the class 'Account':
383
SQL - DROP CLUSTER
The Drop Cluster command removes a cluster and all its content. This operation cannot
be rollbacked.
384
Syntax
Where:
385
See also
create cluster
alter cluster
drop class
SQL commands
Console commands
386
Examples
Remove the cluster 'Account':
387
SQL - DROP INDEX
The Drop Index command removes an index on a property defined in the schema.
388
Syntax
Where:
389
See also
SQL Create Index
Indexes
SQL commands
390
Examples
391
SQL - DROP PROPERTY
The Drop Property command removes a property from the schema. This doesn't
remove the property values in records, but just change the schema information. Records
will continue to have the property values if any.
392
Syntax
Where:
393
Examples
Remove the property 'name' in class 'User':
This is a command of the Orient console. To know all the commands go to Console-
Commands.
394
SQL - EXPLAIN
Profiles any command and returns back result of execution. This is useful to know why a
query is slow. Use EXPLAIN as keyword before the command you want to profile.
395
Syntax
EXPLAIN <command>
Metric Description
396
Examples
Profiled command
'{documentReads:1126,documentReadsCompatibleClass:1126,recordReads:1126,elapsed:209,resultType:collection
397
Indexed query
398
SQL - FIND REFERENCES
SQL command to search all records that contains a link to a given record id in the entire
database or a subset of specified class and cluster. Returns a set of record ids.
399
Syntax
Where:
rid is the record id to search. If a sub-query is passed, then all the RIDs returned by
the sub-query will be searched. Sub-query is available since 1.0rc9
class-list list of specific class or cluster, separated by commas, you want to execute
the search in.
400
Examples
Get all the records that contains a link to 5:0
Result example:
RESULT:
+------+-----------------+
| rid | referredBy |
+------+-----------------+
| #5:0 | [#10:23, #30:4] |
+------+-----------------+
Get all the references to the record of the default cluster (available since 1.0rc9):
Get all the records in Profile and !AnimalType classes that contains a link to 5:0 :
Get all the records in Profile cluster and !AnimalType class that contains a link to 5:0
To know more about other SQL commands look at SQL SQL commands.
401
SQL - GRANT
The Grant command changes the permission of a role granting the access to one or
more resources.
402
Syntax
Where:
403
Examples
Grant the permission to update any records in cluster Account to the role "backoffice".
404
SQL - REBUILD INDEXES
The Rebuild Index command rebuilds an automatic index.
405
Syntax
Where:
index-name name of the index. Use * to rebuild all the automatic indices
406
See also
SQL Create Index
SQL Drop Index
Indexes
SQL commands
407
Examples
REBUILD INDEX *
408
SQL - REVOKE
The Revoke command change the permission of a role revoking the access to one or
more resources.
409
Syntax
Where:
410
Examples
Revoke the permission to delete any records in any cluster to the role "backoffice".
411
SQL - TRAVERSE
Traverse is a special command that retrieves the connected records crossing the
relationships. This command works not only with graph API but at document level. This
means you can traverse relationships between invoice and customers without the need
to model the domain using the Graph API.
412
Syntax
TRAVERSE <[class.]field>|*|any()|all()
[FROM <target>]
[LET <Assignment>*]
WHILE <condition>
[LIMIT <max-records>]
[STRATEGY <strategy>]
Fields
Are the list of fields you want to traverse. If * , any() or all() are specified then all the
fields are traversed. This could be costly so to optimize the traverse use the pertinent
fields. You can also specify fields at class level. Polymorphism is supported, so by
specifying Person.city and Customer class extends Person, you will traverse Customer
instances too.
Target
Class is the class name to browse all the record to be traversed. You can avoid to
specify class: as prefix
Cluster with the prefix 'cluster:' is the cluster name where to execute the query
A set of RIDs inside square brackets to specify one or a small set of records. This is
useful to navigate graphs starting from some root nodes
413
A root record specifying its RID
Context
$parent, to access to the parent's context if any. This is useful when the Traverse is
called in a sub-query
$current, current record iterated. To access to the upper level record in nested
queries use $parent.$current
$depth, as the current depth of nesting
$depth, as the current depth of nesting
$path, as the string representation of the current path. Example #6:0.in.#5:0#.out .
You can also display it with -> select $path from (traverse ** from V)
$stack, as the List of operation in the stack. Use it to access to the history of the
traversal. It's a List> where process implementations are:
OTraverseRecordSetProcess, usually the first one it's the base target of
traverse
OTraverseRecordProcess, represent a traversed record
OTraverseFieldProcess, represent a traversal through a record's field
OTraverseMultiValueProcess, use on fields that are multivalue: arrays,
collections and maps
414
Examples
Assuming #10:1234 is the RID of the record to start traversing get all the friends up to
the third level of depth using the BREADTH_FIRST strategy:
In case you want to filter per minimum depth create a predicate in the select. Example
like before but excluding the first target vertex (#10:1234):
select from ( traverse friends from #10:1234 while $depth <= 3 ) where $depth >= 1
NOTE: You can also define the maximum depth in the SELECT clause but it's much
more efficient to set it at the inner TRAVERSE statement because the returning record
sets are already filtered by depth
Traverse command can be combined with SQL SELECT statement to filter the result set.
Below the same example above but filtering by Rome as city:
select from ( traverse friends from #10:1234 while $depth <= 3 ) where city = 'Rome'
415
Another example to extract all the movies of actors that have worked, at least once, in
any movie produced by J.J. Abrams:
select from (
traverse Movie.actors, Actor.movies from (
select from Movie where producer = "J.J. Abrams"
) while $depth <= 3
) where @class = 'Movie'
To return or use the current path in traversal refer to the $path variable:
416
Should I use TRAVERSE or SELECT?
If traversing information, such as relationship names and depth level, are known at priori,
please consider using SELECT instead of TRAVERSE. SELECT is faster on this case.
Example:
This query traverses the "follow" relationship of Twitter accounts getting the 2nd level of
friendship:
SELECT FROM (
TRAVERSE out('follow') FROM TwitterAccounts WHERE $depth <= 2
) WHERE $depth = 2
But can be expressed also with SELECT and it's shorter and faster:
417
Using TRAVERSE with Graph model and API
Even if the TRAVERSE command can be used with any domain model, the place where
is more used is the Graph-Database model.
Following this model all is based on the concepts of the Vertex (or Node) as the class
"V" and the Edge (or Arc, Connection, Link, etc.) as the class "E". So if you want to
traverse in a direction you have to use the class name when declare the traversing
fields. Below the directions:
OUTGOING, use V.out, E.in because vertices are connected with the "out" field
but the edge exits as "in" field.
INCOMING, use V.in, E.out because vertices are connected with the "in" field but
the edge enters as "out" field.
Example of traversing all the outgoing vertices found starting from the vertex with id
#10:3434:
So in a mailing-like domain to find all the messages sent in 1/1/2012 from the user 'Luca'
assuming it's stored in the 'User' Vertex class and that messages are contained in the
'Message' Vertex class. Sent messages are stored as "out" connections of Edge class
'SentMessage':
select from (
traverse V.out, E.in from (
select from User where name = 'Luca'
) while $depth <= 2 and (@class = 'Message' || ( @class = 'SentMessage' and sentOn = '01/01/2012'
) where @class = 'Message'
418
Operator TRAVERSE
Before the introducing of TRAVERSE command OrientDB has the TRAVERSE operator
but worked in the opposite way and it was applied in the WHERE condition.
TRAVERSE operator is deprecated. Please use the TRAVERSE command together with
SELECT command to have much more power!
Where:
minDeep is the minimum deep level to start to apply the conditions. Usually is 0 for
the root vertex or 1 for the just-outgoing vertexes
maxDeep, optionally limits the maximum deep level to reach. -1 means infinite.
Default is -1
fields, optionally tells the field list to traverse. Default is any()
conditions are the conditions to check for any traversed vertex. To know more
about the query syntax see SQL syntax
Examples
419
Example of a query that returns all the vertices that have at least one friend (connected
with out), up to the 3rd degree, that lives in Rome:
select distinct(in.lid) as lid,distinct(in.fid) as fid from (traverse V.out, E.in from #10:
420
SQL - TRUNCATE CLASS
The Truncate Class command deletes the records of all the clusters defined as part of
the class. By default every class has one cluster associated with the same name. This
command acts at lower level then SQL Delete Command.
421
Syntax
Where:
422
Examples
Remove all the record of class "Profile":
See also SQL Delete Command and SQL Truncate Cluster Command. To create a new
class use the Create Class command.
This is a command of the Orient console. To know all the commands go to Console-
Commands.
423
SQL - TRUNCATE CLUSTER
The Truncate Cluster command deletes all the records of a cluster. This command acts
at lower level then SQL Delete Command.
424
Syntax
Where:
425
Examples
Remove all the records in the cluster "Profile":
See also SQL Delete Command and SQL Truncate Class commands.
This is a command of the Orient console. To know all the commands go to Console-
Commands.
426
SQL - TRUNCATE RECORD
The Truncate Record command truncates a record without loading it. Useful when the
record is dirty in any way and can't be loaded correctly.
427
Syntax
Where:
rid RecordID to truncate. To truncate multiple records in one shot, list all the
RecordIDs separated by comma inside squared brackets.
Returns
428
Examples
Truncates the record #20:3:
This is a command of the Orient console. To know all the commands go to Console-
Commands.
429
Java API
OrientDB is written 100% in Java. You can use the native Java APIs without any driver
or adapter. Here the Javadocs.
430
Architecture of components
OrientDB provides 3 different Java APIs to work with OrientDB. Each one has pros and
cons.
Which API to choose between Graph and Document? Look also at Graph-or-Document-
API?.
Graph API
Use OrientDB as a Graph Database working with Vertices and Edges. Graph API is
100% compliant with TinkerPop standard.
Document API
Handles records as documents. Documents are comprised of fields. Fields can be any of
the types supported. Does not need a Java domain POJO, as required for the Object
Database. Can be used as schema-less or schema-base modes.
Object API
431
It's the JPA like interface where POJO are automatically bound to the database as
documents. Can be used in schema-less or schema-based modes. This API hasn't been
improved since OrientDB 1.5. Please consider using Document or Graph API by writing
an additional layer of mapping with your POJO.
432
What to use? Feature Matrix
Other
GraphDBs like
Neo4J or Titan.
Easy to If you used Other DocumentDB like
switch TinkerPop MongoDB and JPA applications
from standard CouchDB
OrientDB is a
drop-in
replacement
* Speed comparison for generic CRUD operations such as query, insertion, update and
deletion. Larger is better. 100% is fastest. In general the price of a high level of
abstraction is a speed penalty, but remember that Orient is orders of magnitude faster
than the classic RDBMS. So using the Object Database gives you a high level of
abstraction with much less code to develop and maintain.
433
Which library do I use?
OrientDB comes with some jar files contained in the lib directory
snappy-*.jar as
optional,
orientdb-
performance pack:
core-*.jar
Core library Always orientdb-nativeos-
*.jar , jna-*.jar
and jna-platform-
*.jar
Base package
with the
orientdb-
protocol and When your application
enterprise-
network talks with a remote
classes
*.jar
shared by server
client and
server
orientdb-
It's used by the server
server-
Server component. Include it
*.jar component only if you're
embedding a server
Contain the
orientdb- javassist.jar ,
object-
Object Include it if you're
persistence-api-
*.jar Database using this interface 1.0.jar
interface
434
Graph API
To use the Graph API include the following jars in your classpath:
orient-commons-*.jar
orientdb-core-*.jar
blueprints-core-*.jar
orientdb-graphdb-*.jar
(blueprints-orient-graph-*.jar only for OrientDB < v1.7)
orientdb-client-*.jar
orientdb-enterprise-*.jar
pipes-*.jar
gremlin-java-*.jar
gremlin-groovy-*.jar
groovy-*.jar
NOTE: Starting from v2.0, Lightweight Edges are disabled by default when new
database are created.
435
Introduction
Tinkerpop is a complete stack of projects to handle Graphs:
436
Get started with Blueprints
OrientDB supports different kind of storages and depends by the Database URL used:
437
Working with the GraphDB
Before working with a graph you need an instance of OrientGraph class. The constructor
gets a URL that is the location of the database. If the database already exists, it will be
opened, otherwise it will be created. In multi-threaded applications use one OrientGraph
instance per thread.
Remember to always close the graph once done using the .shutdown() method.
Example:
438
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
} finally {
graph.shutdown();
}
439
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 until 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 assures that any errors will rollback the
transaction to the previous status for all the involved elements.
NOTE: To work against a graph always use transactional OrientGraph instances and
never non-transactional ones to avoid graph corruption from multi-threaded changes.
440
Working with Vertices 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());
441
Create an edge
An Edge links two vertices 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. Specify null to not
assign it. Example:
442
Retrieve all the Vertices
To retrieve all the vertices use the getVertices() method:
443
Retrieve all the Edges
To retrieve all the vertices use the getEdges()) method:
NOTE: Starting from OrientDB v1.4.x (until 2.0, where the opposite is true) 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.
444
Removing 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);
445
Removing 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 vertices will not be connected
anymore. Example:
graph.removeEdge(lucaKnowsMarko);
446
Set and get properties
Vertices 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);
vertex1.removeProperty("y");
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:
447
Creating Element and properties all together
If you want to create a vertex or an edge while setting the initial properties, the 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:
This creates a new Edge of class Friend between vertices person1 and person2 with the
property since .
Both methods accept a Map<String, Object> as a parameter to set one property per map
entry (see above for the example).
These methods are especially 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.
448
Using 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 indices on the key properties
you use in the query. For example, if you have a query that is looking for all the vertices
with the name 'OrientDB' you do this:
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):
This constraint will be applied to all the Vertex and sub-type instances. To specify an
index against a custom type like the "Customer" vertices use the additional parameter
"class":
You can also have both UNIQUE index against custom types:
To get a vertex or an edge by key prefix use the class name before the property. For the
example above use Customer.name in place of only name to use the index created against
the field name of class Customer :
449
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);
450
Using Non-Transactional Graphs
To speed up operations like on massive insertions you can avoid transactions by using a
different class than 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 inserts and massive operations.
NOTE: Using non-transactional graphs could create corruption in the graph if changes
are made in multiple threads at the same time. So use non-transactional graph instances
only for non multi-threaded operations.
451
Configure the Graph
Starting from v1.6 OrientDB supports configuration of the graph by setting all the
properties during construction:
Default
Name Description value
blueprints.orientdb.url Database -
URL
Saves the
original
element IDs
by using the
property id.
blueprints.orientdb.saveOriginalIds This could be false
useful on
import of a
graph to
preserve
original ids.
Avoids
keeping
blueprints.orientdb.keepInMemoryReferences records in false
memory by
using only
RIDs
Uses the
Edge's label
as OrientDB
blueprints.orientdb.useCustomClassesForEdges class. If it true
doesn't exist
create it under
the hood.
Uses Vertex's
label as
OrientDB
blueprints.orientdb.useCustomClassesForVertex class. If it true
doesn't exist
create it under
the hood.
Stores the
Edge's
relationships
in the Vertex
by using the
Edge's class.
blueprints.orientdb.useVertexFieldsForEdgeLabels This allows true
using multiple
452
fields and
makes faster
traversal by
edge's label
(class).
Uses
lightweight
edges. This
avoids
creating a
physical
blueprints.orientdb.lightweightEdges document per true
edge.
Documents
are created
only when the
Edges have
properties.
Auto starts a
transaction as
soon as the
graph is
blueprints.orientdb.autoStartTx changed by true
adding/remote
vertices and
edges and
properties.
453
Gremlin usage
If you use GREMLIN language with OrientDB remember to initialize it with:
OGremlinHelper.global().create()
454
Multi-Threaded Applications
Multi-threaded applications must use one OrientGraph instance per thread. For more
information about multi-threading look at Java Multi Threading.
455
Blueprints Extensions
OrientDB is a Graph Database on steroids because it merges the graph, document, and
object-oriented worlds together. Below are some of the features exclusive to OrientDB.
456
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 a few variants to the Blueprints methods to work with types.
By default each class has one cluster with the same name. You can add multiple
clusters to the class to allow OrientDB to write vertices and edges on multiple files.
Furthermore working in Distributed Mode each cluster can be configured to be managed
by a different server.
Example:
// SAVE THE VERTEX INTO THE CLUSTER 'PERSON_USA' ASSIGNED TO THE NODE 'USA'
graph.addVertex("class:Person,cluster:Person_usa");
To retrieve all the vertices of Person class use the special getVerticesOfClass(String
className) method:
All the vertices of class Person and all subclasses will be retrieved. This is because by
default 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 :
457
The same variants also apply to the getEdges() method as:
458
Ordered Edges
OrientDB, by default, uses a set to handle the edge collection. Sometimes it's better
having an ordered list to access the edge by an offset. Example:
person.createEdgeProperty(Direction.OUT, "Photos").setOrdered(true);
Every time you access the edge collection the edges are ordered. Below is an example
to print all the photos in an ordered way.
To access the underlying edge list you have to use the Document Database API. Here's
an example to swap the 10th photo with the last.
459
Working on detached elements
When you work with web applications, its very common to query elements and render
them to the user to let him apply some changes. Once the user updates some fields and
presses 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 with OrientDB v1.7 we added two new methods to the Graph API on the
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 allows you to modify the element off-line and to re-attach it once
finished.
Attach
Once the detached element has been modified, to save it back to the database you need
to call the attach() method. It restores the connection between the Graph Element and
the Graph Instance.
Example
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();
}
460
After a while the element is updated (from GUI or by application)
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 an edge against detached elements? No, you can only get/set/remove a
property while is detached. Any other operation that requires the database will throw an
IllegalStateException.
461
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 there has
been an update by another client. This is the reason why you should write your code to
be concurrency-proof by handling the concurrent updating case:
Auto-retry
Starting with v.1.5, transactions are automaticaly retried if a timeout exception occurs.
This happens in case of deadlocks or network latency. By default the AutoRetry setting
is 10, but you can change it or disable it by setting it to 0, by calling:
((OTransactionOptimistic) graph.getRawGraph().getTransaction()).setAutoRetries( 0 );
462
Execute commands
The OrientDB Blueprints implementation allows you to execute commands using SQL,
Javascript, and all the other supported languages.
SQL queries
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 commands
Along with queries, you can execute any SQL command like CREATE VERTEX , UPDATE , or
DELETE VERTEX . In the example below it sets a new property called "local" to true on all the
Customers that live in Rome:
If the command modifies the schema (like create/alter/drop class and create/alter/drop
property commands), remember to force updating of the schema of the database
instance you're using by calling reload() :
463
graph.getRawGraph().getMetadata().getSchema().reload();
SQL batch
To execute multiple SQL commands in a batch, use the OCommandScript and SQL as
the language. This is recommended when creating edges on the server side, to minimize
the network roundtrip:
Database functions
graph.command(
new OCommandFunction("updateAllTheCustomersInCity")).execute("Rome"));
Code
To execute code on 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!'); }"
464
This prints the line "Hello World!" ten times in the server console or in the local console if
the database has been opened in "plocal" mode.
465
Access to the underlying Graph
Since the TinkerPop Blueprints API is quite raw and doesn't provide ad-hoc methods for
very common use cases, you might need to access the underlying ODatabaseGraphTx
object to better use the graph-engine under the hood. Commons operations are:
The OrientGraph class provides the method .getRawGraph() to return the underlying
database: [Document Database].
Example:
466
Security
If you want to use 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.
467
Tuning
Look at the Performance Tuning Blueprints page.
468
Graph Factory
TinkerPop Blueprints standard doesnt define a proper "Factory" to get graph instances.
For this reason OrientDB users that wanted to use a pool of instances had to mix 2
different API: Graph and Document one. Example:
This is the basic way to create the factory, by using the default "admin" user (with
"admin" password by default):
Once the factory is configured you can get a Graph instance to start working.
OrientGraphFactory has 2 methods to retrieve a Transactional and Non-Transactional
instance:
469
OrientGraph txGraph = factory.getTx();
OrientGraphNoTx noTxGraph = factory.getNoTx();
Or again you can configure in the factory the instances you want and use the get()
method every time:
factory.setTransactional(false);
OrientGraphNoTx noTxGraph = (OrientGraphNoTx) factory.get();
To return the Graph instance to the pool, call the shutdown method on graph instance.
shutdown() will not close the graph instance, but will keep open and available for the next
requester:
graph.shutdown();
To release all the instances and free all the resources (in case of pool usage), call the
close():
factory.close();
470
Graph Schema
Although OrientDB can work in schema-less mode, sometimes you need to enforce your
data model using a schema. OrientDB supports schema-full or schema-hybrid solutions
where the second one means to set such constraints only for certain fields and leave the
user to add custom fields to the records. This mode is at class level, so you can have the
"Employee" class as schema-full and "EmployeeInformation" class as schema-less.
Schema-Full: enable the strict-mode at class level and set all the fields as
mandatory
Schema-Less: create classes with no properties. Default mode is non strict-mode
so records can have arbitrary fields
Schema-Hybrid, called also Schema-Mixed is the most used: create classes and
define some fields but leave the record to define own custom fields
NOTE: Changes to the schema are not transactional, so execute them outside a
transaction.
471
Class
A Class, or type, is a concept taken from the Object Oriented paradigm. In OrientDB
defines a type of record. It's the closest concept to a Relational DBMS Table. Class can
be schema-less, schema-full or mixed. A class can inherit from another shaping a tree of
classes. Inheritance means that the sub-class extends the parent one inheriting all the
attributes as they was own.
A class must have at least one cluster defined (as its default cluster), but can support
multiple ones. In this case By default OrientDB will write new records in the default
cluster, but reads will always involve all the defined clusters. When you create a new
class by default a new physical cluster is created with the same name of the class in
lower-case.
The Graph structure is based on two classes: "V" for Vertices and "E" for Edges. These
class are automatically built once a database is built using the mode "graph". If you don't
have these classes just create them (see below).
You can build a graph using V and E instances but it's strongly suggested to use custom
types for vertices and edges.
To create a vertex of type "Account" pass a string with the format "class:<name>" as
vertex id:
Vertex v = graph.addVertex("class:Account");
Since classes are polymorphic if you look for generic Vertices also "Account" instances
are returned:
472
To retrieve only the vertices of "Account" class:
In Blueprints Edges has the concept of "label" to distinguish between edge types. In
OrientDB we binds the concept of Edge label to Edge class. To create an Edge custom
type use the similar method createEdgeType(<name>) :
graph.dropVertexType("Address");
graph.dropEdgeType("Lives");
473
Property
Properties are the fields of the class. In this guide Property is synonym of Field.
Create a property
Once the class has been created, you can define fields (properties). Below an example:
Please note that each field must belong to one of [Types supported types].
accountVertex.dropProperty("name");
The dropped property will not be removed from records unless you explicitly delete them
using the [SQLUpdate SQL UPDATE + REMOVE statement]. Example:
accountVertex.dropProperty("name");
database.command(new OCommandSQL("UPDATE Account REMOVE name")).execute();
Constraints
Minimum value, accepts a string because works also for date ranges setMin()
Maximum value, accepts a string because works also for date ranges setMax()
474
Mandatory, it must be specified setMandatory()
Readonly, it may not be updated after record is created setReadonly()
Not Null, can't be NULL setNotNull()
Unique, doesn't allow duplicates and speedup searches.
Regexp, it must satisfy the Regular expression.
Ordered, specify if edge list must be ordered, so a List will be used in place of Set.
The method is setOrdered()
Example:
profile.createProperty("nick", OType.STRING).setMin("3").setMax("30").setMandatory(true).setNotNull(true)
profile.createIndex("nickIdx", OClass.INDEX_TYPE.UNIQUE, "nick"); // Creates unique constraint
profile.createProperty("name", OType.STRING).setMin("3").setMax("30");
profile.createProperty("surname", OType.STRING).setMin("3").setMax("30");
profile.createProperty("registeredOn", OType.DATE).setMin("2010-01-01 00:00:00");
profile.createProperty("lastAccessOn", OType.DATE).setMin("2010-01-01 00:00:00");
Indexes as constrains
To let to a property value to be UNIQUE use the UNIQUE index as constraint by passing
a Parameter object with key "type":
This constraint will be applied to all the Vertex and sub-types instances. To specify an
index against a custom type use the additional parameter "class":
You can also have both UNIQUE index against custom types:
To get a vertex or an edge by key prefix the class name to the field. For the example
above use "Member.name" in place of only "name" to use the index created against the
475
field "name" of class "Member":
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);
476
Partitioned graphs
This tutorial explains step-by-step how to create partitioned graphs using the Record
Level Security feature introduced in OrientDB 1.2.0. This feature is so powerful we can
totally separate database's records as sand-boxes where each "Restricted" records can't
be accessed by non authorized users. This tutorial demonstrates this sand-boxes works
well also with the GraphDB API and the TinkerPop stack. Partitioning graphs allows to
build real Multi-tenant applications in a breeze.
Requirements:
477
Create a new empty graph database
First open the console of the GraphDB Edition and create the new database "blog" of
type "graph" against the local file-system:
$ cd $ORIENTDB_HOME/bin
$ console.sh
OrientDB console v.1.2.0-SNAPSHOT www.orientechnologies.com
Type 'help' to display all the commands supported.
478
Enable graph partitioning
Now turn on partitioning against graph by letting classes V (Vertex) and E (Edge) to
extend the ORestricted* class. In this way any access to Vertex and Edge instances
can be restricted:
479
Create 2 users
Now let's go creating 2 users: "luca" and "steve". First ask the current roles in database
to know the "writer" role's rid:
---+---------+--------------------+--------------------+--------------------+--------------------
#| RID |name |mode |rules |inheritedRole
---+---------+--------------------+--------------------+--------------------+--------------------
0| #4:0|admin |1 |{} |null
1| #4:1|reader |0 |{database=2, database.schema=2, database.cluster.
2| #4:2|writer |0 |{database=2, database.schema=7, database.cluster.
---+---------+--------------------+--------------------+--------------------+--------------------
Found it, it's the #4:2. Not create 2 users with as first role #4:2 (writer):
orientdb> insert into ouser set name = 'luca', status = 'ACTIVE', password = 'luca', roles = [#
orientdb> insert into ouser set name = 'steve', status = 'ACTIVE', password = 'steve', roles = [#
480
Create a simple graph as user 'Luca'
Now it's time to disconnect and reconnect to the blog database using the new "luca"
user:
orientdb> disconnect
---+---------+--------------------+--------------------+--------------------+--------------------
#| RID |label |name |_allow |out
---+---------+--------------------+--------------------+--------------------+--------------------
0| #9:0|food |Pizza |[1] |[1]
1| #9:1|restaurant |Dante's Pizza |[1] |null |[1]
---+---------+--------------------+--------------------+--------------------+--------------------+-------
481
Create a simple graph as user 'Steve'
Now let's connect to the database using the 'Steve' user and check if there are vertices:
orientdb> disconnect
---+---------+--------------------+--------------------+--------------------+--------------------
#| RID |label |name |_allow |out
---+---------+--------------------+--------------------+--------------------+--------------------
0| #9:2|car |Ferrari Modena |[1] |[1]
1| #9:3|driver |steve |[1] |null |[
---+---------+--------------------+--------------------+--------------------+--------------------+-------
The "Steve" user doesn't see the vertices and edges creates by other users!
482
What happen if we try to connect 2 vertices of different users?
The partition is totally isolated and OrientDB thinks the vertex doesn't exist while it's
present, but invisible to the current user.
483
TinkerPop Stack
Record Level Security feature is very powerful because acts at low level inside the
OrientDB engine. This is why everything works like a charm, even the TinkerPop stack.
Now try to display all the vertices and edges using Gremlin:
[v[#9:2], v[#9:3]]
e[#10:1][#9:2-drive->#9:3]
The same is using other technologies that use the !TinkerPop Blueprints: TinkerPop
Rexter, TinkerPop Pipes, TinkerPop Furnace, TinkerPop Frames and ThinkAurelius
Faunus.
484
Graph Database Comparison
This is a comparison page between GraphDB projects. To know more about the
comparison of DocumentDBs look at this comparison.
We want to keep it always updated with the new products and more features in the
matrix. If any information about any product is not updated or wrong, please change it if
you've the permissions or send an email to any contributors with the link of the source of
the right information.
485
Feature matrix
Transaction
support
ACID ACID
Custom
types Supports
custom types and
polymorphism
Self loops
486
Blueprints support
The products below all support the TinkerPop Blueprints API at different level of
compliance. Below the supported ones. As you can see OrientDB is the most compliant
implementation of TinkerPop Blueprints!
allowsDuplicateEdges
allowsSelfLoops
isPersistent
supportsVertexIteration
supportsEdgeIteration
supportsVertexIndex
supportsEdgeIndex
ignoresSuppliedIds
supportsTransactions
allowSerializableObjectProperty
allowBooleanProperty
487
allowDoubleProperty
allowFloatProperty
allowIntegerProperty
allowPrimitiveArrayProperty
allowUniformListProperty
allowMixedListProperty
allowLongProperty
allowMapProperty
allowStringProperty
488
Micro benchmark
The table below reports the time to complete the Blueprints Test Suite. This is not a
benchmark between GraphDBs and unfortunately doesn't exist a public benchmark
shared by all the vendors :-(
So this table is just to give an idea about the performance of each implementation in
every single module it supports. The support is based on the compliance level reported
in the table above. For the test default settings were used. To run these tests on your
own machine follow these simple instructions.
Lower means faster. In bold the fastest implementation for each module.
All the tests are executed against the same HW/SW configuration: MacBook Pro
(Retina) 2013 - 16 GB Ram - MacOSX 12.3.0 - SDD 7200rpm. Similar results executed
on Linux CentOS.
489
Run the tests
To run the Blueprints Test Suite you need java6+, Apache Maven and Git. Follow these
simple steps:
490
Lightweight Edges
OrientDB supports Lightweight Edges from v1.4. Lightweight Edges are like regular
edges, but they have no identity on database. Lightweight edges can be used only
when:
By avoiding the creation of the underlying Document, Lightweight Edges have the
same impact on speed and space as with Document LINKs, but with the additional
bonus to have bidirectional connections. This means you can use the MOVE VERTEX
command to refactor your graph with no broken LINKs.
491
Regular Edge representation
Look at the figure below. With Regular Edges both vertices (#10:33 and #10:12) are
connected through an Edge Document (#17:11). The outgoing out_Friend property in
#10:33 document is a set of LINKs with #17:11 as item. Instead, in document #10:12 the
relationship is as incoming, so the property in_Friend is used with the LINK to the same
Edge #17:11.
When you cross this relationship, OrientDB loads the Edge document #17:11 to resolve
the other part of the relationship.
492
Lightweight Edge representation
With Lightweight Edge, instead, there is no Edge document, but both vertices (#10:33
and #10:12) are connected directly to each other. The outgoing out_Friend property in
#10:33 document contains the direct LINK to the vertex #10:12. The same happens on
Vertex document #10:12, where the relationship is as incoming and the property
in_Friend contains the direct LINK to vertex #10:33.
When you cross this relationship, OrientDB doesn't need to load any edge to resolve the
other part of the relationship. Furthermore no edge document is created.
+---------------------+ +---------------------+
| Account Vertex | | Account Vertex |
| #10:33 | | #10:12 |
+---------------------+ +---------------------+
|out_Friend: [#10:12] |<-->|in_Friend: [#10:33] |
+---------------------+ +---------------------+
Starting from OrientDB v2.0, Lightweight Edges are disabled by default with new
databases. This is because having regular edges makes easier to act on edges from
SQL. Many issues from beginner users were on Lightweight Edges. If you want to use
Lightweight Edges, enable it via API:
Or via SQL:
Changing useLightweightEdges setting to true , will not transform previous edges, but all
new edges could be Lightweight Edges if they meet the requirements.
493
When use Lightweight Edges?
These are the PROS and CONS of Lightweight Edges vs Regular Edges:
PROS:
CONS:
494
Document API
To use the Document API include the following jars in your classpath:
orient-commons-*.jar
orientdb-core-*.jar
If you're using the Document Database interface connected to a remote server (not
local/embedded mode) include also:
orientdb-client-*.jar
orientdb-enterprise-*.jar
495
Introduction
The Orient Document DB is the base of higher-level implementation like Object-
Database and Graph-Database. The Document Database API has the following
features:
db.close();
This is the very first example. While the code is pretty clear and easy to understand
please note that we haven't declared the type "Person" before now. When an
ODocument instance is saved, the declared type "Person" will be created without
constraints. To declare persistent classes look at the Schema management.
496
Use the database
Before to execute any operation you need an opened database instance. You can open
an existent database or create a new one. Databases instances aren't thread safe, so
use one database per thread.
Before to open or create a database instance you need a valid URL. URL is where the
database is available. URL says what kind of database will be used. For example
memory: means in-memory only database, plocal: is for embedded ones and remote: to
use a remote database hosted on an up & running DBServer OrientDB Server instance.
For more information look at Database URL.
try {
// YOUR CODE
} finally {
db.close();
}
If you are using a remote storage (url starts with "remote:") assure the server is up &
running and include the orientdb-client.jar file in your classpath.
497
Multi-threading
The ODatabaseDocumentTx class is non thread-safe. For this reason use different
ODatabaseDocumentTx instances by multiple threads. They will share the same
Storage instance (with the same URL) and the same level-2 cache. For more information
look at Multi-Threading with Java.
498
Create a new database
In local filesystem
On a remote server
To create a database in a remote server you need the user/password of the remote
OrientDB Server instance. By default the "root" user is created on first startup of the
server. Check this in the file config/orientdb-server-config.xml, where you will also find
the password.
To create a new document database called dbname on dbhost using filesystem storage
(as opposed to in-memory storage):
new OServerAdmin("remote:dbhost")
.connect("root", "kjhsdjfsdh128438ejhj")
.createDatabase("dbname","document","local").close();
499
Open a database
The database instance will share the connection versus the storage. if it's a "local"
storage, then all the database instances will be synchronized on it. If it's a "remote"
storage then the network connection will be shared among all the database instances.
One of most common use cases is to reuse the database, avoiding to create it every
time. It's also the typical scenario of the Web applications. Instead of creating a new
ODatabaseDocumentTx instance all the times, get an available instance from the pool:
Remember to always close the database instance using the close() database method
like a classic non-pooled database. In this case the database will be not closed for real,
but the instance will be released to the pool, ready to be reused by future requests. The
best is to use a try/finally block to avoid cases where the database instance remains
open, just like the example above.
Global pool
By default OrientDB provide a global pool declared with maximum 20 instances. Use it
with: ODatabaseDocumentPool.global() .
To create your own pool build it and call the setup(min, max) method to define minimum
and maximum managed instances. Remember to close it when the pool is not more
500
used. Example:
501
Schema
OrientDB can work in schema-full (like RDBMS), schema-less (like many NoSQL
Document databases) and in schema-hybrid mode. For more information about the
Schema look at the Schema page.
To use the schema with documents create the ODocument instance using the
ODocument(String className) constructor passing the class name. If the class hasn't been
declared, it's created automatically with no fields. This can't work during transaction
because schema changes can't be applied in transactional context.
502
Security
Few NoSQL solutions supports security. OrientDB does it. To know more about it look at
Security.
To manage the security get the Security Manager and use it to work with users and
roles. Example:
OSecurity sm = db.getMetadata().getSecurity();
OUser user = sm.createUser("god", "god", new String[] { "admin" } );
503
Create a new document
ODocument instances can be saved by calling the save() method against the object
itself. Note that the behaviour depends on the running transaction, if any. See
Transactions.
504
Retrieve documents
505
Browse all the records of a class
506
Count records of a class
507
Execute a query
Although OrientDB is part of the NoSQL database community, it supports a subset of
SQL that allows it to process links to documents and graphs.
Asynchronous query
OrientDB supports asynchronous queries. The result is not collected and returned like
synchronous ones (see above) but a callback is called every time a record satisfy the
predicates:
database.command(
new OSQLAsynchQuery<ODocument>("select * from animal where name = 'Gipsy'",
new OCommandResultListener() {
resultCount = 0;
@Override
public boolean result(Object iRecord) {
resultCount++;
ODocument doc = (ODocument) iRecord;
// DO SOMETHING WITH THE DOCUMENT
@Override
public void end() {
}
})).execute();
Asynchronous queries are useful to manage big result sets because don't allocate
memory to collect results.
Prepared query
Prepared query are quite similar to the Prepared Statement of JDBC. Prepared queries
508
are pre-parsed so on multiple execution of the same query are faster than classic SQL
queries. Furthermore the pre-parsing doesn't allow SQL Injection. Note: prepared
queries (parameter substition) only works with select statements (but not select
statements within other types of queries such as "create vertex").
? is positional parameter
:<par> is named parameter
OrientDB is a graph database. This means that traversing is very efficient. You can use
this feature to optimize queries. A common technique is the Pivoting.
SQL Commands
509
If the command modifies the schema (like create/alter/drop class and create/alter/drop
property commands), remember to force updating of the schema of the database
instance you're using:
db.getMetadata().getSchema().reload();
510
Traverse records
Traversing is the operation to cross documents by links (relationships). OrientDB is a
graph database so this operation is much much more efficient than executing a JOIN in
the relational databases. To know more about traversing look at the Java traverse API.
The example below traverses, for each movie, all the connected records up to the 5th
depth level.
System.out.println(id);
}
511
Update a document
Any persistent document can be updated by using the Java API and then by calling the
db.save() method. Alternatively, you can call the document's save() method to
synchronize the changes to the database. The behaviour depends on the transaction
begun, if any. See Transactions.
512
Delete a document
To delete a document call the delete() method on the document instance that's loaded.
The behaviour depends on the transaction begun, if any. See Transactions.
animal.delete();
513
Transactions
Transactions are a practical way to group a set of operations together. OrientDB
supports ACID transactions so that all or none of the operations succeed. The database
always remains consistent. For more information look at Transactions.
Transactions are managed at the database level. Nested transactions are currently not
supported. A database instance can only have one transaction running. The database's
methods to handle transactions are:
begin() to start a new transaction. If a transaction was already running, it's rolled
back and a new one is begun.
commit() makes changes persistent. If an error occurs during commit the
transaction is rolled back and an OTransactionException exception is raised.
rollback() aborts a transaction. All the changes will be lost.
514
Optimistic approach
The current release of OrientDB only supports OPTIMISTIC transactions where no lock
is kept and all operations are checked at commit time. This improves concurrency but
can throw an OConcurrentModificationException exception in the case where records are
modified by concurrent clients or threads. In this scenario, the client code can reload the
updated records and repeat the transaction.
Optimistic transactions keep all the changes in memory in the client. If you're using
remote storage no changes are sent to the server until commit() is called. All the
changes will be transferred in a block. This reduces network latency, speeds-up the
execution, and increases concurrency. This is a big difference compared to most
Relational DBMS where, during a transaction, changes are sent immediately to the
server.
515
Usage
Transactions are committed only when the commit() method is called and no errors
occur. The most common usage of transactions is to enclose all the database operations
inside a try/finally block. On closing of the database ("finally" block) if a pending
transaction is running it will be rolled back automatically. Look at this example:
try {
db.begin();
// YOUR CODE
db.commit();
} finally {
db.close();
}
516
Index API
Even though you can use Indices via SQL, the best and most efficient way is to use the
Java API.
The main class to use to work with indices is the IndexManager. To get the
implementation of the IndexManager use:
The Index Manager allows you to manage the index life-cycle for creating, deleting, and
retrieving an index instance. The most common usage is with a single index. You can
get the reference to an index by using:
Where "Profile.name" is the index name. Note that by default OrientDB assigns the
name as <class>.<property> for automatic indices created against a class's property.
The OIndex interface is similar to a Java Map and provides methods to get, put, remove,
and count items. The following are examples of retrieving records using a UNIQUE index
against a name field and a NOTUNIQUE index against a gender field:
While automatic indices are managed automatically by OrientDB hooks, the manual
indices can be used to store any value. To create a new entry use the put() :
517
OIndex<?> addressbook = database.getMetadata().getIndexManager().getIndex("addressbook");
518
Resources
Javadoc: JavaDoc
OrientDB Studio Web tool.
519
Schema
Although OrientDB can work in schema-less mode, sometimes you need to enforce your
data model using a schema. OrientDB supports schema-full or schema-hybrid solutions
where the latter means to set such constraints only for certain fields and to leave the
user to add custom fields on the records. This mode is at a class level, so you can have
an "Employee" class as schema-full and an "EmployeeInformation" class as schema-
less.
Schema-Full: enables the strict-mode at class level and sets all the fields as
mandatory.
Schema-Less: creates classes with no properties. Default mode is non strict-mode
so records can have arbitrary fields.
Schema-Hybrid, also called Schema-Mixed is the most used: creates classes and
define some fields but allows the user to define custom fields.
NOTE: Changes to the schema are not transactional, so execute them outside a
transaction.
To gain access to the schema APIs you get the OMetadata object from database
instance you're using and then call its getSchema() method.
520
Class
A Class is a concept taken from the Object Oriented paradigm. In OrientDB a class
defines a type of record. It's the closest concept to a relational database table. A Class
can be schema-less, schema-full, or mixed.
A Class can inherit from another class. This [#Inheritance] means that the sub-class
extends the parent class, inheriting all its attributes as if they were its own.
Each class has its own clusters that can be logical (by default) or physical. A class must
have at least one cluster defined (as its default cluster), but can support multiple ones. In
this case By default OrientDB will write new records in the default cluster, but reads will
always involve all the defined clusters.
When you create a new class, by default, a new physical cluster is created with the
same name as the class (in lowercase).
521
Create a persistent class
Each class contains one or more properties (also called fields). This mode is similar to
the classic relational DBMS approach where you define tables before storing records.
To create a new Vertex or Edge type you have to extend the "V" and "E" classes,
respectively. Example:
522
Get a persistent class
To retrieve a persistent class use the getClass(String) method. If the class does not exist
then null is returned.
523
Drop a persistent class
To drop a persistent class use the OSchema.dropClass(String) method.
database.getMetadata().getSchema().dropClass("Account");
The records of the removed class will not be deleted unless you explicitly delete them
before dropping the class. Example:
524
Constraints
To work in schema-full mode set the strict mode at the class level by calling the
setStrictMode(true) method. In this case, all the properties of the record must be
predefined.
525
Property
Properties are the fields of the class. In this guide a property is synonymous with a field.
526
Create the Class property
Once the class has been created, you can define fields (properties). Below is an
example:
Please note that each field must belong to one of these Types.
527
Drop the Class property
To drop a persistent class property use the OClass.dropProperty(String) method.
database.getMetadata().getSchema().getClass("Account").dropProperty("name");
The dropped property will not be removed from records unless you explicitly delete them
using the [SQLUpdate SQL UPDATE + REMOVE statement]. Example:
database.getMetadata().getSchema().getClass("Account").dropProperty("name");
database.command(new OCommandSQL("UPDATE Account REMOVE name")).execute();
528
Define relationships
OrientDB supports two types of relationships: referenced and embedded.
Referenced relationships
OrientDB uses a direct link to the referenced record(s) without the need of a costly JOIN
as does the relational world. Example:
customer
Record A -------------> Record B
CLASS=Invoice CLASS=Customer
RID=5:23 RID=10:2
Record A will contain the reference to the Record B in the property called "customer".
Note that both records are reachable by any other records since they have a
[Concepts#RecordID RecordID].
1-1 and N-1 referenced relationships are expressed using the LINK type.
In this case records of class "Invoice" will link to a record of class "Customer" using the
field "customer".
1-N and N-M referenced relationships are expressed using the collection of links such
as:
529
LINKMAP as an ordered map of links with String key. It doesn't accept duplicated
keys
db.getMetadata().getSchema().save();
Embedded relationships
Embedded records, instead, are contained inside the record that embeds them. It's a
kind of relationship stronger than the [#Referenced_relationships reference]. The
embedded record will not have its own [Concepts#RecordID RecordID] since it can't be
directly referenced by other records. It's only accessible via the container record. If the
container record is deleted, then the embedded record will be deleted too. Example:
address
Record A <>----------> Record B
CLASS=Account CLASS=Address
RID=5:23 NO RID!
Record A will contain the entire Record B in the property called "address". Record B can
be reached only by traversing the container record.
Example:
1-1 and N-1 referenced relationships are expressed using the EMBEDDED type.
530
OClass address = database.getMetadata().getSchema().createClass("Address");
In this case, records of class "Account" will embed a record of class "Address".
1-N and N-M referenced relationships are expressed using the collection of links such
as:
531
Constraints
OrientDB supports a number of constraints for each field:
Minimum value, accepts a string because it also works for date ranges setMin()
Maximum value, accepts a string because it also works for date ranges setMax()
Mandatory, must be specified setMandatory()
Readonly, may not be updated after record is created setReadonly()
Not Null, cannot be NULL setNotNull()
Unique, doesn't allow duplicates and speeds up searches.
Regexp, must satisfy the Regular expression.
Example:
profile.createProperty("nick", OType.STRING).setMin("3").setMax("30").setMandatory(true).setNotNull(true)
profile.createIndex("nickIdx", OClass.INDEX_TYPE.UNIQUE, "nick"); // Creates unique constraint
profile.createProperty("name", OType.STRING).setMin("3").setMax("30");
profile.createProperty("surname", OType.STRING).setMin("3").setMax("30");
profile.createProperty("registeredOn", OType.DATE).setMin("2010-01-01 00:00:00");
profile.createProperty("lastAccessOn", OType.DATE).setMin("2010-01-01 00:00:00");
Indexes as constraints
To ensure that a property value is UNIQUE use the UNIQUE index as a constraint:
532
Working with Fields
OrientDB has a powerful way to extract parts of a Document field. This applies to the
Java API, SQL Where conditions, and SQL projections.
533
Extract punctual items
Single item
Single items
Following the tags example above, the expression tags[0,2] will return a list with [Smart,
'Cool'].
Range items
Inside square brackets put the lower and upper bounds of an item, separated by "-".
Following the tags example above, the expression tags[1-2] returns ['Geek', 'Cool'].
Example:
With lists and arrays you can pick an item element from a range:
534
and single items:
Condition
Inside the square brackets you can specify a condition. Today only the equals condition
is supported.
Example:
employees[label = 'Ferrari']
Use in graphs
You can cross a graph using a projection. This an example of traversing all the retrieved
nodes with name "Tom". "out" is outEdges and it's a collection. Previously, a collection
couldn't be traversed with the . notation. Example:
This retrieves all the vertices connected to the outgoing edges from the Vertex with
name = 'Tom'.
A collection can be filtered with the equals operator. This an example of traversing all the
retrieved nodes with name "Tom". The traversal crosses the out edges but only where
the linked (in) Vertex has the label "Ferrari" and then forward to the:
535
SELECT out[in.@class = 'Car'] FROM v WHERE name = 'Tom'
Or both:
As you can see where brackets ([]) follow brackets, the result set is filtered in each step
like a Pipeline.
NOTE: This doesn't replace the support of GREMLIN. GREMLIN is much more powerful
because it does thousands of things more, but it's a simple and, at the same time,
powerful tool to traverse relationships.
Future directions
In the future you will be able to use the full expression of the OrientDB SQL language
inside the square brackets [], like:
But for this you have to wait yet :-) Monitor the issue:
https://github.com/nuvolabase/orientdb/issues/513
536
Document Database Comparison
This is a comparison page between OrientDB and other DocumentDB projects . To know
more about the comparison of OrientDB against GraphDBs look at this comparison.
NOTE: If any information about any product is not updated or wrong, please send an
email to the committers with the link of the source of the right information. Thanks!
537
Features matrix
538
Object API
Note: The object database has been refactored since the release 1.0. If you use the
previous one look at: Old Implementation ODatabaseObjectTx.
539
Requirements
To use the Object APi include the following jars in your classpath:
orient-commons-*.jar
orientdb-core-*.jar
orientdb-object-*.jar
If you're using the Object Database interface connected to a remote server (not
local/embedded mode) include also:
orientdb-client-*.jar
orientdb-enterprise-*.jar
540
Introduction
The OrientDB Object Interface works on top of the Document-Database and works like
an Object Database: manages Java objects directly. It uses the Java Reflection to
register the classes and Javassist tool to manage the Object-to-Document conversion.
Please consider that the Java Reflection in modern Java Virtual Machines is really fast
and the discovering of Java meta data is made only at first time.
The proxied objects have a ODocument bounded to them and transparently replicate
object modifications. It also allows lazy loading of the fields: they won't be loaded from
the document until the first access. To do so the object MUST implement getters and
setters since the Javassist Proxy is bounded to them. In case of object load, edit an
update all non loaded fields won't be lost.
The database instance has an API to generate new objects already proxied, in case a
non-proxied instance is passed it will be serialized, wrapped around a proxied instance
and returned.
Read more about the Binding between Java Objects and Records.
db.save( account );
541
City rome = new City("Rome", new Country("Italy"));
account.getAddresses().add(new Address("Residence", rome, "Piazza Navona, 1"));
// SAVE THE ACCOUNT: THE DATABASE WILL SERIALIZE THE OBJECT AND GIVE THE PROXIED INSTANCE
account = db.save( account );
542
Connection Pool
One of most common use case is to reuse the database avoiding to create it every time.
It's also the typical scenario of the Web applications.
try {
...
} finally {
db.close();
}
The close() method doesn't close the database but release it to the owner pool. It could
be reused in the future.
543
Database URL
In the example above a database of type Database Object Transactional has been
created using the storage: remote:localhost/petshop. This address is a URL. To know
more about database and storage types go to Database URL.
In this case the storage resides in the same computer of the client, but we're using the
remote storage type. For this reason we need a OrientDB Server instance up and
running. If we would open the database directly bypassing the server we had to use the
local storage type such as "plocal:/usr/local/database/petshop/petshop" where, in this
case, the storage was located in the /usr/local/database/petshop folder on the local file
system.
544
Multi-threading
The OObjectDatabaseTx class is non thread-safe. For this reason use different
OObjectDatabaseTx instances by multiple threads. They will share local cache once
transactions are committed.
545
Inheritance
Starting from the release 0.9.19 OrientDB supports the Inheritance. Using the
ObjectDatabase the inheritance of Documents fully matches the Java inheritance.
When registering a new class Orient will also generate the correct inheritance schema if
not already generated.
Example:
When you save a Company object, OrientDB will save the object as unique Document in
the cluster specified for Company class. When you search between all the Account
instances with:
The search will find all the Account and Company documents that satisfy the query.
546
Use the database
Before to use a database you need to open or create it:
The database instance will share the connection versus the storage. if it's a local
storage, then all the database instances will be synchronized on it. If it's a remote
storage then the network connection will be shared among all the database instances.
db.close();
547
Working with POJO
Please read the POJO binding guide containing all the information about the
management of POJO.
548
Work in schema-less mode
The Object Database can be used totally in schema-less mode as long as the POJO
binding guide requirements are followed. Schema less means that the class must be
created but even without properties. Take a look to this example:
Person p = db.newInstance(Person.class);
p.setName( "Luca" );
p.setSurname( "Garulli" );
p.setCity( new City( "Rome", "Italy" ) );
db.save( p );
db.close();
This is the very first example. While the code it's pretty clear and easy to understand
please note that we didn't declared "Person" structure before now. However Orient has
been able to recognize the new object and save it in persistent way.
549
Work in schema-full mode
In the schema-full mode you need to declare the classes you're using. Each class
contains one or multiple properties. This mode is similar to the classic Relational DBMS
approach where you need to create tables before to store records. To work in schema-
full mode take a look to the Schema APIs page.
550
Create a new object
The best practice to create a Java object is to use the OObjectDatabase.newInstance()
API:
public Person(){
}
However any Java object can be saved by calling the db.save() method, if not created
with the database API will be serialized and saved. In this case the user have to assign
the result of the db.save() method in order to get the proxied instance, if not the
database will always treat the object as a new one. Example:
551
Animal animal = new Animal();
animal.setName( "Gaudi" );
animal.setLocation( "Madrid" );
animal = db.save( animal );
Note that the behaviour depends by the transaction begun if any. See Transactions
552
Browse all the records in a cluster
553
Browse all the records of a class
554
Count records of a class
555
Count records of a cluster
556
Update an object
Any proxied object can be updated using the Java language and then calling the
db.save() method to synchronize the changes to the repository. Behaviour depends by
the transaction begun if any. See Transactions.
animal.setLocation( "Nairobi" );
db.save( animal );
If the db.save() method is called with a non-proxied object the database will create a
new document, even if said object were already saved
557
Delete an object
To delete an object call the db.delete() method on a proxied object. If called on a non-
proxied object the database won't do anything. Behaviour also depends by the
transaction begun if any. See Transactions.
db.delete( animal );
Cascade deleting
Object Database uses JPA annotations to manage cascade deleting. It can be done
expliciting (orphanRemoval = true) or using the CascadeType. The first mode works only
with @OneToOne and @OneToMany annotations, the CascadeType works also with
@ManyToMany annotation.
Example:
@OneToOne(orphanRemoval = true)
private JavaSimpleTestClass simpleClass;
@ManyToMany(cascade = { CascadeType.REMOVE })
private Map<String, Child> children = new HashMap<String, Child>();
@OneToMany(orphanRemoval = true)
private List<Child> list = new ArrayList<Child>();
@OneToMany(orphanRemoval = true)
private Set<Child> set = new HashSet<Child>();
...
so calling
558
database.delete(testClass);
or
will also delete JavaSimpleTestClass instances contained in "simpleClass" field and all
the other documents contained in "children","list" and "test"
559
Attaching and Detaching
Since version 1.1.0 the Object Database provides attach(Object) and detach(Object)
methods to manually manage object to document data transfer.
Attach
With the attach method all data contained in the object will be copied in the associated
document, overwriting all existing informations.
in this way all changes done within the object without using setters will be copied to the
document.
There's also an attachAndSave(Object) methods that after attaching data saves the
object.
Detach
With the detach method all data contained in the document will be copied in the
associated object, overwriting all existing informations. The detach(Object) method
returns a proxied object, if there's a need to get a non proxied detached instance the
detach(Object,boolean) can be used.
560
this will copy all the loaded document information in the object, without needing to call all
getters. This methods returns a proxied instance
this example does the same as before but in this case the detach will return a non
proxied instance.
Since version 1.2 there's also the detachAll(Object, boolean) method that detaches
recursively the entire object tree. This may throw a StackOverflowError with big trees. To
avoid it increase the stack size with -Xss java option. The boolean parameter works the
same as with the detach() method.
561
Execute a query
Although OrientDB is part of NoSQL databases, supports the SQL engine, or at least a
subset of it with such extensions to work with objects and graphs.
Example:
OrientDB is a graph database. This means that traversing is very efficient. You can use
this feature to optimize queries. A common technique is the Pivoting.
SQL Commands
562
Get the ODocument from a POJO
The OObjectDatabase implementation has APIs to get a document from its referencing
object:
In case of non-proxied objects the document will be a new generated one with all object
field serialized in it.
563
Get the POJO from a Record
The Object Database can also create an Object from a record.
564
Schema Generation
Since version 1.5 the Object Database manages automatic Schema generation based
on registered entities. This operation can be
manual
automatic
The ObjectDatabase will generate class properties based on fields declaration if not
created yet.
Changes in class fields (as for type changing or renaming) types won't be
updated, this operation has to be done manually
Version 1.6
Version 1.5
db.setAutomaticSchemaGeneration(true);
db.getEntityManager().registerClass(Foo.class); // Generates the schema for Foo class after registering.
db.getEntityManager().registerEntityClasses("com.mycompany.myapp.mydomainpackage"); // Generates the sche
565
class Foo could look like, generating one field with an Integer and ignoring the String
field.
schema generation will create "text", "reference" and "number" properties as respectively
STRING, LINK and INTEGER types.
Schema synchronizing
Since version 1.6 there's an API to synchronize schema of all registered entities.
db.getMetadata().getSchema().synchronizeSchema();
By calling this API the ObjectDatabase will check all registered entities and generate the
schema if not generated yet. This management is useful on multi-database enviroments
566
567
Old Implementation ODatabaseObjectTx
Until the release 1.0rc9 the Object Database was implemented as the class
com.orientechnologies.orient.db.object.ODatabaseObjectTx . This class is deprecated, but if
you want to continue to use it change the package to:
com.orientechnologies.orient.object.db .
568
Introduction
This implementation and documentation refers to all ODatabaseObjectXXX
deprecated classes.
The Orient Object DB works on top of the Document-Database and it's able to treat Java
objects without the use of pre-processor, byte enhancer or Proxy classes. It uses the
simpler way: the Java Reflection. Please consider that the Java reflection in modern
Java Virtual Machines is really fast and the discovering of Java meta data is made at
first time. Future implementation could use the byte-code enhancement techniques in
addition.
Read more about the Binding between Java Objects and Records.
db.getEntityManager().registerEntityClasses("foo.domain");
db.save( account );
569
Connection Pool
One of most common use case is to reuse the database avoiding to create it every time.
It's also the typical scenario of the Web applications.
...
db.close();
The close() method doesn't close the database but release it to the owner pool. It could
be reused in the future.
570
Inheritance
Starting from the release 0.9.19 OrientDB supports the Inheritance. Using the
ObjectDatabase the inheritance of Documents fully matches the Java inheritance.
Example:
When you save a Company object, OrientDB will save the object as unique Document in
the cluster specified for Company class. When you search between all the Account
instances with:
The search will find all the Account and Company documents that satisfy the query.
571
Object Binding
The ObjectDatabase implementation makes things easier for the Java developer since
the binding between Objects to Records is transparent.
572
How it works?
OrientDB uses Java reflection and Javassist Proxy to bound POJOs to Records directly.
Those proxied instances take care about the synchronization between the POJO and the
underlying record. Every time you invoke a setter method against the POJO, the value is
early bound into the record. Every time you call a getter method the value is retrieved
from the record if the POJO's field value is null. Lazy loading works in this way too.
NOTE: In case a non-proxied object is found it will be serialized, proxied and bounded to
a corresponding Record.
573
Requirements
database.getEntityManager().registerEntityClasses("com.orientechnologies.orient.test.domain");
This must be done only right after the database is created or opened.
574
Naming conventions
OrientDB follows some naming conventions to avoid writing tons of configuration files
but just applying the rule "Convention over Configuration". Below those used:
1. Java classes will be bound to persistent classes defined in the OrientDB schema
with the same name. In OrientDB class names are case insensitive. The Java class
name is taken without the full package. For example registering the class Account in
the package com.orientechnologies.demo , the expected persistent class will be
"Account" and not the entire com.orientechnologies.demo.Account . This means that
class names, in the database, are always unique and can't exist two class with the
same name even if declared in different packages.
2. Java class's attributes will be bound to the fields with the same name in the
persistent classes. Field names are case sensitive.
575
Empty constructor
All the Java classes must have an empty constructor to let to OrientDB to create
instances.
576
Getters and Setters
All your classes must have getters and setters of every field that needs to be persistent
in order to let to OrientDB to manage proxy operations. Getters and Setters also need to
be named same as the declaring field: Example:
// THIS DECLARATION WON'T WORK, ORIENTDB WON'T BE ABLE TO RECOGNIZE THE REAL FIELD NAME
public int getInt(){
return intField;
}
// THIS DECLARATION WON'T WORK, ORIENTDB WON'T BE ABLE TO RECOGNIZE THE REAL FIELD NAME
public void setInt(int iInt){
intField = iInt;
}
}
577
Collections and Maps
To avoid ClassCastExecption when the Java classes have Collections and Maps, the
interface must be used rather than the Java implementation. The classic mistake is to
define in a persistent class the types ArrayList, HashSet, HashMap instead of List, Set
and Map.
Example:
// CORRECT
protected Set<MyElement> correctSet;
// CORRECT
protected Map<String,MyElement> correctMap;
578
POJO binding
OrientDB manages all the POJO attributes in persistent way during read/write from/to
the record, except for the fields those:
OrientDB uses the Java reflection to discovery the POJO classes. This is made only
once during the registration of the domain classes.
579
Default binding
This is the default. It tries to use the getter and setter methods for the field if they exist,
otherwise goes in RAW mode (see below). The convention for the getter is the same as
Java: get<field-name> where field-name is capitalized. The same is for setter but with
'set' as prefix instead of 'get': set<field-name> . If the getter or setter is missing, then the
raw binding will be used.
Example: Field ' String name ' -> getName() and setName(String)
580
Custom binding
Since v1.2 Orient provides the possibility of custom binding extending the
OObjectMethodFilter class and registering it to the wanted class.
@Override
public String getFieldName(Method m) {
if (m.getName().startsWith("get")) {
if (m.getName().contains("UPPERCASE")) {
581
return "UPPERCASEFIELD";
}
return getFieldName(m.getName(), "get");
} else if (m.getName().startsWith("set")) {
if (m.getName().contains("UPPERCASE")) {
return "UPPERCASEFIELD";
}
return getFieldName(m.getName(), "set");
} else
return getFieldName(m.getName(), "is");
}
}
OObjectEntityEnhancer.getInstance().registerClassMethodFilter(CustomMethodFilterTestClass.class,
582
Read a POJO
You can read a POJO from the database in two ways:
When OrientDB loads the record, it creates a new POJO by calling the empty
constructor and filling all the fields available in the source record. If a field is present only
in the record and not in the POJO class, then it will be ignored. Even when the POJO is
updated, any fields in the record that are not available in the POJO class will be
untouched.
583
Save a POJO
You can save a POJO to the database by calling the method save(pojo) . If the POJO is
already a proxied instance, then the database will just save the record bounded to it. In
case the object is not proxied the database will serialize it and save the corresponded
record: In this case the object MUST be reassinged with the one returned by the
database
584
Fetching strategies
Starting from release 0.9.20, OrientDB supports Fetching-Strategies by using the Fetch
Plans. Fetch Plans are used to customize how OrientDB must load linked records. The
ODatabaseObjectTx uses the Fetch Plan also to determine how to bind the linked
records to the POJO by building an object tree.
585
Custom types
To let OrientDB use not supported types use the custom types. They MUST BE
registered before domain classes registration, if not all custom type fields will be treated
as domain classes. In case of registering a custom type that is already register as a
domain class said class will be removed.
Enum declaration
@Override
public String toString() {
return id;
}
586
public Object serializeFieldValue(Class<?> type, SecurityRole role) {
return role.name();
}
OObjectSerializerHelper.bindSerializerContext(null, serializerContext);
OrientDB will use that custom serializer to marshall and unmarshall special types.
587
ODatabaseObjectTx (old deprecated
implementation)
Available since v1.0rc9
The ObjectDatabase implementation makes things easier for the Java developer since
the binding between Objects to Records is transparent.
588
How it works?
OrientDB uses Java reflection and doesn't require that the POJO is enhanced in order to
use it according to the JDO standard and doesn't use Proxies as do many JPA
implementations such as Hibernate. So how can you work with plain POJOs?
Connected mode
Detached mode
Connected mode
Each POJO read from the database is created and tracked by ODatabaseObjectTx. If
you change the POJO and call the ODatabaseObjectTx.save(pojo) method, OrientDB
recognizes the POJO bound with the underlying record and, before saving it, will copy
the POJO attributes to the loaded record.
This works with POJOs that belong to the same ODatabaseObjectTx instance. For
example:
try{
List<Customer> result = db.query( new OSQLSynchQuery<Customer>(db, "select from customer") );
for( Customer c : result ){
c.setAge( 100 );
db.save( c ); // <- AT THIS POINT THE POJO WILL BE RECOGNIZED AS KNOWN BECAUSE IS
// ALWAYS LOADED WITH THIS DB INSTANCE
}
} finally {
db.close;
}
When the db.save( c ) is called, the ODatabaseObjectTx instance already knows obout
it because has been retrieved by using a query through the same instance.
589
Detached mode
In a typical Front-End application you need to load objects, display them to the user,
capture the changes and save them back to the database. Usually this is implemented
by using a database pool in order to avoid leaving a database instance open for the
entire life cycle of the user session.
This is why OrientDB needs to store the record information inside the POJO itself. This
is retrieved when the POJO is saved so it is known if the POJO already has own identity
(has been previously loaded) or not (it's new).
To save the Record Identity you can use the JPA @Id annotation above the property
interested. You can declare it as:
Object, the suggested, in this case OrientDB will store the ORecordId instance
String, in this case OrientDB will store the string representation of the ORecordId
Long, in this case OrientDB will store the right part of the RecordID. This works only
if you've a schema for the class. The left side will be rebuilt at save time by getting
the class id.
Example:
590
return name;
}
public void setSurname(String surname){
this.surname = surname;
}
}
OrientDB will save the Record Identity in the id property even if getter/setter methods
are not created.
If you work with transactions you also need to store the Record Version in the POJO to
allow MVCC. Use the JPA @Version annotation above the property interested. You can
declare it as:
java.lang.Object (suggested) - a
com.orientechnologies.orient.core.version.OSimpleVersion is used
java.lang.Long
java.lang.String
Example:
@Version
private Object version; // DON'T CREATE GETTER/SETTER FOR IT TO PREVENT THE CHANGING BY THE USER APPLIC
// UNLESS IT'S NEEDED
591
Save Mode
Since OrientDB doesn't know what object is changed in a tree of connected objects, by
default it saves all the objects. This could be very expensive for big trees. This is the
reason why you can control manually what is changed or not via a setting in the
ODatabaseObjectTx instance:
db.setSaveOnlyDirty(true);
OGlobalConfiguration.OBJECT_SAVE_ONLY_DIRTY.setValue(true);
db.setDirty(pojo);
db.unsetDirty(pojo);
Dirty mode doesn't affect in memory state of POJOs, so if you change an object without
marking it as dirty, OrientDB doesn't know that the object is changed. Furthermore if you
load the same changed object using the same database instance, the modified object is
returned.
592
Requirements
database.getEntityManager().registerEntityClasses("com.orientechnologies.orient.test.domain");
OrientDB saves only the final part of the class name without the package. For example if
you're using the class Account in the package com.orientechnologies.demo , the persistent
class will be only "Account" and not the entire com.orientechnologies.demo.Account . This
means that class names, in the database, are always unique and can't exist two class
with the same name even if declared in different packages.
Empty constructor
All your classes must have an empty constructor to let to OrientDB to create instances.
593
POJO binding
All the POJO attributes will be read/stored from/into the record except for fields with the
transient modifier. OrientDB uses Java reflection but the discovery of POJO classes is
made only the first time at startup. Java Reflection information is inspected only the first
time to speed up the access to the fields/methods.
Default binding
This is the default. It tries to use the getter and setter methods for the field if they exist,
otherwise goes in RAW mode (see below). The convention for the getter is the same as
Java: get<field-name> where field-name is capitalized. The same is for setter but with
'set' as prefix instead of 'get': set<field-name> . If the getter or setter is missing, then the
raw binding will be used.
Example: Field ' String name ' -> getName() and setName(String)
594
Raw binding
This mode acts at raw level by accessing the field directly. If the field signature is private
or protected, then the accessibility will be forced. This works generally in all the
scenarios except where a custom SecurityManager is defined that denies the change to
the accessibility of the field.
To force this behaviour, use the JPA 2 @AccessType annotation above the relevant
property. For example:
595
Read a POJO
You can read a POJO from the database in two ways:
When OrientDB loads the record, it creates a new POJO by calling the empty
constructor and filling all the fields available in the source record. If a field is present only
in the record and not in the POJO class, then it will be ignored. Even when the POJO is
updated, any fields in the record that are not available in the POJO class will be
untouched.
Callbacks
You can define some methods in the POJO class that are called as callbacks before the
record is read:
Example:
@OAfterDeserialization
public void init(){
status = "Loaded";
}
}
596
Save a POJO
You can save a POJO to the database by calling the method save(pojo) . If the POJO is
already known to the ODatabaseObjectTx instance, then it updates the underlying
record by copying all the POJO attributes to the records (omitting those with transient
modifier).
Callbacks
You can define in the POJO class some methods called as callback before the record is
written:
Example:
@OAfterSerialization
public void free(){
s.close();
}
}
== Fetching strategies =v
Starting from release 0.9.20, OrientDB supports Fetching-Strategies by using the Fetch
Plans. Fetch Plans are used to customize how OrientDB must load linked records. The
ODatabaseObjectTx uses the Fetch Plan also to determine how to bind the linked
records to the POJO by building an object tree.
597
Custom types
To let OrientDB use not supported types use the custom types. Register them before to
register domain classes. Example to manage a BigInteger (that it's not natively
supported):
});
OObjectSerializerHelper.bindSerializerContext(null, serializerContext);
OrientDB will use that custom serializer to marshall and unmarshall special types.
598
Traverse
OrientDB is a graph database. This means that the focal point is on relationships (links)
and how are managed. The standard SQL language is not enough to work with tree or
graphs because it hasn't the concept of recursion. This is the reason why OrientDB
provide a new command to traverse trees and graphs: TRAVERSE. Traversing is the
operation that cross relationships between records (documents, vertexes, nodes, etc).
This operation is much much faster than executing a JOIN in a Relational database.
fields, the fields to traverse. Use * , any() or all() to traverse all the fields of a
document
limit, the maximum number of records to retrieve
predicate, as the predicate to execute against each document traversed. If the
predicate returns true, then the document is returned, otherwise is skipped
strategy, as the way the traverse go in deep:
DEPTH_FIRST, the default,
BREADTH_FIRST,
Traversing strategies
DEPTH_FIRST strategy
This is the default strategy used by OrientDB traversal. It explores as far as possible
along each branch before backtracking. It's implemented using recursion. To know more
look at Depth-First algorithm. Below the ordered steps executed while traversing the
graph using BREADTH_FIRST strategy:
599
BREADTH_FIRST strategy
It inspects all the neighboring nodes, then for each of those neighbor nodes in turn, it
inspects their neighbor nodes which were unvisited, and so on. Compare
BREADTH_FIRST with the equivalent, but more memory-efficient Iterative deepening
DEPTH_FIRST search and contrast with DEPTH_FIRST search. To know more look at
Breadth-First algorithm. Below the ordered steps executed while traversing the graph
using Depth-First strategy:
600
Context variables
During traversing some context variables are managed and can be used by the traverse
condition:
$depth, as an integer that contain the depth level of nesting in traversal. First level
is 0
$path, as a string representation of the current position as the sum of traversed
nodes
$stack, as the stack current node traversed
$history, as the entire collection of visited nodes
601
SQL Traverse
The simpler available way to execute a traversal is using the SQL Traverse command.
Example to retrieve all the records connected from and to Movie records up to the 5th
level of depth:
for (OIdentifiable id : new OSQLSynchQuery<ODocument>("traverse in, out from Movie while $depth <= 5"
System.out.println(id);
}
602
Native Fluent API
Native API supports fluent execution guaranteeing compact and readable syntax. The
main class is OTraverse :
In the traverse command context iContext you can read/put any variable. Traverse
command updates these variables:
603
Example using an anonymous OCommandPredicate as
predicate
System.out.println(id);
}
System.out.println(id);
}
Other examples
OTraverse gets any Iterable, Iterator and Single/Multi OIdentifiable. There's also the
limit() clause. To specify multiple fields use fields(). Full example:
System.out.println( id);
}
604
Multi-Threading
OrientDB supports multi-threads access to the database. ODatabase instances are not
thread-safe, so you've to get an instance per thread and each database instance can be
used only in one thread per time*.
Multiple database instances points to the same storage by using the same URL. In this
case Storage is thread-save and orchestrates requests from different ODatabase*
instances.
ODatabaseDocument1------+
+----> OStorageLocal (url=local:/temp/db)
ODatabaseDocument2------+
schema
index manager
security
These objects are synchronized for concurrent contexts by storing the current database
in the ThreadLocal variable. Every time you create, open or acquire a database
connection, the database instance is automatically set into the current ThreadLocal
space, so in normal use this is hidden from the developer.
The current database is always reset for all common operations like load, save, etc.
rec1.field("name", "Luca");
database1.save(rec1); // force saving in database1 no matter where the record came from
rec2.field("name", "Luke");
database2.save(rec2); // force saving in database2 no matter where the record came from
605
Get current database
To get the current database from the ThreadLocal use:
606
Manual control
Beware when you reuse database instances from different threads or then a thread
handle multiple databases. In this case you can override the current database by calling
this manually:
ODatabaseRecordThreadLocal.INSTANCE.set( database );
ODatabaseRecordThreadLocal.INSTANCE.set( database1 );
rec1.field("name", "Luca");
rec1.save();
ODatabaseRecordThreadLocal.INSTANCE.set( database2 );
rec2.field("name", "Luke");
rec2.save();
607
Custom database factory
Since v1.2 Orient provides an interface to manage custom database management in
MultiThreading cases:
Examples:
When a database is not found in current thread it will be called the factory getDb() to
retrieve the database instance.
608
Close a database
What happens if you are working with two databases and close one? The Thread Local
isn't a stack, so you loose the previous database in use. Example:
db2.close();
// NOW NO DATABASE IS SET IN THREAD LOCAL. TO WORK WITH DB1 SET IT IN THE THREAD LOCAL
ODatabaseRecordThreadLocal.INSTANCE.set( db1 );
...
609
Multi Version Concurrency Control
If two threads update the same record, then the last one receive the following exception:
"OConcurrentModificationException: Cannot update record #X:Y in storage 'Z' because
the version is not the latest. Probably you are updating an old record or it has been
modified by another user (db=vA your=vB)"
This is because every time you update a record, the version is incremented by 1. So the
second update fails checking the current record version in database is higher than the
version contained in the record to update.
if your JVM is the only client is writing to the database then disabling the Level1
cache could be enough: http://code.google.com/p/orient/wiki/Caching#Level_1
disable MVCC by setting the {db.mvcc} parameter to false: java -Ddb.mvcc=false
If you're using the GraphDB api look at: concurrency
If you want to leave the MVCC and write code concurrency proof:
document.save();
break;
} catch( ONeedRetryException e ) {
// RELOAD IT TO GET LAST VERSION
document.reload();
}
}
610
items.add( invoiceItem );
invoice.save();
db.commit();
break;
} catch( OTransactionException e ) {
// RELOAD IT TO GET LAST VERSION
invoice.reload();
}
}
611
What about running transaction?
Transactions are bound to a database, so if you change the current database while a tx
is running, the deleted and saved objects remain attached to the original database
transaction. When it commits, the objects are committed.
Example:
db1.begin();
612
Transaction Propagation
During application development there are situations when a transaction started in one
method should be propagated to other method.
As you can see transaction is started in first method and then new one is started in
second method. So how these transactions should interact with each other. Prior 1.7-rc2
first transaction was rolled back and second was started so were risk that all changes
will be lost.
Since 1.7-rc2 we start nested transaction as part of outer transaction. What does it mean
on practice?
Lets consider example above we may have two possible cases here:
First case:
When nested transaction is started all changes of outer transaction are visible in nested
transaction and then when nested transaction is committed changes are done in nested
613
transaction are not committed they will be committed at the moment when outer
transaction will be committed.
Second case:
When nested transaction is rolled back, changes are done in nested transaction are not
rolled back. But when we commit outer transaction all changes will be rolled back and
ORollbackException will be thrown.
614
Binary Data
OrientDB natively handles binary data, namely BLOB. However, there are some
considerations to take into account based on the type of binary data, the size, the kind of
usage, etc.
Sometimes it's better to store binary records in a different path then default database
directory to benefit of faster HD (like a SSD) or just to go in parallel if the OS and HW
configuration allow this.
All the records in cluster binary will reside in files created under the directory /mnt/ssd .
615
Techniques
Example:
Pros:
Easy to write
100% delegated to the File System
Cons:
616
Store it as a Document field
ODocument class is able to manage binary data in form of byte[] (byte array). Example:
This is the easiest way to keep the binary data inside the database, but it's not really
efficient on large BLOB because the binary content is serialized in Base64. This means
a waste of space (33% more) and a run-time cost in marshalling/unmarshalling.
Also be aware that once the binary data reaches a certain size (10 MB in some recent
testing), the database's performance can decrease significantly. If this occurs, the
solution is to use the ORecordBytes solution described below.
Pros:
Easy to write
Cons:
617
Store it with ORecordBytes
The ORecordBytes class is a record implementation able to store binary content without
conversions (see above). This is the faster way to handle binary data with OrientDB but
needs a separate record to handle it. This technique also offers the highest performance
when storing and retrieving large binary data records.
Example:
Since this is a separate record, the best way to reference it is to link it to a Document
record. Example:
In this way you can access to the binary data by traversing the binary field of the
parent's document record.
You can manipulate directly the buffer and save it back again by calling the setDirty()
against the object:
618
byte[] content = record.toStream();
byte[] newContent = new byte[content*2];
System.arrayCopy(content, 0, newContent, 0, content.length);
record.fromStream(newContent);
record.setDirty();
record.save();
Pros:
Cons:
619
Large content: split in multiple
ORecordBytes
OrientDB can store up to 2Gb as record content. But there are other limitations on
network buffers and file sizes you should tune to reach the 2GB barrier.
However managing big chunks of binary data means having big byte[] structures in
RAM and this could cause a Out Of Memory of the JVM. Many users reported that
splitting the binary data in chunks it's the best solution.
Continuing from the last example we could handle not a single reference against one
ORecordBytes record but multiple references. A One-To-Many relationship. For this
purpose the LINKLIST type fits perfect because maintains the order.
To avoid OrientDB caches in memory large records use the massive insert intent and
keep in the collection the RID, not the entire records.
// SAVE THE CHUNK TO GET THE REFERENCE (IDENTITY) AND FREE FROM THE MEMORY
database.save( chunk );
database.declareIntent( null );
620
record.setLazyLoad(false);
for (OIdentifiable id : (List<OIdentifiable>) record.field("data")) {
ORecordBytes chunk = (ORecordBytes) id.getRecord();
chunk.toOutputStream(out);
chunk.unload();
}
Pros:
Cons:
621
Conclusion
What to use?
622
Web Applications
The database instances are not thread-safe, so each thread needs a own instance. All
the database instances will share the same connection to the storage for the same URL.
For more information look at Java Multi threads and databases.
Java WebApp runs inside a Servlet container with a pool of threads that work the
requests.
Manual control of the database instances from Servlets (or any other server-side
technology like Apache Struts Actions, Spring MVC, etc.)
Automatic control using Servlet Filters
623
Manual control
package com.orientechnologies.test;
import javax.servlet.*;
try {
// USER CODE
} finally {
database.close();
}
}
}
624
Automatic control using Servlet Filters
Servlets are the best way to automatise database control inside WebApps. The trick is to
create a Filter that get a database from the pool and binds it in current ThreadLocal
before to execute the Servlet code. Once returned the ThreadLocal is cleared and
database released to the pool.
JaveEE Servlets
625
Create a Filter class
In this example a new database instance is created per request, opened and at the end
closed.
package com.orientechnologies.test;
import javax.servlet.*;
package com.orientechnologies.test;
import javax.servlet.*;
626
Register the filter
Now we've create the filter class it needs to be registered in the web.xml file:
627
Manage a remote Server instance
Introduction
A remote server can be managed via API using the OServerAdmin class. Create it using
the URL of the remote server as first parameter of the constructor.
628
Connect to a remote server
User and password are not the database accounts but the server users configured in
orientdb-server-config.xml file.
When finished call the OServerAdmin.close() method to release the network connection.
629
Create a database
To create a new database in a remote server you can use the console's create database
command or via API using the OServerAdmin.createDatabase() method.
// VERSION >= 1.4: CREATE A SERVER ADMIN CLIENT AGAINST A REMOTE SERVER
OServerAdmin serverAdmin = new OServerAdmin("remote:localhost").connect("admin", "admin");
serverAdmin.createDatabase("GratefulDeadConcerts", "graph", "local");
630
Drop a database
To drop a database from a server you can use the console's drop database command or
via API using the OServerAdmin.dropDatabase() method.
631
Check if a database exists
To check if a database exists in a server via API use the OServerAdmin.existsDatabase()
method.
632
JDBC Driver
OrientDB is a NoSQL DBMS that support a subset of SQL ad query language.
633
Include in your projects
<dependency>
<groupId>com.orientechnologies</groupId>
<artifactId>orientdb-jdbc</artifactId>
<version>1.7</version>
</dependency>
NOTE: to use SNAPSHOT version remember to add the Snapshot repository to your
pom.xml .
634
How can be used in my code?
The driver is registered to the Java SQL DriverManager and can be used to work with all
the OrientDB database types:
memory,
plocal and
remote
635
First get a connection
rs.next();
rs.getInt("@version");
rs.getString("@class");
rs.getString("@rid");
rs.getString("stringKey");
rs.getInt("intKey");
rs.close();
stmt.close();
The driver retrieves OrientDB metadata (@rid,@class and @version) only on direct
queries. Take a look at tests code to see more detailed examples.
636
Advanced features
Connection pool
By default a new database instance is created every time you ask for a JDBC
connection. OrientDB JDBC driver provides a Connection Pool out of the box. Set the
connection pool parameters before to ask for a connection:
637
JPA
There are two ways to configure OrientDB JPA
638
Configuration
The first - do it through /META-INF/persistence.xml Folowing OrientDB properties are
supported as for now:
Example:
<properties>
<property name="javax.persistence.jdbc.url" value="remote:localhost/test.odb" />
<property name="javax.persistence.jdbc.user" value="admin" />
<property name="javax.persistence.jdbc.password" value="admin" />
<!-- Register whole package.
See com.orientechnologies.orient.core.entity.OEntityManager.registerEntityCl
<property name="com.orientdb.entityClasses" value="com.example.domains" />
</properties>
</persistence-unit>
</persistence>
639
Programmatic
The second one is programmatic:
Guice example
com.google.inject.persist.jpa.JpaPersistModule.properties(Properties)
/**
* triggered as soon as a web application is deployed, and before any requests
* begin to arrive
*/
@WebListener
public class GuiceServletConfig extends GuiceServletContextListener {
@Override
protected Injector getInjector() {
return Guice.createInjector(
new JpaPersistModule("appJpaUnit").properties(orientDBProp),
new ConfigFactoryModule(),
servletModule);
}
Native example
640
DB properties, that were passed programmatically, will overwrite parsed from XML ones
641
Note
Config parser checks persistence.xml with validation schemes (XSD), so configuration
file must be valid.
642
Gremlin API
Gremlin is a language specialized to work with Property Graphs. Gremlin is part of
TinkerPop Open Source products. For more information:
Gremlin Documentation
Gremlin WiKi
OrientDB adapter to use it inside Gremlin
OrientDB implementation of TinkerPop Blueprints
To know more about Gremlin and TinkerPop's products subscribe to the Gremlin Group.
643
Get Started
Launch the gremlin.sh (or gremlin.bat on Windows OS) console script located in bin
directory:
> gremlin.bat
\,,,/
(o o)
-----oOOo-(_)-oOOo-----
644
Open the graph database
Before to play with Gremlin you need a valid OrientGraph instance that points to a
OrientDB database. To know all the database types look at Storage types.
When you're working with a local or memory database if the database not exists it's
created automatically. Using the remote connection you need to create the database on
the target server before to use it. This is due to security restrictions.
Once created the OrientGraph instance with a proper URL is necessary to assign it to a
variable. Gremlin is written in Groovy, so it supports all the Groovy syntax and both can
be mixed to create very powerful scripts!
Example with a local database (see below for more information about it):
645
Working with local database
This is the most used mode. The console opens and locks the database for exclusive
use. Doesn't require to start a OrientDB Server.
646
Working with remote database
Open a database on a remote server. Assure the server is up and running. To start the
server just launch server.sh (or server.bat on Windows OS) script. For more information
look at OrientDB Server
647
Working with in-memory database
In this mode the database is volatile and all the changes will be not persistent. Use this
in cluster configuration (the database life is assured by the cluster itself) or just for test.
648
Use the security
OrientDB supports the security by creating multiple users and roles to associate
privileges. To know more look at Security. To open the graph database with a different
user than default pass user and password as additional parameters:
649
Create a new Vertex
To create a new vertex use the addVertex() method. The vertex will be created and the
unique id will be displayed as return value.
g.addVertex();
==>v[#5:0]
650
Create an edge =
To create a new edge between two vertices use the addEdge(v1, v2, label) method.
The edge will be created with the label specified.
In the example below 2 vertices are created and assigned to a variable (Gremlin is
based on Groovy), then an edge is created between them.
gremlin> v1 = g.addVertex();
==>v[#5:0]
gremlin> v2 = g.addVertex();
==>v[#5:1]
651
Save changes
OrientDB assigns a temporary identifier to each vertex and edge that is created. For
saving them to the database stopTransaction(SUCCESS) should be called
gremlin> g.stopTransaction(SUCCESS)
652
Retrieve a vertex
To retrieve a vertex by its ID, use the v(id) method passing the RecordId as argument
(with or without the prefix '#'). This example retrieves the first vertex created in the upon
example.
gremlin> g.v('5:0')
==>v[#5:0]
653
Get all the vertices
To retrieve all the vertices in the opened graph use .V (V in upper-case):
gremlin> g.V
==>v[#5:0]
==>v[#5:1]
654
Retrieve an edge
Retrieving an edge it's very similar to [use the e(id) method passing the
Concepts#RecordId RecordId as argument (with or without the prefix '#'). This example
retrieves the first edge created in the upon example.
gremlin> g.e('6:0')
==>e[#6:0][#5:0-friend->#5:1]
655
Get all the edges
To retrieve all the edges in the opened graph use .E (E in upper-case):
gremlin> g.E
==>e[#6:0][#5:0-friend->#5:1]
656
Traversal
The power of Gremlin is on traversal. Once you have a graph loaded in your database
you can traverse it in many ways.
657
Basic Traversal
To display all the outgoing edges of the first vertex just created postpone the .outE at
the vertex. Example:
gremlin> v1.outE
==>e[#6:0][#5:0-friend->#5:1]
And to display all the incoming edges of the second vertex created in the previous
examples postpone the .inE at the vertex. Example:
gremlin> v2.inE
==>e[#6:0][#5:0-friend->#5:1]
In this case the edge is the same because it's the outgoing of 5:0 and the goes up to 5:1
where is the incoming edge.
658
Filter results
This examples returns all the outgoing edges of all the vertices with label equals to
'friend'.
gremlin> g.V.outE('friend')
==>e[#6:0][#5:0-friend->#5:1]
659
Close the database =
To close a graph use the shutdown() method:
gremlin> g.shutdown()
==>null
This is not strictly necessary because OrientDB always closes the database when the
Gremlin console quits.
660
Create complex paths
Gremlin allows to concatenate expressions to create more complex traversal in a single
line:
v1.outE.inV
Of course this could be much more complex. Below an examples with the graph taken
from the official documentation:
g = new OrientGraph('memory:test')
661
Passing input parameters
Some Gremlin expressions require declaration of input parameters to be run. This is the
case, for example, of bound variables, as described in JSR223 Gremlin Script Engine.
OrientDB has enabled a mechanism to pass variables to a Gremlin pipeline declared in
a command as described below:
662
GremlinPipeline
You can also use native Java GremlinPipeline like:
663
Declaring output
In the simplest case, the output of the last step
(https://github.com/tinkerpop/gremlin/wiki/Gremlin-Steps) in the Gremlin pipeline
corresponds to the output of the overall Gremlin expression. However, it is possible to
instruct the Gremlin engine to consider any of the input variables as output. This can be
declared as:
There are more possibilities to define the output in Gremlin pipelines so this mechanism
is expected to be extended in the future. Please, contact OrientDB mailing list to discuss
customized outputs.
664
Conclusions
Now you learned how to use Gremlin on top of OrientDB the best place to go in deep
with this powerful language is the Gremlin WiKi.
665
Javascript
Starting from version 1.0, OrientDB supports server side scripting. All the JVM
languages are supported. By default JavaScript is installed.
Scripts can be executed client and server side. For the client side the user must have
the privilege of READ against database.command resource. For the server side the server
must enable the scripting interpreter that are disabled by default for security reason.
666
See also
SQL-batch
667
Usage
Execute a command like SQL but using the class OCommandScript passing the language
to use. JavaScript is installed by default. Example:
668
Via console
JavaScript code can be executed at client-side, the console, or server-side:
Since the semicolon ; character is used in both console and JavaScript language to
separate statements, how can we execute multiple commands in the console and
JavaScript?
OrientDB console uses a reserved keyword end to switch from the JavaScript mode to
the console mode.
Example:
orientdb> connect remote:localhost/demo admin admin; js for( i = 0; i < 10; i++ ){ db.query('select from
This line connects to the remote server and executes 10 queries on the console. The
end command switches the mode back to the OrientDB console and then executes the
console exit command.
Below an example to display the result of a query server and client side.
Interactive mode
$ ./console.sh
OrientDB console v.1.5 www.orientechnologies.com
Type 'help' to display all the commands supported.
669
---+---------+--------------------+--------------------+--------------------+--------------------
#| RID |name |password |status |roles
---+---------+--------------------+--------------------+--------------------+--------------------
0| #4:0|admin |{SHA-256}8C6976E5B5410415BDE908BD4DEE15DFB167A9C873FC4BB8A81F6F2AB448A
1| #4:1|reader |{SHA-256}3D0941964AA3EBDCB00CCEF58B1BB399F9F898465E9886D5AEC7F31090A0F
2| #4:2|writer |{SHA-256}B93006774CBDD4B299389A03AC3D88C3A76B460D538795BC12718011A909F
---+---------+--------------------+--------------------+--------------------+--------------------
Script executed in 0,073000 sec(s). Returned 3 records
orientdb> exit
Batch mode
---+---------+--------------------+--------------------+--------------------+--------------------
#| RID |name |password |status |roles
---+---------+--------------------+--------------------+--------------------+--------------------
0| #4:0|admin |{SHA-256}8C6976E5B5410415BDE908BD4DEE15DFB167A9C873FC4BB8A81F6F2AB448A
1| #4:1|reader |{SHA-256}3D0941964AA3EBDCB00CCEF58B1BB399F9F898465E9886D5AEC7F31090A0F
2| #4:2|writer |{SHA-256}B93006774CBDD4B299389A03AC3D88C3A76B460D538795BC12718011A909F
---+---------+--------------------+--------------------+--------------------+--------------------
Script executed in 0,099000 sec(s). Returned 3 records
670
Examples of usage
orientdb> js for( i = 0; i < 1000; i++ ){ db.query( 'insert into jstest (label) values ("test
Client side script executed in 0,426000 sec(s). Value returned is: Profile#11:52{name:Luca} v3
671
Enable Server side scripting
For security reason server-side scripting is disabled by default on server. To enable it
change the enable field to true in orientdb-server-config.xml file:
<!-- SERVER SIDE SCRIPT INTERPRETER. WARNING! THIS CAN BE A SECURITY HOLE: ENABLE IT ONLY IF CLIENTS ARE
<handler class="com.orientechnologies.orient.server.handler.OServerSideScriptInterpreter">
<parameters>
<parameter name="enabled" value="true" />
</parameters>
</handler>
NOTE: this will allow to clients to execute any code inside the server. Enable it only if
clients are trusted.
672
Javascript API
This driver wraps the most common use cases in database usage. All parameters
required by methods or constructor are Strings. This library works on top of HTTP
RESTful protocol.
Note: Due to cross-domain XMLHttpRequest restriction this API works, for now, only
placed in the server deployment. To use it with cross-site look at Cross-site scripting .
673
See also
Javascript-Command
674
Example
675
API
ODatabase object
Example:
Once created database instance is ready to be used. Every method return the operation
result when it succeeded, null elsewhere.
In case of null result the database instance will have the error message obtainable by
the getErrorMessage() method.
Open
Method that connects to the server, it returns database information in JSON format.
Browser Authentication
Syntax: <databaseInstance>.open()
Note: This implementation asks to the browser to provide user and password.
Example:
Javascript Authentication
Syntax: <databaseInstance>.open(username,userpassword)
Example:
676
databaseInfo = orientServer.open('admin','admin');
Return Example:
{"classes": [
{
"id": 0,
"name": "ORole",
"clusters": [3],
"defaultCluster": 3, "records": 3,
"properties": [
{
"id": 0,
"name": "mode",
"type": "BYTE",
"mandatory": false,
"notNull": false,
"min": null,
"max": null,
"indexed": false
},
{
"id": 1,
"name": "rules",
"linkedType": "BYTE",
"type": "EMBEDDEDMAP",
"mandatory": false,
"notNull": false,
"min": null,
"max": null,
"indexed": false
}
]},
],
"dataSegments": [
{"id": -1, "name": "default", "size": 10485760, "filled": 1380391, "maxSize": "0", "files
],
"clusters": [
{"id": 0, "name": "internal", "type": "PHYSICAL", "records": 4, "size": 1048576, "filled":
],
"txSegment": [
{"totalLogs": 0, "size": 1000000, "filled": 0, "maxSize": "50mb", "file": "${STORAGE_PATH}/txlog.otx"
], "users": [
{"name": "admin", "roles": "[admin]"},
{"name": "reader", "roles": "[reader]"},
{"name": "writer", "roles": "[writer]"}
],
"roles": [
{"name": "admin", "mode": "ALLOW_ALL_BUT",
"rules": []
},
{"name": "reader", "mode": "DENY_ALL_BUT",
677
"rules": [{
"name": "database", "create": false, "read": true, "update": false, "delete": false
}, {
"name": "database.cluster.internal", "create": false, "read": true, "update": false, "
}, {
"name": "database.cluster.orole", "create": false, "read": true, "update": false, "delete
}, {
"name": "database.cluster.ouser", "create": false, "read": true, "update": false, "delete
}, {
"name": "database.class.*", "create": false, "read": true, "update": false, "delete":
}, {
"name": "database.cluster.*", "create": false, "read": true, "update": false, "delete
}, {
"name": "database.query", "create": false, "read": true, "update": false, "delete": false
}, {
"name": "database.command", "create": false, "read": true, "update": false, "delete":
}, {
"name": "database.hook.record", "create": false, "read": true, "update": false, "delete
}]
},
],
"config":{
"values": [
{"name": "dateFormat", "value": "yyyy-MM-dd"},
{"name": "dateTimeFormat", "value": "yyyy-MM-dd hh:mm:ss"},
{"name": "localeCountry", "value": ""},
{"name": "localeLanguage", "value": "en"},
{"name": "definitionVersion", "value": 0}
],
"properties": [
]
}
}
Query
Method that executes the query, it returns query results in JSON format.
Simple Example:
Return Example:
678
{ "result": [{
"@rid": "12:0", "@class": "Address",
"street": "Piazza Navona, 1",
"type": "Residence",
"city": "#13:0"
}, {
"@rid": "12:1", "@class": "Address",
"street": "Piazza di Spagna, 111",
"type": "Residence",
"city": "#13:0"
}
]
}
Return Example 1:
{ "result": [{
"@rid": "12:0", "@class": "Address",
"street": "Piazza Navona, 1",
"city":{
"@rid": "13:0", "@class": "City",
"name": "Rome",
"country":{
"@rid": "14:0", "@class": "Country",
"name": "Italy"
}
}
}, {
"@rid": "12:1", "@version": 1, "@class": "Address",
"street": "Piazza di Spagna, 111",
"city":{
"@rid": "13:0", "@class": "City",
"name": "Rome",
"country":{
"@rid": "14:0", "@class": "Country",
"name": "Italy"
}
}
}
]
}
679
queryResult = orientServer.query('select from Address where city.country.name = \'Italy\'',null
Return Example 2:
{ "result": [{
"@rid": "12:0", "@class": "Address",
"street": "Piazza Navona, 1",
"type": "Residence"
}, {
"@rid": "12:1", "@version": 1, "@class": "Address",
"street": "Piazza di Spagna, 111",
"type": "Residence"
}
]
}
Return Example 3:
{ "result": [{
"@rid": "12:0", "@class": "Address",
"street": "Piazza Navona, 1",
"type": "Residence",
"city":{
"@rid": "13:0", "@class": "City",
"name": "Rome"
}
}
]
}
Execute Command
Method that executes arbitrary commands, it returns command result in text format.
Syntax: <databaseInstance>.executeCommand(<commandText>)
680
Example 1 (insert):
Example 2 (delete):
commandResult = orientServer.executeCommand('delete from Address where street = \'Via test 1\' and type =
{ "value" : 5 }
Load
Method that loads a record from the record ID, it returns the record informations in JSON
format.
Simple Example:
queryResult = orientServer.load('12:0');
Return Example:
681
"@rid": "12:0", "@class": "Address",
"street": "Piazza Navona, 1",
"type": "Residence",
"city": "#13:0"
}
Return Example 1:
{
"@rid": "12:0", "@class": "Address",
"street": "Piazza Navona, 1",
"city":{
"@rid": "13:0",
"name": "Rome",
"country":{
"@rid": "14:0",
"name": "Italy"
}
}
}
Class Info
Method that retrieves information of a class, it returns the class informations in JSON
format.
Syntax: <databaseInstance>.classInfo(<className>)
Example:
addressInfo = orientServer.classInfo('Address');
Return Example:
{ "result": [{
"@rid": "14:0", "@class": "Address",
"street": "WA 98073-9717",
"type": "Headquarter",
682
"city": "#12:1"
}, {
"@rid": "14:1", "@class": "Address",
"street": "WA 98073-9717",
"type": "Headquarter",
"city": "#12:1"
}
]
}
Browse Cluster
Method that retrieves information of a cluster, it returns the class informations in JSON
format.
Syntax: <databaseInstance>.browseCluster(<className>)
Example:
addressInfo = orientServer.browseCluster('Address');
Return Example:
{ "result": [{
"@rid": "14:0", "@class": "Address",
"street": "WA 98073-9717",
"type": "Headquarter",
"city": "#12:1"
}, {
"@rid": "14:1", "@class": "Address",
"street": "WA 98073-9717",
"type": "Headquarter",
"city": "#12:1"
}
]
}
Server Information
Method that retrieves server informations, it returns the server informations in JSON
format.
Note: Server information needs root username and password.
Syntax: <databaseInstance>.serverInfo()
683
Example:
serverInfo = orientServer.serverInfo();
Return Example:
{
"connections": [{
"id": "64",
"id": "64",
"remoteAddress": "127.0.0.1:51459",
"db": "-",
"user": "-",
"protocol": "HTTP-DB",
"totalRequests": "1",
"commandInfo": "Server status",
"commandDetail": "-",
"lastCommandOn": "2010-12-23 12:53:38",
"lastCommandInfo": "-",
"lastCommandDetail": "-",
"lastExecutionTime": "0",
"totalWorkingTime": "0",
"connectedOn": "2010-12-23 12:53:38"
}],
"dbs": [{
"db": "demo",
"user": "admin",
"open": "open",
"storage": "OStorageLocal"
}],
"storages": [{
"name": "temp",
"type": "OStorageMemory",
"path": "",
"activeUsers": "0"
}, {
"name": "demo",
"type": "OStorageLocal",
"path": "/home/molino/Projects/Orient/releases/0.9.25-SNAPSHOT/db/databases/demo",
"activeUsers": "1"
}],
"properties": [
{"name": "server.cache.staticResources", "value": "false"
},
{"name": "log.console.level", "value": "info"
},
{"name": "log.file.level", "value": "fine"
}
]
}
684
Schema
Method that retrieves database Schema, it returns an array of classes (JSON parsed
Object).
Syntax: <databaseInstance>.schema()
Example:
schemaInfo = orientServer.schema();
Return Example:
{"classes": [
{
"id": 0,
"name": "ORole",
"clusters": [3],
"defaultCluster": 3, "records": 3,
"properties": [
{
"id": 0,
"name": "mode",
"type": "BYTE",
"mandatory": false,
"notNull": false,
"min": null,
"max": null,
"indexed": false
},
{
"id": 1,
"name": "rules",
"linkedType": "BYTE",
"type": "EMBEDDEDMAP",
"mandatory": false,
"notNull": false,
"min": null,
"max": null,
"indexed": false
}
]},
]
}
getClass()
685
Return a schema class from the schema.
Syntax: <databaseInstance>.getClass(<className>)
Example:
Return Example:
{
"id": 0,
"name": "Customer",
"clusters": [3],
"defaultCluster": 3, "records": 3,
"properties": [
{
"id": 0,
"name": "name",
"type": "STRING",
},
{
"id": 1,
"name": "surname",
"type": "STRING",
}
]
}
Security
Roles
Method that retrieves database Security Roles, it returns an array of Roles (JSON
parsed Object).
Syntax: <databaseInstance>.securityRoles()
Example:
roles = orientServer.securityRoles();
Return Example:
686
{ "roles": [
{"name": "admin", "mode": "ALLOW_ALL_BUT",
"rules": []
},
{"name": "reader", "mode": "DENY_ALL_BUT",
"rules": [{
"name": "database", "create": false, "read": true, "update": false, "delete": false
}, {
"name": "database.cluster.internal", "create": false, "read": true, "update": false, "
}, {
"name": "database.cluster.orole", "create": false, "read": true, "update": false, "delete
}, {
"name": "database.cluster.ouser", "create": false, "read": true, "update": false, "delete
}, {
"name": "database.class.*", "create": false, "read": true, "update": false, "delete":
}, {
"name": "database.cluster.*", "create": false, "read": true, "update": false, "delete
}, {
"name": "database.query", "create": false, "read": true, "update": false, "delete": false
}, {
"name": "database.command", "create": false, "read": true, "update": false, "delete":
}, {
"name": "database.hook.record", "create": false, "read": true, "update": false, "delete
}]
}
]
}
Users
Method that retrieves database Security Users, it returns an array of Users (JSON
parsed Object).
Syntax: <databaseInstance>.securityUsers()
Example:
users = orientServer.securityUsers();
Return Example:
{ "users": [
{"name": "admin", "roles": "[admin]"},
{"name": "reader", "roles": "[reader]"},
{"name": "writer", "roles": "[writer]"}
]
}
687
close()
Syntax: <databaseInstance>.close()
Example:
orientServer.close();
Syntax: <databaseInstance>.setDatabaseUrl(<newDatabaseUrl>)
Example:
orientServer.setDatabaseUrl('http://localhost:3040')
Syntax: <databaseInstance>.setDatabaseName(<newDatabaseName>)
Example:
orientServer.setDatabaseName('demo2');
This API allows you to chose the return type, Javascript Object or JSON plain text.
Default return is Javascript Object.
688
Important: the javascript object is not always the evaluation of JSON plain text: for each
document (identified by its Record ID) the JSON file contains only one expanded object,
all other references are just its Record ID as String, so the API will reconstruct the real
structure by re-linking all references to the matching javascript object.
Syntax: orientServer.setEvalResponse(<boolean>)
Examples:
orientServer.setEvalResponse(true);
orientServer.setEvalResponse(false);
Cross-site scripting
To invoke OrientDB cross-site you can use the Query command in GET and the JSONP
protocol. Example:
This will put the result of the query select from XXXX</code> into the <code>datajson
variable.
Errors
In case of errors the error message will be stored inside the database instance,
retrievable by getErrorMessage() method.
Syntax: <databaseInstance>.getErrorMessage()
Example:
689
if (orientServer.getErrorMessage() != null){
//write error message
}
690
Scala API
OrientDB is a NoSQL database writen in Java, we can use it in scala easily. Look also at
Scala utilities and tests project for Scala high level classes built on top of OrientDB.
691
Java method invocation problems
Usually the main problems are related to calling conventions between Scala and Java.
692
Parameters
Be careful to pass parameters to methods with varargs like db.query(...) . You need to
convert it to java's repeated args correctly.
693
Collections
You can only use java collections when define pojos. If you use scala collections, they
can be persisted, but can't be queried.
import scala.collection.JavaConverters._
import scala.collection.JavaConversions._
You don't need to convert Java and Scala collections manually (even don't need to
invoke .asJava or .asScala ) You can treat these java collections as scala's.
694
models.scala
package models
class User {
@Id var id: String = _
var name: String = _
var addresses: java.util.List[Address] = new java.util.ArrayList()
@Version var version: String = _
override def toString = "User: " + this.id + ", name: " + this.name + ", addresses: " + this
}
class Address {
var city: String = _
var street: String = _
class Question {
@Id var id: String = _
var title: String = _
var user: User = _
@Version var version: String = _
override def toString = "Question: " + this.id + ", title: " + this.title + ", belongs: "
}
695
test.scala
package models
import com.orientechnologies.orient.core.id.ORecordId
import com.orientechnologies.orient.core.sql.query.OSQLSynchQuery
import scala.collection.JavaConverters._
import scala.collection.JavaConversions._
import com.orientechnologies.orient.core.db.`object`.{ODatabaseObject, ODatabaseObjectPool, OObjectDataba
object Test {
implicit def dbWrapper(db: OObjectDatabaseTx) = new {
def queryBySql[T](sql:-String,-params:-AnyRef*.md): List[T] = {
val params4java = params.toArray
val results: java.util.List[T] = db.query(new OSQLSynchQuery[T](sql.md), params4java: _*)
results.asScala.toList
}
}
user.addresses += address1
user.addresses += address2
db.save(user)
696
db.save(q2)
// query by id
val userById = db.queryBySql[User]("select-from-User-where-@rid-=-?",-new-ORecordId(user.id))
println("User by id: " + userById)
// query by field
val userByField = db.queryBySql[User]("select-from-User-where-name-=-?",-user.name)
println("User by field: " + userByField)
// query by city
val userByCity = db.queryBySql[User]("select-from-User-where-addresses-contains-(-city-=-?-.md)"
println("User by city: " + userByCity)
db.drop()
db.close()
}
}
697
HTTP Protocol
OrientDB RESTful HTTP protocol allows to talk with a OrientDB Server instance using
the HTTP protocol and JSON. OrientDB supports also a highly optimized Binary protocol
for superior performances.
698
Available Commands
document
Operations on documentbyclass export function
documents by RID Operations on Exports a Executes a
GET - HEAD - documents by database server-side
POST - PUT - Class function
DELETE
server
Information about
the server
699
HTTP Methods
This protocol uses the four methods of the HTTP protocol:
GET, to retrieve values from the database. It's idempotent that means no changes
to the database happen. Remember that in IE6 the URL can be maximum of 2,083
characters. Other browsers supports major length, but if you want to stay
compatible with all limit to 2,083 characters
POST, to insert values into the database
PUT, to change values into the database
DELETE, to delete values from the database
When using POST and PUT the following are important when preparing the contents of
the post message:
700
Headers
All the requests must have these 2 headers:
'Accept-Encoding': 'gzip,deflate'
'Content-Length': <content-length>
`
701
Syntax
The REST API is very flexible, with the following features:
The REST syntax used is the same for all the four HTTP methods:
Syntax: http://<server>:<port>/<command>/[<database>/<arguments>]
Results are always in JSON format. Support for 'document' object types is through the
use of the attribute @type : 'd' . This also applies when using inner document objects.
Example:
{
"@type" : "d"
"Name" : "Test",
"Data" : { "@type": "d",
"value": 0 },
"@class" : "SimpleEntity"
}
JSONP is also supported by adding a callback parameter to the request (containing the
callback function name).
Syntax: http://<server>:<port>/<command>/[<database>/<arguments>]?callback=
<callbackFunctionName>
Server commands, such as to know server statistics and to create a new database
Database commands, all the commands against a database
702
Authentication and security
All the commands (but the Disconnect need a valid authentication before to get
executed. The OrientDB Server checks if the Authorization HTTP header is present,
otherwise answers with a request of authentication (HTTP error code: 401).
The HTTP client (or the Internet Browser) must send user and password using the HTTP
Base authentication. Password is encoded using Base64 algorithm. Please note that if
you want to encrypt the password using a safe mode take in consideration to use SSL
connections.
Server commands use the realm "OrientDB Server", while the database commands use
a realm per database in this form: "OrientDB db-<database>" , where <database> is the
database name. In this way the Browser/HTTP client can reuse user and password
inserted multiple times until the session expires or the "Disconnect" is called.
On first call (or when the session is expired and a new authentication is required),
OrientDB returns the OSESSIONID parameter in response's HTTP header. On further
calls the client should pass this OSESSIONID header in the requests and OrientDB will
skip the authentication because a session is alive. By default sessions expire after 300
seconds (5 minutes), but you can change this configuration by setting the global setting:
network.http.sessionExpireTimeout
703
JSON data type handling and Schema-less
mode
Since OrientDB supports also schema-less/hybrid modes how to manage types? JSON
doesn't support all the types OrientDB has, so how can I pass the right type when it's not
defined in the schema?
The answer is using the special field "@fieldTypes" as string containing all the field
types separated by comma. Example:
704
HTTP commands
Connect
GET - Connect
Syntax: http://<server>:[<port>]/connect/<database>
Example
705
Database
GET - Database
{
"server": {
"version": "1.1.0-SNAPSHOT",
"osName": "Windows 7",
"osVersion": "6.1",
"osArch": "amd64",
"javaVendor": "Oracle Corporation",
"javaVersion": "23.0-b21"
}, "classes": [
{
"id": 0,
"name": "ORole",
"clusters": [3],
"defaultCluster": 3, "records": 0},
...
706
Class
GET - Class
Syntax: http://<server>:[<port>]/class/<database>/<class-name>
HTTP response:
{ "class": {
"name": "<class-name>"
"properties": [
{ "name": <property-name>,
"type": <property-type>,
"mandatory": <mandatory>,
"notNull": <not-null>,
"min": <min>,
"max": <max>
}
]
}
}
For more information about properties look at the supported types, or see the SQL
Create property page for text values to be used when getting or posting class commands
Example
{
"name": "OFunction",
"superClass": "",
"alias": null,
"abstract": false,
"strictmode": false,
"clusters": [
7
],
"defaultCluster": 7,
"records": 0,
"properties": [
{
"name": "language",
"type": "STRING",
"mandatory": false,
707
"readonly": false,
"notNull": false,
"min": null,
"max": null,
"collate": "default"
},
{
"name": "name",
"type": "STRING",
"mandatory": false,
"readonly": false,
"notNull": false,
"min": null,
"max": null,
"collate": "default"
},
{
"name": "idempotent",
"type": "BOOLEAN",
"mandatory": false,
"readonly": false,
"notNull": false,
"min": null,
"max": null,
"collate": "default"
},
{
"name": "code",
"type": "STRING",
"mandatory": false,
"readonly": false,
"notNull": false,
"min": null,
"max": null,
"collate": "default"
},
{
"name": "parameters",
"linkedType": "STRING",
"type": "EMBEDDEDLIST",
"mandatory": false,
"readonly": false,
"notNull": false,
"min": null,
"max": null,
"collate": "default"
}
]
}
POST - Class
Create a new class where the schema of the vertexes or edges is known. OrientDB
allows (encourages) classes to be derived from other class definitions this is achieved
by using the COMMAND call with an OrientDB SQL command. Returns the id of the new
708
class created.
Syntax: http://<server>:[<port>]/class/<database>/<class-name>
709
Property
POST - Property
Create one or more properties into a given class. Returns the number of properties of
the class.
Syntax: http://<server>:[<port>]/property/<database>/<class-name>/<property-name>/[<property-
type>]
Syntax: http://<server>:[<port>]/property/<database>/<class-name>/
{
"fieldName": {
"propertyType": "<property-type>"
},
"fieldName": {
"propertyType": "LINK",
"linkedClass": "<linked-class>"
},
"fieldName": {
"propertyType": "<LINKMAP|LINKLIST|LINKSET>",
"linkedClass": "<linked-class>"
},
"fieldName": {
"propertyType": "<LINKMAP|LINKLIST|LINKSET>",
"linkedType": "<linked-type>"
}
}
Example
Single property:
710
http://localhost:2480/class/demo/simpleField HTTP response: 1
{
"name": {
"propertyType": "STRING"
},
"father": {
"propertyType": "LINK",
"linkedClass": "Person"
},
"addresses": {
"propertyType": "LINKMAP",
"linkedClass": "Address"
},
"examsRatings": {
"propertyType": "LINKMAP",
"linkedType": "INTEGER"
}
"events": {
"propertyType": "LINKLIST",
"linkedType": "DATE"
}
"family": {
"propertyType": "LINKLIST",
"linkedClass": "Person"
}
...
HTTP response: 6
711
Cluster
GET - Cluster
Where the primary usage is a document db, or where the developer wants to optimise
retrieval using the clustering of the database, use the CLUSTER command to browse
the records of the requested cluster.
Syntax: http://<server>:[<port>]/cluster/<database>/<cluster-name>/
Where <limit> is optional and tells the maximum of records to load. Default is 20.
Example
HTTP response:
{ "schema": {
"id": 5,
"name": "Address"
},
"result": [{
"_id": "11:0",
"_ver": 0,
"@class": "Address",
"type": "Residence",
"street": "Piazza Navona, 1",
"city": "12:0"
}
...
712
Command
POST - Command
Execute a command against the database. Returns the records affected or the list of
records for queries. Command executed via POST can be non-idempotent (look at
Query).
Syntax: http://<server>:[<port>]/command/<database>/<language>[/<command-text>
[/limit[/<fetchPlan>]]] content: <command-text>
Where:
The command-text can appear in either the URL or the content of the POST
transmission.
Where the command-text is included in the URL, it must be encoded as per normal URL
encoding.
Read the SQL section or the Gremlin introduction for the type of commands.
Example
HTTP response: 10
Or the same:
HTTP response: 10
713
Batch
POST - Batch
Executes a batch of operations in a single call. This is useful to reduce network latency
issuing multiple commands as multiple requests. Batch command supports transactions
as well.
Syntax: http://<server>:[<port>]/batch/<database>
Example
{ "transaction" : true,
"operations" : [
{ "type" : "u",
"record" : {
"@rid" : "#14:122",
"name" : "Luca",
"vehicle" : "Car"
}
}, {
"type" : "d",
"record" : {
"@rid" : "#14:100"
}
}, {
714
"type" : "c",
"record" : {
"@class" : "City",
"name" : "Venice"
}
}, {
"type" : "cmd",
"language" : "sql",
"command" : "create edge Friend from #10:33 to #11:33"
}, {
"type" : "script",
"language" : "javascript",
"script" : "orient.getGraph().createVertex('class:Account')"
}
]
}
SQL batch
{ "transaction" : true,
"operations" : [
{
"type" : "script",
"language" : "sql",
"script" : [ "let account = create vertex Account set name = 'Luke'",
"let city =select from City where name = 'London'",
"create edge Lives from $account to $city retry 100" ]
}
]
}
715
Function
Executes a server-side function against the database. Returns the result of the function
that can be a string or a JSON containing the document(s) returned.
The difference between GET and POST method calls are if the function has been
declared as idempotent. In this case can be called also by GET, otherwise only POST is
accepted.
Syntax: http://<server>:[<port>]/function/<database>/<name>[/<argument>*]<server>
Where
Creation of functions, when not using the Java API, can be done through the Studio in
either Orient DB SQL or Java see the OrientDB Functions page.
Example
716
Database
GET - Database
Syntax: http://<server>:[<port>]/database/<database>
Example
HTTP response:
{"classes": [
{
"id": 0,
"name": "ORole",
"clusters": [3],
"defaultCluster": 3, "records": 0},
{
"id": 1,
"name": "OUser",
"clusters": [4],
"defaultCluster": 4, "records": 0},
{
...
POST - Database
storage can be
'plocal' for disk-based database
'memory' for in memory only database.
type, is optional, and can be document or graph. By default is a document.
Example
717
{ "classes": [
{
"id": 0,
"name": "ORole",
"clusters": [3],
"defaultCluster": 3, "records": 0},
{
"id": 1,
"name": "OUser",
"clusters": [4],
"defaultCluster": 4, "records": 0},
{
...
DELETE - Database
Syntax: http://<server>:[<port>]/database/<databaseName>
Where:
Example
718
Export
GET - Export
Syntax: http://:[]/export/
719
Import
POST - Import
Syntax: http://<server>:[<port>]/import/<database>
Important: Connect required: the connection with the selected database must be
already established
Example
{
"responseText": "Database imported correctly"
}
_Fail::
{
"responseText": "Error message"
}
720
List Databases
Syntax: http://<server>:<port>/listDatabases
To let to the Studio to display the database list by default the permission to list the
database is assigned to guest. Remove this permission if you don't want anonymous
user can display it.
Example
{
"@type": "d", "@version": 0,
"databases": ["demo", "temp"]
}
721
Disconnect
GET - Disconnect
Syntax: http://<server>:[<port>]/disconnect
Example
722
Document
GET - Document
This is a key way to retrieve data from the database, especially when combined with a
<fetchplan> . Where a single result is required then the RID can be used to retrieve that
single document.
Syntax: http://<server>:[<port>]/document/<database>/<record-id>[/<fetchPlan>]
Where:
Example
HTTP Code 200, with the document in JSON format in the payload, such as:
{
"_id": "9:0",
"_ver": 2,
"@class": "Profile",
"nick": "GGaribaldi",
"followings": [],
"followers": [],
"name": "Giuseppe",
"surname": "Garibaldi",
"location": "11:0",
"invitedBy": null,
"sex": "male",
"online": true
}
The example above can be extended to return all the edges and vertices beneath #9:0
723
HTTP GET request: http://localhost:2480/document/demo/9:0/*:-1
HEAD - Document
Syntax: http://<server>:[<port>]/document/<database>/<record-id>
Where:
Example
POST - Document
Create a new document. Returns the document with the new @rid assigned. Before
1.4.x the return was the @rid content only.
Syntax: http://<server>:[<port>]/document/<database>
Example
content:
{
"@class": "Profile",
"nick": "GGaribaldi",
"followings": [],
"followers": [],
"name": "Giuseppe",
"surname": "Garibaldi",
"location": "11:0",
"invitedBy": null,
"sex": "male",
"online": true
}
724
HTTP response, as the document created with the assigned RecordID as @rid:
{
"@rid": "#11:4456",
"@class": "Profile",
"nick": "GGaribaldi",
"followings": [],
"followers": [],
"name": "Giuseppe",
"surname": "Garibaldi",
"location": "11:0",
"invitedBy": null,
"sex": "male",
"online": true
}
PUT - Document
Update a document. Remember to always pass the version to update. This prevent to
update documents changed by other users (MVCC).
Syntax: http://<server>:[<port>]/document/<database>[/<record-id>][?updateMode=full|partial]
Where:
updateMode can be full (default) or partial. With partial mode only the delta of
changes is sent, otherwise the entire document is replaced (full mode)
Example
content:
{
"@class": "Profile",
"@version": 3,
"nick": "GGaribaldi",
"followings": [],
"followers": [],
"name": "Giuseppe",
"online": true
}
HTTP response, as the updated document with the updated @version field (Since v1.6):
725
content:
{
"@class": "Profile",
"@version": 4,
"nick": "GGaribaldi",
"followings": [],
"followers": [],
"name": "Giuseppe",
"online": true
}
DELETE - Document
Delete a document.
Syntax: http://<server>:[<port>]/document/<database>/<record-id>
Example
726
Document By Class
Syntax: http://<server>:[<port>]/documentbyclass/<database>/<class-name>/<record-position>
[/fetchPlan]
Where:
Example
HTTP response:
{
"_id": "9:0",
"_ver": 2,
"@class": "Profile",
"nick": "GGaribaldi",
"followings": [],
"followers": [],
"name": "Giuseppe",
"surname": "Garibaldi",
"location": "11:0",
"invitedBy": null,
"sex": "male",
"online": true
}
727
Syntax: http://<server>:[<port>]/documentbyclass/<database>/<class-name>/<record-position>
Where:
Example
728
Allocation
GET - Allocation
Syntax: http://<server>:[<port>]/allocation/<database>
Example
HTTP response: { "size": 61910, "segments": [ {"type": "d", "offset": 0, "size": 33154},
{"type": "h", "offset": 33154, "size": 4859}, {"type": "h", "offset": 3420, "size": 9392},
{"type": "d", "offset": 12812, "size": 49098} ], "dataSize": 47659, "dataSizePercent": 76,
"holesSize": 14251, "holesSizePercent": 24 }
729
Index
NOTE: Every single new database has the default manual index called "dictionary".
GET - Index
Syntax: http://<server>:[<port>]/index/<index-name>/<key>
Example
{
"name" : "Jay",
"surname" : "Miner"
}
PUT - Index
Syntax: http://<server>:[<port>]/index/<index-name>/<key>
Example
DELETE - Index
Syntax: http://<server>:[<port>]/index/<index-name>/<key>
Example
730
HTTP DELETE request: http://localhost:2480/dictionary/test HTTP response: No
response.
731
Query
GET - Query
Execute a query against the database. Query means only idempotent commands like
SQL SELECT and TRAVERSE. Idempotent means the command is read-only and can't
change the database. Remember that in IE6 the URL can be maximum of 2,083
characters. Other browsers supports major length, but if you want to stay compatible
with all limit to 2,083 characters.
Syntax: http://<server>:[<port>]/query/<database>/<language>/<query-text>[/<limit>]
[/<fetchPlan>]
Where:
To use commands that change the database (non-idempotent), see the POST
Command section
The command-text included in the URL must be encoded as per a normal URL
See the SQL section for the type of queries that can be sent
Example
HTTP response:
{ "result": [
{
"_id": "-3:1",
"_ver": 0,
732
"@class": "Address",
"type": "Residence",
"street": "Piazza di Spagna",
"city": "-4:0"
},
{
"_id": "-3:2",
"_ver": 0,
"@class": "Address",
"type": "Residence",
"street": "test",
"city": "-4:1"
}] }
The same query with the limit to maximum 20 results using the fetch plan *:-1 that
means load all recursively:
733
Server
GET - Server
Syntax: http://<server>:[<port>]/server
Example
{
"connections": [{
"id": "4",
"id": "4",
"remoteAddress": "0:0:0:0:0:0:0:1:52504",
"db": "-",
"user": "-",
"protocol": "HTTP-DB",
"totalRequests": "1",
"commandInfo": "Server status",
"commandDetail": "-",
"lastCommandOn": "2010-05-26 05:08:58",
"lastCommandInfo": "-",
"lastCommandDetail": "-",
"lastExecutionTime": "0",
"totalWorkingTime": "0",
...
734
Connection
POST - Connection
Syntax: http://<server>:[<port>]/connection/<command>/<id>
Where:
id, as the connection id. To know all the connections use GET /connections/[<db>]
You've to execute this command authenticated in the OrientDB Server realm (no
database realm), so get the root password from config/orientdb-server-config.xml file
(last section).
735
Binary Protocol
Current protocol version for 2.0-SNAPSHOT: 28. Look at compatibility for retro-
compatibility.
736
Table of content
Introduction
Connection
Getting started
Session
Response
Statuses
Errors
Operations
REQUEST_SHUTDOWN
REQUEST_CONNECT
REQUEST_DB_OPEN
REQUEST_DB_CREATE
REQUEST_DB_CLOSE
REQUEST_DB_EXIST
REQUEST_DB_RELOAD
REQUEST_DB_DROP
REQUEST_DB_SIZE
REQUEST_DB_COUNTRECORDS
REQUEST_DATACLUSTER_ADD
REQUEST_DATACLUSTER_DROP
REQUEST_DATACLUSTER_COUNT
Example
REQUEST_DATACLUSTER_DATARANGE
Example
REQUEST_RECORD_LOAD
REQUEST_RECORD_CREATE
737
REQUEST_RECORD_UPDATE
REQUEST_RECORD_DELETE
REQUEST_COMMAND
SQL command payload
SQL Script command payload
REQUEST_TX_COMMIT
History
Version 24
Version 23
Version 22
Version 21
Version 20
Version 19
Version 18
Version 17
Version 16
Version 15
Version 14
Version 13
Version 12
Version 11
Compatibility
738
Introduction
The OrientDB binary protocol is the fastest way to interface a client application to an
OrientDB Server instance. The aim of this page is to provide a starting point from which
to build a language binding, maintaining high-performance.
If you'd like to develop a new binding, please take a look to the available ones before
starting a new project from scratch: Existent Drivers.
739
Connection
(Since 0.9.24-SNAPSHOT Nov 25th 2010) Once connected, the server sends a short
number (2 byte) containing the binary protocol number. The client should check that it
supports that version of the protocol. Every time the protocol changes the version is
incremented.
740
Getting started
After the connection has been established, a client can Connect to the server or request
the opening of a database Database Open. Currently, only TCP/IP raw sockets are
supported. For this operation use socket APIs appropriate to the language you're using.
After the Connect and Database Open all the client's requests are sent to the server
until the client closes the socket. When the socket is closed, OrientDB Server instance
frees resources the used for the connection.
The first operation following the socket-level connection must be one of:
In both cases a Session-Id is sent back to the client. The server assigns a unique
Session-Id to the client. This value must be used for all further operations against the
server. You may open a database after connecting to the server, using the same
Session-Id
741
Session
The session managment is implemented in two different way, one stateful another
stateless this is choosed in the open/connect operation with a flag, the stateful is based
on a Session-id the stateless is based on a Token
742
Session-Id
All the operations that follow the open/connect must contain, as the first parameter, the
client Session-Id (as Integer, 4 bytes) and it will be sent back on completion of the
request just after the result field.
NOTE: In order to create a new server-side connection, the client must send a negative
number into the open/connect calls.
This Session-Id can be used into the client to keep track of the requests if it handles
multiple session bound to the same connection. In this way the client can implement a
sharing policy to save resources. This requires that the client implementation handle the
response returned and dispatch it to the correct caller thread.
743
Token
All the operation in a stateless session are based on the token, the token is a byte[] that
contains all the information for the interaction with the server, the token is acquired at the
mement of open or connect, and need to be resend for each request. the session id
used in the stateful requests is still there and is used to associate the request to the
response. in the response can be resend a token in case of expire renew.
744
Enable debug messages on protocol
To make the development of a new client easier it's strongly suggested to activate debug
mode on the binary channel. To activate this, edit the file orientdb-server-config.xml and
configure the new parameter "network.binary.debug" on the "binary" or "distributed"
listener. E.g.:
...
<listener protocol="distributed" port-range="2424-2430"
ip-address="127.0.0.1">
<parameters>
<parameter name="network.binary.debug" value="true" />
</parameters>
</listener>
...
In the log file (or the console if you have configured the orientdb-server-log.properties
file) all the packets received will be printed.
745
Exchange
This is the typical exchange of messages between client and server sides:
+------+ +------+
|Client| |Server|
+------+ +------+
| TCP/IP Socket connection |
+-------------------------->|
| DB_OPEN |
+-------------------------->|
| RESPONSE (+ SESSION-ID) |
+<--------------------------+
... ...
| REQUEST (+ SESSION-ID) |
+-------------------------->|
| RESPONSE (+ SESSION-ID) |
+<--------------------------+
... ...
| DB_CLOSE (+ SESSION-ID) |
+-------------------------->|
| TCP/IP Socket close |
+-------------------------->|
746
Network message format
In explaining the network messages these conventions will be used:
fields are bracketed by parenthesis and contain the name and the type separated by
':'. E.g. (length:int)
747
Supported types
The network protocol supports different types of information:
Minimum Maximum
Type length in length in Notes Example
bytes bytes
Signed integer
int 4 4 type 0001
An entire record
serialized. The
format depends if
a RID is passed or
an entire record
with its content. In
case of null record
then -2 as short is
passed. In case of
RID -3 is passes
as short and then
record 2 N the RID: (-3:short)
(cluster-id:short)
(cluster-
position:long) . In
case of record:
(0:short)(record-
type:byte)(cluster-
id:short)(cluster-
position:long)
(record-version:int)
(record-
content:bytes)
748
strings 4 N The format is: 00020005Hello0007World!
(length:int)[(Nth-
string:string)]
749
Record format
The record format is choose during the CONNECT or DB_OPEN request, the formats
available are:
The CSV format is the default for all the versions 0. and 1. or for any client with Network
Protocol Version < 22
750
Request
Each request has own format depending of the operation requested. The operation
requested is indicated in the first byte:
1 byte for the operation. See Operation types for the list
4 bytes for the Session-Id number as Integer
N bytes optional token bytes only present if the
REQUEST_CONNECT/REQUEST_DB_OPEN return a token.
N bytes = message content based on the operation type
751
Operation types
Value
Command as
byte
REQUEST_DATACLUSTER_LH_CLUSTER_IS_USED 16
752
REQUEST_RECORD_LOAD 30 Load a record.
REQUEST_RECORD_UPDATE 32
REQUEST_PUSH_RECORD 79
REQUEST_PUSH_DISTRIB_CONFIG 80
REQUEST_DB_COPY 90
REQUEST_REPLICATION 91
REQUEST_CLUSTER 92
REQUEST_DB_TRANSFER 93
REQUEST_DB_FREEZE 94
REQUEST_DB_RELEASE 95
REQUEST_DATACLUSTER_FREEZE 96
REQUEST_DATACLUSTER_RELEASE 97
753
Response
Every request has a response unless the command supports the asynchronous mode
(look at the table above).
754
Statuses
Every time the client sends a request, and the command is not in asynchronous mode
(look at the table above), client must read the one-byte response status that indicates
OK or ERROR. The rest of response bytes depends on this first byte.
* OK = 0;
* ERROR = 1;
OK response bytes are depends for every request type. ERROR response bytes
sequence described below.
755
Errors
The format is: [(1)(exception-class:string)(exception-message:string)]*(0)(serialized-
exception:bytes)
The pairs exception-class and exception-message continue while the following byte is 1.
A 0 in this position indicates that no more data follows.
E.g. (parentheses are used here just to separate fields to make this easier to read: they
are not present in the server response):
Since 1.6.1 we also send serialized version of exception thrown on server side. This
allows to preserve full stack trace of server exception on client side but this feature can
be used by Java clients only.
756
Operations
This section explains the request and response messages of all suported operations.
757
REQUEST_SHUTDOWN
Shut down the server. Requires "shutdown" permission to be set in orientdb-server-
config.xml file.
Request: (user-name:string)(user-password:string)
Response: empty
Typically the credentials are those of the OrientDB server administrator. This is not the
same as the admin user for individual databases.
758
REQUEST_CONNECT
This is the first operation requested by the client when it needs to work with the server
instance. It returns the session id of the client.
Request: (driver-name:string)(driver-version:string)(protocol-version:short)(client-id:string)(serializat
Response: (session-id:int)(token:bytes)
Where:
request content:
response content:
759
REQUEST_DB_OPEN
This is the first operation the client should call. It opens a database on the remote
OrientDB Server. Returns the Session-Id to being reused for all the next calls and the list
of configured clusters.
Request: (driver-name:string)(driver-version:string)(protocol-version:short)(client-id:string)(serializat
Response: (session-id:int)(token:bytes)(num-of-clusters:short)[(cluster-name:string)(cluster-id:short)](c
response detail :
760
REQUEST_DB_CREATE
Creates a database in the remote OrientDB server instance
Request: (database-name:string)(database-type:string)(storage-type:string)
Response: empty
Where:
761
REQUEST_DB_CLOSE
Closes the database and the network connection to the OrientDB Server instance. No
return is expected. The socket is also closed.
Request: empty
Response: no response, the socket is just closed at server side
762
REQUEST_DB_EXIST
Asks if a database exists in the OrientDB Server instance. It returns true (non-zero) or
false (zero).
Where:
763
REQUEST_DB_RELOAD
Reloads database information. Available since 1.0rc4.
Request: empty
Response:(num-of-clusters:short)[(cluster-name:string)(cluster-id:short)]
764
REQUEST_DB_DROP
Removes a database from the OrientDB Server instance. It returns nothing if the
database has been deleted or throws a OStorageException if the database doesn't
exists.
Where:
765
REQUEST_DB_SIZE
Asks for the size of a database in the OrientDB Server instance.
Request: empty
Response: (size:long)
766
REQUEST_DB_COUNTRECORDS
Asks for the number of records in a database in the OrientDB Server instance.
Request: empty
Response: (count:long)
767
REQUEST_DATACLUSTER_ADD
Add a new data cluster.
768
REQUEST_DATACLUSTER_DROP
Remove a cluster.
Request: (cluster-number:short)
Response: (delete-on-clientside:byte)
Where:
delete-on-clientside can be 1 if the cluster has been successfully removed and the
client has to remove too, otherwise 0
769
REQUEST_DATACLUSTER_COUNT
Returns the number of records in one or more clusters.
Request: (cluster-count:short)(cluster-number:short)*(count-tombstones:byte)
Response: (records-in-clusters:long)
Where:
Example
Request the record count for clusters 5, 6 and 7. Note the "03" at the beginning to tell
you're passing 3 cluster ids (as short each). 1,000 as long (8 bytes) is the answer.
Request: 03050607
Response: 00001000
770
REQUEST_DATACLUSTER_DATARANGE
Returns the range of record ids for a cluster.
Request: (cluster-number:short)
Response: (begin:long)(end:long)
Example
Request the range for cluster 7. The range 0-1,000 is returned in the response as 2
longs (8 bytes each).
Request: 07
Response: 0000000000001000
771
REQUEST_RECORD_LOAD
Load a record by RecordID, according to a fetch plan
Request: (cluster-id:short)(cluster-position:long)(fetch-plan:string)(ignore-cache:byte)(load-tombstones:
Response: [(payload-status:byte)[(record-type:byte)(record-version:int)(record-content:bytes)]*]+
Where:
772
REQUEST_RECORD_CREATE
Create a new record. Returns the position in the cluster of the new record. New records
can have version > 0 (since v1.0) in case the RID has been recycled.
Request: (cluster-id:short)(record-content:bytes)(record-type:byte)(mode:byte)
Response: (cluster-id:short)(cluster-position:long)(record-version:int)(count-of-collection-changes)[(uui
Where:
The last part of response is referred to RidBag management. Take a look at the main
page for more details.
773
REQUEST_RECORD_UPDATE
Update a record. Returns the new record's version.
Request: (cluster-id:short)(cluster-position:long)(update-content:boolean)(record-content:bytes)(record-v
Response: (record-version:int)(count-of-collection-changes)[(uuid-most-sig-bits:long)(uuid-least-sig-bits
true - content of record has been changed and content should be updated in
storage
false - the record was modified but its own content has not been changed. So
related collections (e.g. rig-bags) have to be updated, but record version and
content should not be.
The last part of response is referred to RidBag management. Take a look at the main
page for more details.
774
REQUEST_RECORD_DELETE
Delete a record by its RecordID. During the optimistic transaction the record will be
deleted only if the versions match. Returns true if has been deleted otherwise false.
Request: (cluster-id:short)(cluster-position:long)(record-version:int)(mode:byte)
Response: (payload-status:byte)
Where:
mode is:
0 = synchronous (default mode waits for the answer)
1 = asynchronous (don't need an answer)
payload-status returns 1 if the record has been deleted, otherwise 0. If the record
didn't exist 0 is returned.
775
REQUEST_COMMAND
Executes remote commands:
Request: (mode:byte)(command-payload-length:int)(class-name:string)(command-payload)
Response:
- synchronous commands: [(synch-result-type:byte)[(synch-result-content:?)]]+
- asynchronous commands: [(asynch-result-type:byte)[(asynch-result-content:?)]*](pre-fetched-record-size.
mode can be 'a' for asynchronous mode and 's' for synchronous mode
command-payload-length is the length of the class-name field plus the command-
payload field
class-name is the class name of the command implementation. There are short
form for the most common commands:
q stands for query as idempotent command. It's like passing
com.orientechnologies.orient.core.sql.query.OSQLSynchQuery
synchronous:
synch-result-type can be:
'n', means null result
'r', means single record returned
'l', collection of records. The format is:
an integer to indicate the collection size
776
all the records one by one
'a', serialized result, a byte[] is sent
777
REQUEST_TX_COMMIT
Commits a transaction. This operation flushes all the pending changes to the server
side.
tx-entry: (operation-type:byte)(cluster-id:short)(cluster-position:long)(record-type:byte)(entry-content
entry-content for CREATE: (record-content:bytes)
entry-content for UPDATE: (version:record-version)(content-changed:boolean)(record-content:bytes)
entry-content for DELETE: (version:record-version)
Response: (created-record-count:int)[(client-specified-cluster-id:short)(client-specified-cluster-positio
Where:
This response contains two parts: a map of 'temporary' client-generated record ids to
'real' server-provided record ids for each CREATED record, and a map of UPDATED
record ids to update record-versions.
The last part or response is referred to RidBag management. Take a look at the main
page for more details.
778
REQUEST_CREATE_SBTREE_BONSAI
Request: (clusterId:int)
Response: (collectionPointer)
REQUEST_SBTREE_BONSAI_GET
Request: (collectionPointer)(key:binary)
Response: (valueSerializerId:byte)(value:binary)
Key and value are serialized according to format of tree serializer. If the operation is
used by RidBag key is always a RID and value can be null or integer.
REQUEST_SBTREE_BONSAI_FIRST_KEY
Request: (collectionPointer)
Response: (keySerializerId:byte)(key:binary)
Key are serialized according to format of tree serializer. If the operation is used by
RidBag key is null or RID.
REQUEST_SBTREE_BONSAI_GET_ENTRIES_MAJOR
Request: (collectionPointer)(key:binary)(inclusive:boolean)(pageSize:int)
Response: (count:int)[(key:binary)(value:binary)]*
779
See: serialization of collection pointer
Gets the portion of entries major than specified one. If returns 0 entries than the
specified entry is the largest.
Keys and values are serialized according to format of tree serializer. If the operation is
used by RidBag key is always a RID and value is integer.
REQUEST_RIDBAG_GET_SIZE
Request: (collectionPointer)(collectionChanges)
Response: (size:int)
Rid-bag specific operation. Send but does not save changes of rid bag. Retrieves
computed size of rid bag.
780
Special use of LINKSET types
NOTE. Since 1.7rc1 this feature is deprecated. Usage of RidBag is preferable.
Starting from 1.0rc8-SNAPSHOT OrientDB can transform collections of links from the
classic mode:
[#10:3,#10:4,#10:5]
to:
(ORIDs@pageSize:16,root:#2:6)
mvrbtree.ridBinaryThreshold = -1
Where mvrbtree.ridBinaryThreshold is the threshold where OrientDB will use the tree
instead of plain collection (as before). -1 means "hey, never use the new mode but leave
all as before".
781
Tree node binary structure
To improve performance this structure is managed in binary form. Below how is made:
+-----------+-----------+--------+------------+----------+-----------+---------------------+
| TREE SIZE | NODE SIZE | COLOR .| PARENT RID | LEFT RID | RIGHT RID | RID LIST .......... |
+-----------+-----------+--------+------------+----------+-----------+---------------------+
| 4 bytes . | 4 bytes . | 1 byte | 10 bytes ..| 10 bytes | 10 bytes .| 10 * MAX_SIZE bytes |
+-----------+-----------+--------+------------+----------+-----------+---------------------+
= 39 bytes + 10 * PAGE-SIZE bytes
Where:
TREE SIZE as signed integer (4 bytes) containing the size of the tree. Only the root
node has this value updated, so to know the size of the collection you need to load
the root node and get this field. other nodes can contain not updated values
because upon rotation of pieces of the tree (made during tree rebalancing) the root
can change and the old root will have the "old" size as dirty.
NODE SIZE as signed integer (4 bytes) containing number of entries in this node.
It's always <= to the page-size defined at the tree level and equals for all the nodes.
By default page-size is 16 items
COLOR as 1 byte containing 1=Black, 0=Red. To know more about the meaning of
this look at Red-Black Trees
PARENT RID as RID (10 bytes) of the parent node record
LEFT RID as RID (10 bytes) of the left node record
RIGHT RID as RID (10 bytes) of the right node record
RID LIST as the list of RIDs containing the references to the records. This is pre-
allocated to the configured page-size. Since each RID takes 10 bytes, a page-size
of 16 means 16 x 10bytes = 160bytes
The size of the tree-node on disk (and memory) is fixed to avoid fragmentation. To
compute it: 39 bytes + 10 * PAGE-SIZE bytes. For a page-size = 16 you'll have 39 + 160
= 199 bytes.
782
History
Version 28
Since version 28 the REQUEST_RECORD_LOAD response order is changed from:
[(payload-status:byte)[(record-content:bytes)(record-version:int)(record-type:byte)]*]+ to:
[(payload-status:byte)[(record-type:byte)(record-version:int)(record-content:bytes)]*]+
783
Version 27
Since version 27 is introduced an extension to allow use a token based session, if this
modality is enabled a few things change in the modality the protocol works.
in the first negotiation the client should ask for a token based authentication using
the token-auth flag
the server will reply with a token or an empty byte array that means that it not
support token based session and is using a old style session.
if the server don't send back the token the client can fail or drop back the the old
modality.
for each request the client should send the token and the sessionId
the sessionId is needed only for match a response to a request
if used the token the connections can be shared between users and db of the same
server, not needed to have connection associated to db and user.
REQUEST_DB_OPEN
REQUEST_CONNECT
784
Version 26
added cluster-id in the REQUEST_CREATE_RECORD response.
785
Version 25
Reviewd serialization of index changes in the REQUEST_TX_COMMIT for detais #2676
Removed double serialization of commands parameters, now the parameters are
directly serialized in a document see Network Binary Protocol Commands and #2301
786
Version 24
cluster-type and cluster-dataSegmentId parameters were removed from response
for REQUEST_DB_OPEN, REQUEST_DB_RELOAD requests.
datasegment-id parameter was removed from REQUEST_RECORD_CREATE
request.
type, location and datasegment-name parameters were removed from
REQUEST_DATACLUSTER_ADD request.
REQUEST_DATASEGMENT_ADD request was removed.
REQUEST_DATASEGMENT_DROP request was removed.
787
Version 23
Add support of updateContent flag to UPDATE_RECORD and COMMIT
788
Version 22
REQUEST_CONNECT and REQUEST_OPEN now send the document serialization
format that the client require
789
Version 21
REQUEST_SBTREE_BONSAI_GET_ENTRIES_MAJOR (which is used to iterate
through SBTree) now gets "pageSize" as int as last argument. Version 20 had a
fixed pageSize=5. The new version provides configurable pageSize by client.
Default pageSize value for protocol=20 has been changed to 128.
790
Version 20
Rid bag commands were introduced.
Save/commit was adapted to support client notifications about changes of collection
pointers.
791
Version 19
Serialized version of server exception is sent to the client.
792
Version 18
Ability to set cluster id during cluster creation was added.
793
Version 17
Synchronous commands can send fetched records like asynchronous one.
794
Version 16
Storage type is required for REQUEST_DB_FREEZE, REQUEST_DB_RELEASE,
REQUEST_DB_DROP, REQUEST_DB_EXIST commands.
This is required to support plocal storage.
795
Version 15
SET types are stored in different way then LIST. Before rel. 15 both were stored
between squared braces [] while now SET are stored between <>
796
Version 14
DB_OPEN returns information about version of OrientDB deployed on server.
797
Version 13
To support upcoming auto-sharding support feature following changes were done
RECORD_LOAD flag to support ability to load tombstones was added.
DATACLUSTER_COUNT flag to support ability to count tombstones in cluster
was added.
798
Version 12
DB_OPEN returns the dataSegmentId foreach cluster
799
Version 11
RECORD_CREATE always returns the record version. This was necessary
because new records could have version > 0 to avoid MVCC problems on RID
recycle
800
Compatibility
Current release of OrientDB server supports older client versions.
801
CSV Serialization
The CSV serialzation is the format how record are serialized in the orientdb 0. and 1.
version.
Documents are serialized in a proprietary format (as a string) derived from JSON, but
more compact. The string retrieved from the storage could be filled with spaces. This is
due to the oversize feature if it is set. Just ignore the tailing spaces.
\ -> \
The class, if present, is at the begin and must end with @ . E.g. Customer@
Each Field must be present with its name and value separated by : .
E.g. name:"Barack"
Fields must be separated by , . E.g. name:"Barack",surname:"Obama"
All Strings must be enclosed by " character. E.g. city:"Rome"
All Binary content (like byte[must be encoded in Base64 and enclosed by
underscore character. E.g. buffer:_AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGx . Since
v1.0rc7
Numbers (integer, long, short, byte, floats, double) are formatted as strings as ouput
by the Java toString() method. No thousands separator must be used. The decimal
separator is always . Starting from version 0.9.25, if the type is not integer, a suffix
is used to distinguish the right type when unmarshalled: b=byte, s=short, l=long,
f=float, d=double, c=BigDecimal (since 1.0rc8). E.g. salary:120.3f or code:124b .
Output of Floats
Output of Doubles
Output of BigDecimal
Booleans are expressed as true and false always in lower-case. They are
recognized as boolean since the text has no double quote as is the case with strings
Dates must be in the POSIX format (also called UNIX format:
http://en.wikipedia.org/wiki/Unix_time). Are always stored as longs but end with:
the 't' character when it's DATETIME type (default in schema-less mode when a
Date object is used). Datetime handles the maximum precision up to milliseconds.
E.g. lastUpdate:1296279468000t is read as 2011-01-29 05:37:48
the 'a' character when it's DATE type. Date handles up to day as precision. E.g.
802
lastUpdate:1306281600000a is read as 2011-05-25 00:00:00 (Available since 1.0rc2)
RecordID (link) must be prefixed by # . A Record Id always has the format
<cluster-id>:<cluster-position> . E.g. location:#3:2
Embedded documents are enclosed by parenthesis ( and ) characters. E.g.
(name:"rules") . Note: before SVN revision 2007 (0.9.24-snapshot) only characters
were used to begin and end the embedded document.*
Lists (array and list) must be enclosed by [ and ] characters. E.g. [1,2,3] ,
[#10:3,#10:4] and [(name:"Luca")] . Before rel.15 SET type was stored as a list, but
now it uses own format (see below)
Sets (collections without duplicates) must be enclosed by < and > characters.
E.g. <1,2,3> , <#10:3,#10:4> and <(name:"Luca")> . There is a special case when use
LINKSET type reported in detail in Special use of LINKSET types section. Before
rel.15 SET type was stored as a list (see upon).
Maps (as a collection of entries with key/value) must be enclosed in { and }
characters. E.g. rules:{"database":2,"database.cluster.internal":2</code>} (NB. to set a
value part of a key/value pair, set it to the text "null", without quotation marks. Eg.
rules:{"database_name":"fred","database_alias":null} )
[<class>@][,][<field-name>:<field-value>]*
Profile@nick:"ThePresident",follows:[],followers:[#10:5,#10:6],name:"Barack",surname:"Obama",
location:#3:2,invitedBy:,salary_cloned:,salary:120.3f
Complex example used in schema (line breaks introduced so it's visible on this page):
name:"ORole",id:0,defaultClusterId:3,clusterIds:[3],properties:[(name:"mode",type:17,offset:0,
mandatory:false,notNull:false,min:,max:,linkedClass:,
linkedType:,index:),(name:"rules",type:12,offset:1,mandatory:false,notNull:false,min:,
max:,linkedClass:,linkedType:17,index:)]
803
Other example of ORole that uses a map (line breaks introduced so it's visible on this
page):
ORole@name:"reader",inheritedRole:,mode:0,rules:{"database":2,"database.cluster.internal":2,"database.clu
"database.class.*":2,"database.cluster.*":2,"database.query":2,"database.command":2,
"database.hook.record":2}
804
Serialization
Below the serialization of types in JSON and Binary format (always refers to latest
version of the protocol).
805
Collections of values separated
Embedded by commas and surrounded by
list Example: [20, 30]
brackets "[ ]". Example: [20,
30]
806
Schemaless Serialization
The binary schemaless serialization is an attempt to define a serialization format that
can serialize a document containing all the information about the structure and the data,
with no need of a external schema definition and with support for partial
serialization/deserialization.
+---------------+------------------+---------------+-------------+
| version:byte | className:string | header:byte[] | data:byte[] |
+---------------+------------------+---------------+-------------+
807
Version
1 byte that contain the version of the current record serialization, to allow progressive
serialization upgrade
808
Class Name
A String containing the name of the class of the record, if the record has no class will be
just an empty string, the serialization of the string is the same of the String value
809
Header
The header contains the list of fields names of the current record with the association to
the data location
+----------------------------+
| fields:field_definition[] |
+----------------------------+
field definition
+-----------------------------+-------------------+-------------------------------+----------------+
| field_name_length|id:varint | field_name:byte[] | pointer_to_data_structure:int | data_type:byte |
+-----------------------------+-------------------+-------------------------------+----------------+
field_name_length varint that describe the field, if positive is the size of the string that
fallow next if negative is and id of current property referred in the schema, if is 0 mark
the end of the header.
field_name the field name present only with field_name_length > 0
pointer_to_data a pointer to the data structure in the data segment that contains the
field value or 0 if the field is null
data_type the field type id, the supported types are defined here OType present only
with field_name_length > 0
Property ID
the relative property will be found in the schema, stored in the globalProperty list at the
root of the document that rapresent the schema definition.
810
Data
The data segment is where the data is stored is composed by an array of data structure
+------------------------+
| data:data_structure[] |
+------------------------+
each data structures content is depended to the field type, each type have it's own
serialization structure
811
field_data serialization by type
SHORT,INTEGER,LONG
The Integer numbers will be serialized as variable size integer it use the same format of
protobuf specified HERE
-64 < value < 64 1 byte
-8192 < value < 8192 2 byte
-1048576 < value < 1048576 3 byte
-134217728 < value < 134217728 4 byte
-17179869184 < value < 17179869184 5 byte
all the negative value are translated to positive using the ZigZag encoding
BYTE
BOOLEAN
FLOAT
This is stored as flat byte array copying the memory from the float memory
+---------------+
| float:byte[4] |
+---------------+
DOUBLE
This is stored as flat byte array copying the memory from the double memory
+---------------+
| float:byte[8] |
+---------------+
812
DATETIME
The date is converted to millisecond unix epoch and stored as the type LONG
DATE
STRING
+-------------+----------------+
| size:varInt | string:byte[] |
+-------------+----------------+
size the number of the bytes in the string stored(not the length of the string) as variable
size integer string the bytes of the string in UTF-8 encodings
BINARY
+--------------+----------------+
| size:varInt | bytes:byte[] |
+--------------+----------------+
size the number of the bytes to store bytes the row bytes
EMBEDDED
embedded document
+-----------------------------+
813
| serialized_document:bytes[] |
+-----------------------------+
EMBEDDEDLIST, EMBEDDEDSET
The embedded collections is stored as an array of bytes that contain the serialized
document in the embedded mode.
+-------------+------------+-------------------+
|size:varInt | type:Otype | items:item_data[] |
+-------------+------------+-------------------+
size the number of items in the list type the type of the types in the list or ANY if the type
is unknown items an array of value serialized by type or if the type is ANY the item will
have it's own structure.
EMBEDDEDMAP
+---------------------------+-------------------------+
| header:headerStructure | values:valueStructure |
+---------------------------+-------------------------+
header structure
+--------------+------------------+
| keyType:byte | keyValue:byte[] |
+--------------+------------------+
Current implementation convert all the keys to string keyType is the type of the key,
814
can be only one of the listed type. keyValue the value of the key serialized with the
serializer of the type
value structure
+---------------+---------------+
|valueType:byte | value:byte[] |
+---------------+---------------+
valueType the OType of the stored value value the value serialized with the serializer
selected by OType
LINK
+--------------+--------------+
|cluster:64int | record:64Int |
+--------------+--------------+
LINKLIST, LINKSET
+-------------+---------------------+
| size:varint | collection:LINK[] |
+-------------+---------------------+
size the number of links in the collection collection an array of LINK each element is
serialized as LINK type.
LINKMAP
+----------------------------+
| values:link_map_entry[] |
815
+----------------------------+
link_map_entry structure
+--------------+------------------+------------+
| keyType:byte | keyValue:byte[] | link:LINK |
+--------------+------------------+------------+
keyType is the type of the key, can be only one of the listed type. keyValue the value of
the key serialized with the serializer of the type link the link value store with the formant
of a LINK
DECIMAL
The Decimal is converted to an integer and stored as scale and value (example
"10234.546" is stored as scale "3" and value as:"10234546")
+---------------+-------------------+--------------+
| scale:byte[4] | valueSize:byte[4] | value:byte[] |
+---------------+-------------------+--------------+
scale an 4 byte integer that represent the scale of the value valueSize the length of the
value bytes value the bytes that represent the value of the decimal in big-endian order.
LINKBAG
816
Network Binary Protocol Commands
This is the guide to the commands you can send through the binary protocol.
817
See also
List of SQL Commands
Network Binary Protocol Specification
(text:string)(non-text-limit:int)[(fetch-plan:string)](serialized-params:bytes[])
SQL Commands
(text:string)(has-simple-parameters:boolean)(simple-paremeters:bytes[])(has-complex-parameters:boolean)(c
818
array is present or not
complex-parameters the byte[] result of the serialization of a ODocument.
Script
(language:string)(text:string)(has-simple-parameters:boolean)(simple-paremeters:bytes[])(has-complex-para
language the language of the script present in the text field. All the others paramenters
are serialized as the SQL Commands
819
Use Cases
This page contains the solution to the most common use cases. Please don't consider
them as the definitive solution, but as suggestions where to get the idea to solve your
needs.
820
Use cases
Time Series Use case
Use OrientDB as a Key/Value DBMS
821
Time Series Use Case
Managing records related to historical information is pretty common. When you've
millions of records indexes show their limitation because the cost to find the records is
O(logN). This is also the main reason why Relational DBMS are so slow with huge
database.
So when you've millions of record the best way to scale up linearly is avoid using
indexes at all or as much as you can. But how to retrieve records in short time without
indexes? Should OrientDB scan the entire database at every query? No. You should use
the Graph properties of OrientDB. Let's look at a simple example where the domain are
logs.
A typical log record has some information about the event and a date. Follows the Log
record to use in our example. We're going to use the JSON format to simplify reading:
{
"date" : 12293289328932,
"priority" : "critical",
"note" : "System reboot"
}
Now let's create a tree (that is a directed, non cyclic graph) to group the Log records
based on the granularity we need. Example:
Year -> month (map) -> Month -> day (map) -> Day -> hour (map) -> Hour
Where Year, Month, Day and Hour are vertex classes. Each Vertex links the other
Vertices of smaller type. The links should be handled using a Map to make easier the
writing of queries.
822
Example to retrieve the vertex relative to the date March 2012, 20th at 10am
(2012/03/20 10:00:00):
If you need more granularity than the Hour you can go ahead until the Time unit you
need:
Hour -> minute (map) -> Minute -> second (map) -> Second
Now connect the record to the right Calendar vertex. If the usual way to retrieve Log
records is by hour you could link the Log records in the Hour. Example:
Year -> month (map) -> Month -> day (map) -> Day -> hour (map) -> Hour -> log (set) -> Log
The "log" property connects the Time Unit to the Log records. So to retrieve all the log of
March 2012, 20th at 10am:
That could be used as starting point to retrieve only a sub-set of logs that satisfy certain
rules. Example:
select from (
select flatten( month[3].day[20].hour[10].logs ) from Year where year = "2012"
) where priority = 'critical'
That retrieves all the CRITICAL logs of March 2012, 20th at 10am.
823
Join multiple hours
If you need multiple hours/days/months as result set you can use the UNION function to
create a unique result set:
In this example we create a union between the 10th and 11th hours. But what about
extracting all the hours of a day without writing a huge query? The shortest way is using
the Traverse. Below the Traverse to get all the hours of one day:
So putting all together this query will extract all the logs of all the hours in a day:
824
Aggregate
Once you built up a Calendar in form of a Graph you can use it to store aggregated
values and link them to the right Time Unit. Example: store all the winning ticket of
Online Games. The record structure in our example is:
{
"date" : 12293289328932,
"win" : 10.34,
"machine" : "AKDJKD7673JJSH",
}
You can link this records to the closest Time Unit like the example above, but you could
sum all the records in the same Day and put link it to the Day vertex. Example:
Link it in the Calendar graph assuming the previous command returned #23:45 as the
RecordId of the brand new DailyLog record:
update (
select flatten( month[3].day[20] ) from Year where year = "2012"
) add logs = #23:45
825
Key Value Use Case
OrientDB can be used like a Key Value DBMS by using the super fast Indexes. You can
have as many Indexes as you need.
826
HTTP
OrientDB RESTful HTTP protocol allows to talk with a OrientDB Server instance using
the HTTP protocol and JSON. OrientDB supports also a highly optimized Binary protocol
for superior performances.
827
Operations
To interact against OrientDB indexes use the four methods of the HTTP protocol in
REST fashion:
828
Create an entry
To create a new entry in the database use the Index-PUT API.
Syntax: http://<server>:[<port>]/index/<index-name>/<key>
Example:
{
"name" : "Jay",
"surname" : "Miner"
}
829
Retrieve an entry
To retrieve an entry from the database use the Index-GET API.
Syntax: http://<server>:[<port>]/index/<index-name>/<key>
Example:
{
"name" : "Jay",
"surname" : "Miner"
}
830
Remove an entry
To remove an entry from the database use the Index-DELETE API.
Syntax: http://<server>:[<port>]/index/<index-name>/<key>
Example:
831
Step-by-Step tutorial
Before to start assure you've a OrientDB server up and running. In this example we'll
use curl considering the connection to localhost to the default HTTP post 2480. The
default "admin" user is used.
832
Create a new index
To use OrientDB as a Key/Value store we need a brand new manual index, let's call it
"mainbucket". We're going to create it as UNIQUE because keys cannot be duplicated. If
you can have multiple keys consider:
Response:
{ "result" : [
{ "@type" : "d" , "@version" : 0, "value" : 0, "@fieldTypes" : "value=l" }
]
}
833
Store the first entry
Below we're going to insert the first entry by using the HTTP PUT method passing "jay"
as key in the URL and as value the entire document in form of JSON:
Response:
834
Retrieve the entry just inserted
Below we're going to retrieve the entry we just entered by using the HTTP GET method
passing "jay" as key in the URL:
Response:
[{
"@type" : "d" , "@rid" : "#3:477" , "@version" : 0,
"name" : "Jay",
"surname" : "Miner"
}]
Note that an array is always returned in case multiple records are associated to the
same key (if NOTUNIQUE index is used). Look also at the document has been created
with RID #3:477. You can load it directly if you know the RID. Remember to remove the
# character. Example:
Response:
{
"@type" : "d" , "@rid" : "#3:477" , "@version" : 0,
"name" : "Jay",
"surname" : "Miner"
}
835
Drop an index
Once finished drop the index "mainbucket" created for the example:
Response:
{ "result" : [
{ "@type" : "d" , "@version" : 0, "value" : 0, "@fieldTypes" : "value=l" }
]
}
836
OrientDB Server
OrientDB Server (DB-Server from now) is a multi-threaded Java application that listens
to remote commands and executes them against the Orient databases. OrientDB Server
supports both binary and HTTP protocols. The first one is used by the Orient native
client and the Orient Console. The second one can be used by any languages since it's
based on HTTP RESTful API. The HTTP protocol is used also by the OrientDB Studio
application.
837
Install as a service
OrientDB Server is part of Community and Enterprise distributions. To install OrientDB
as service follow the following guides
838
Start the server
To start the server, execute bin/orient-db.sh (or bin/orient-db.bat on Microsoft Windows
systems). By default both the binary and http interfaces are active. If you want to disable
one of these change the Server configuration.
Upon startup, the server runs on port 2424 for the binary protocol and 2480 for the http
one. If a port is busy the next free one will be used. The default range is 2424-2430
(binary) and 2480-2490 (http). These default ranges can be changed in in Server
configuration.
839
Stop the server
To stop a running server, press CTRL+C in the open shell that runs the Server instance
or soft kill the process to be sure that the opened databases close softly. Soft killing on
Windows can be done by closing the window. On Unix-like systems, a simple kill is
enough (Do not use kill -9 unless you want to force a hard shutdown).
840
Connect to the server
By Console
The OrientDB distribution provides the Orient Console tool as a console Java application
that uses the binary protocol to work with the database.
By OrientDB Studio
Starting from the release 0.9.13 Orient comes with the OrientDB Studio application, a
client-side web app that uses the HTTP protocol to work with the database.
By your application
Consider the native APIs if you use Java. For all the other languages you can use the
HTTP RESTful protocol.
841
Distributed servers
To setup a distributed configuration look at: Distributed-Architecture.
842
Change the Server's database directory
By default OrientDB server manages the database under the directory
"$ORIENTDB_HOME/databases" where $ORIENTDB_HOME is the OrientDB
installation directory. By setting the configuration parameter "server.database.path" in
server orientdb-server-config.xml you can specify a custom path. Example:
<orient-server>
...
<properties>
<entry value="C:/temp/databases" name="server.database.path" />
</properties>
</orient-server>
843
Configuration
Plugins
Plug-ins (old name "Handler") are the way the OrientDB Server can be extended.
Available plugins:
Automatic-Backup
EMail Plugin
JMX Plugin
Distributed-Server-Manager
Server-side script interpreter
Write your own
Protocols
Contains the list of protocols used by the listeners section. The protocols supported
today are:
binary: the Raw binary protocol used by OrientDB clients and console application.
http: the HTTP RESTful protocol used by OrientDB Studio and direct raw access
from any language and browsers.
Listeners
You can configure multiple listeners by adding items under the <listeners> tag and
selecting the ip-address and TCP/IP port to bind. The protocol used must be listed in the
protocols section. Listeners can be configured with single port or port range. If a range of
ports is specified, then it will try to acquire the first port available. If no such port is
available, then an error is thrown. By default the Server configuration activates
connections from both the protocols:
binary: by default the binary connections are listened to the port range 2424-2430.
http: by default the HTTP connections are listened to the port range 2480-2490.
Storages
844
Contains the list of the static configured storages. When the server starts for each
storages static configured storage enlisted check if exists. If exists opens it, otherwise
creates it transparently.
are located outside the default folder. You can use any environment variable in the
path such the ORIENT_HOME that points to the Orient installation path if defined
otherwise to the root directory where the Orient Server starts.
want to create/open automatically a database when the server start ups
Example of configuration:
To create a new database use the CREATE DATABASE console command or create it
dinamically using the Java-API.
Users
Starting from v.0.9.15 OrientDB supports per-server users in order to protect sensible
operations to the users. In facts the creation of a new database is a server operation as
much as the retrieving of server statistics.
When an OrientDB server starts for the first time, a new user called "root" will be
generated and saved in the server configuration. This avoid security problems when,
very often, the passwords remain the default ones.
Resources
User based authentication checks if the logged user has the permission to access to the
845
requested resource. "*" means access to all the resource. This is the typical setting for
the user "root". Multiple resources must be separated by comma.
Example to let to the "root" user to access to all the server commands:
Example to let to the "guest" user to access only to the "info-server" command:
<users>
<user name="MyUser" password="MyPassword" resources="database.exists"/>
</users>
846
Extend the server
To extend the server's features look at Extends the server.
847
Debug the server
To debug the server configure your IDE to execute the class OServerMain:
com.orientechnologies.orient.server.OServerMain
-server
-Dorientdb.config.file=config/orientdb-server-config.xml
-Dorientdb.www.path=src/site
-DORIENTDB_HOME=url/local/orientdb/releases/orientdb-1.2.0-SNAPSHOT
-Djava.util.logging.config.file=config/orientdb-server-log.properties
-Dcache.level1.enabled=false
-Dprofiler.enabled=true
848
Embed the Server
Embedding an OrientDB Server inside a Java application has several advantages and
interesting features:
Java application that runs embedded with the server can bypass the remote
connection and use the database directly with local mode. local and remote
connections against the same database can work in concurrency: OrientDB will
synchronize the access.
You can use the Console to control it
You can use the OrientDB Studio
You can replicate the database across distributed standalone or embedded servers
To embed an OrientDB Server inside a Java application you have to create the OServer
object and use a valid configuration for it.
849
Requirements
In order to embed the server you need to include the following jar files in the classpath:
orientdb-enterprise-**.jar
orientdb-server-**.jar
850
Include the commands you need
Even if most of the HTTP commands are auto registered assure to have all the
commands you need. For example the static content must be registered. This is
fundamental if you want to use OrientDB as Web Server providing static content like the
Studio app:
851
Use an embedded configuration
import com.orientechnologies.orient.server.OServerMain;
Once the embedded server is running, clients can connect using the remote connection
method. For example in the console, you can connect with:
852
Use custom file for configuration
Use a regular File :
853
Shutdown
OrientDB Server creates some threads internally as non-daemon, so they run even if the
main application exits. Use the OServer.shutdown() method to shutdown the server in soft
way:
import com.orientechnologies.orient.server.OServerMain;
854
OrientDB Plugins
The OrientDB Server is a customizable platform to build powerful server component and
applications.
Since the OrientDB server contains an integrated Web Server what about creating
server side applications without the need to have a J2EE and Servlet container? By
extending the server you can benefit of the best performance because you don't have
many layers but the database and the application reside on the same JVM without the
cost of the network and serialization of requests.
Furthermore you can package your application together with the OrientDB server to
distribute just a ZIP file containing the entire Application, Web server and Database.
Handlers
Custom commands
To debug the server while you develop new feature follow Debug the server.
855
Handlers (Server Plugins)
Handlers are plug-ins and starts when OrientDB starts.
To create a new handler create the class and register it in the OrientDB server
configuration.
856
Create the Handler class
A Handler must implements the OServerPlugin interface or extends the
OServerPluginAbstract abstract class.
Below an example of a handler that print every 5 seconds a message if the "log"
parameters has been configured to be "true":
package orientdb.test;
@Override
public void config(OServer oServer, OServerParameterConfiguration[] iParams) {
for (OServerParameterConfiguration p : iParams) {
if (p.name.equalsIgnoreCase("log"))
log = true;
}
@Override
public String getName() {
return "PrinterHandler";
}
}
857
Register the handler
Once created register it to the server configuration in orientdb-server-config.xml file:
<orient-server>
<handlers>
<handler class="orientdb.test.PrinterHandler">
<parameters>
<parameter name="log" value="true"/>
</parameters>
</handler>
</handlers>
...
Note that you can specify arbitrary parameters in form of name and value. Those
parameters can be read by the config() method. In this example a parameter "log" is
read. Look upon to the example of handler to know how to read parameters specified in
configuration.
858
Creating a distributed change manager
As more complete example let's create a distributed record manager by installing hooks
to all the server's databases and push these changes to the remote client caches.
@Override
public void config(OServer oServer, OServerParameterConfiguration[] iParams) {
for (OServerParameterConfiguration p : iParams) {
if (p.name.equalsIgnoreCase("log"))
log = true;
}
}
@Override
public void onAfterClientRequest(final OClientConnection iConnection, final byte iRequestType)
if (iRequestType == OChannelBinaryProtocol.REQUEST_DB_OPEN)
iConnection.database.registerHook(this);
else if (iRequestType == OChannelBinaryProtocol.REQUEST_DB_CLOSE)
iConnection.database.unregisterHook(this);
}
@Override
public boolean onTrigger(TYPE iType, ORecord<?> iRecord) {
try {
if (log)
System.out.println("Broadcasting record: " + iRecord + "...");
OClientConnectionManager.instance().broadcastRecord2Clients((ORecordInternal<?>) iRecord,
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
@Override
public String getName() {
return "DistributedRecordHook";
}
}
859
Custom commands
Custom commands are useful when you want to add behavior or business logic at the
server side.
860
The Hello World Web
To learn how to create a custom command, let's begin with a command that just returns
"Hello world!".
OServerCommand<method><name> Where:
method is the HTTP method and can be: GET, POST, PUT, DELETE
name is the command name
In our case the class name will be "OServerCommandGetHello". We want that the use
must be authenticated against the database to execute it as any user.
Furthermore we'd like to receive via configuration if we must display the text in Italic or
not, so for this purpose we'll declare a parameter named "italic" of type boolean (true or
false).
package org.example;
@Override
public boolean execute(final OHttpRequest iRequest, OHttpResponse iResponse) throws Exception
// CHECK THE SYNTAX. 3 IS THE NUMBER OF MANDATORY PARAMETERS
String[] urlParts = checkSyntax(iRequest.url, 3, "Syntax error: hello/<database>/<name>");
// TELLS TO THE SERVER WHAT I'M DOING (IT'S FOR THE PROFILER)
iRequest.data.commandInfo = "Salutation";
iRequest.data.commandDetail = "This is just a test";
861
result = "<i>" + result + "</i>";
}
@Override
public String[] getNames() {
return new String[]{"GET|hello/* POST|hello/*"};
}
}
Once created the command you need to register them through the orientdb-server-
config.xml file. Put a new tag <command> under the tag commands of <listener> with
attribute protocol="http" :
...
<listener protocol="http" port-range="2480-2490" ip-address="0.0.0.0">
<commands>
<command implementation="org.example.OServerCommandGetHello" pattern="GET|hello/*">
<parameters>
<entry name="italic" value="true"/>
</parameters>
</command>
</commands>
</listener>
Where:
http://localhost/hello/demo/Luca
862
You will see:
Hello Luca
863
Complete example
Below a more complex example taken by official distribution. It is the command that
executes queries via HTTP. Note how to get a database instance to execute operation
against the database:
@Override
public boolean execute(OHttpRequest iRequest, OHttpResponse iResponse) throws Exception {
String[] urlParts = checkSyntax(
iRequest.url,
4,
"Syntax error: query/<database>/sql/<query-text>[/<limit>][/<fetchPlan>].<br/>Limit is optional a
iRequest.data.commandInfo = "Query";
iRequest.data.commandDetail = text;
ODatabaseDocumentTx db = null;
List<OIdentifiable> response;
try {
db = getProfiledDatabaseInstance(iRequest);
response = (List<OIdentifiable>) db.command(new OSQLSynchQuery<OIdentifiable>(text, limit).setFetch
} finally {
if (db != null) {
db.close();
}
}
iResponse.writeRecords(response, fetchPlan);
return false;
}
@Override
public String[] getNames() {
return NAMES;
}
}
864
Include JARS in the classpath
If your extensions need additional libraries put the additional jar files under the /lib
folder of the server installation.
865
Debug the server
To debug your plugin you can start your server in debug mode.
Parameter Value
866
Automatic Backup Plugin
Java class implementation:
com.orientechnologies.orient.server.handler.OAutomaticBackup
867
Introduction
Configure an automatic backup of databases. This task is configured as a Server
handler. The task can be configured in easy way by changing parameters:
<!-- AUTOMATIC BACKUP, TO TURN ON SET THE 'ENABLED' PARAMETER TO 'true' -->
<handler class="com.orientechnologies.orient.server.handler.OAutomaticBackup">
<parameters>
<parameter name="enabled" value="false" />
<parameter name="delay" value="4h" />
<parameter name="target.directory" value="backup" />
<parameter name="target.fileName" value="${DBNAME}-${DATE:yyyyMMddHHmmss}.zip" /><!-- ${DBNAME} AND $
<parameter name="db.include" value="" /><!-- DEFAULT: NO ONE, THAT MEANS ALL DATABASES. USE COMMA TO
<parameter name="db.exclude" value="" /><!-- USE COMMA TO SEPARATE MULTIPLE DATABASE NAMES -->
<parameter name="compressionLevel" value="9"/>
<parameter name="bufferSize" value="1048576"/>
</parameters>
</handler>
868
Mail Plugin
Java class implementation:
com.orientechnologies.orient.server.plugin.mail.OMailPlugin
869
Introduction
Allows to send (and in future read) emails.
870
Configuration
This plugin is configured as a Server handler. The plugin can be configured in easy way
by changing parameters:
true to turn
enabled on, false boolean true
(default) is
turned off
The SMTP
profile.<name>.mail.smtp.host
host name string smtp.gmail.com
or ip-
address
profile.<name>.mail.smtp.port
The SMTP number 587
port
profile.<name>.mail.smtp.auth
Authenticate boolean true
in SMTP
profile.<name>.mail.smtp.user
The SMTP string [email protected]
username
The
profile.<name>.mail.from
source's string [email protected]
email
address
The date
format to
use, default yyyy-MM-dd
profile.<name>.mail.date.format
is "yyyy- string HH:mm:ss
MM-dd
HH:mm:ss"
871
<parameter name="profile.default.mail.smtp.starttls.enable" value="true" />
<parameter name="profile.default.mail.from" value="[email protected]" />
<parameter name="profile.default.mail.smtp.user" value="[email protected]" />
<parameter name="profile.default.mail.smtp.password" value="mypassword" />
<parameter name="profile.default.mail.date.format" value="yyyy-MM-dd HH:mm:ss" />
</parameters>
</handler>
872
Usage
The message is managed as a map of properties containing all the fields those are part
of the message.
to :
from source email No "[email protected]", 1.7
address "[email protected]"
destination to :
to addresses Yes "[email protected]", 1.2.0
separated by
commas "[email protected]"
The subject of
the message.
Pass a
java.util.Date
object or a string No, if not
formatted specified
date following the current date : "2012-09-25 1.2.0
rules specified in 13:20:00"
"mail.date.format" date is
configuration assumed
parameter or
"yyyy-MM-dd
HH:mm:ss" is
taken
873
From Server-Side Functions
The Email plugin install a new variable in the server-side function's context: "mail".
"profile" attribute is the profile name in configuration.
mail.send({
profile : "default",
to: "[email protected]",
cc: "[email protected]",
bcc: "[email protected]",
subject: "The EMail plugin works",
message : "Sending email from OrientDB Server is so powerful to build real web applications!"
});
On Nashorn (>= Java8) the mapping of JSON to Map is not implicit. Use this:
874
From Java
plugin.send(message);
875
JMX plugin
Java class implementation:
com.orientechnologies.orient.server.handler.OJMXPlugin
876
Introduction
Expose the OrientDB server configuration through JMX protocol. This task is configured
as a Server handler. The task can be configured in easy way by changing parameters:
<!-- JMX SERVER, TO TURN ON SET THE 'ENABLED' PARAMETER TO 'true' -->
<handler class="com.orientechnologies.orient.server.handler.OJMXPlugin">
<parameters>
<parameter name="enabled" value="false" />
<parameter name="profilerManaged" value="true" />
</parameters>
</handler>
877
Studio Home page
Studio is a web interface for the administration of OrientDB that comes in bundle with the
OrientDB distribution.
If you run OrientDB in your machine the web interface can be accessed via the URL:
http://localhost:2480
878
Connect to an existing database
To Login, select a database from the databases list and use any database user. By
default reader/reader can read records from the database, writer/writer can read,
create, update and delete records. admin/admin has all rights.
879
Drop an existing database
Select a database from the databases list and click the trash icon. Studio will open a
confirmation popup where you have to insert
Server User
Server Password
and then click the "Drop database" button. You can find the server credentials in the
$ORIENTDB_HOME/config/orientdb-server-config.xml file:
<users>
<user name="root" password="pwd" resources="*" />
</users>
880
Create a new database
To create a new database, click the "New DB" button from the Home Page
Database name
Database type (Document/Graph)
Storage type (plocal/memory)
Server user
Server password
<users>
<user name="root" password="pwd" resources="*" />
</users>
881
Import a public database
Studio 2.0 allows you to import databases from a public repository. These databases
contains public data and bookmarked queries that will allow you to start playing with
OrientDB and OrientDB SQL. The classic bundle database 'GratefulDeadConcerts' will
be moved to this public repository.
To install a public database, you will need the Server Credentials. Then, click the
download button of the database that you are interested in. Then Studio will download
and install in to your $ORIENTDB_HOME/databases directory. Once finished, Studio will
automatically login to the newly installed database.
882
Execute a query
Studio supports auto recognition of the language you're using: between those supported:
SQL and Gremlin. While writing, use the auto-complete feature by pressing Ctrl + Space.
Ctrl + Return to execute the query or just click the Run button
Ctrl/Cmd + Z to undo changes
Ctrl/Cmd + Shift + Z to redo changes
Ctrl/Cmd + F to search in the editor
Ctrl/Cmd + / to toggle a comment
Note: If you have multiple queries in the editor, you can select a single query with
text selection and execute it with Ctrl + Return or the Run button
By clicking any @rid value in the result set, you will go into document edit mode if the
record is a Document, otherwise you will go into vertex edit.
You can bookmark your queries by clicking the star icon in the results set or in the editor.
To browse bookmarked queries, click the Bookmarks button. Studio will open the
bookmarks list on the left, where you can edit/delete or rerun queries.
883
Studio saves the executed queries in the Local Storage of the browser, in the query
settings, you can configure how many queries studio will keep in history. You can also
search a previously executed query, delete all the queries from the history or delete a
single query.
From Studio 2.0, you can send the result set of a query to the Graph Editor by clicking to
the circle icon in the result set actions. This allows you to visualize your data graphically.
884
Look at the JSON output
Studio speaks with the OrientDB Server using HTTP/RESt+JSON protocol. To see the
output in JSON format, press the RAW tab.
885
Edit Document
886
Edit Vertex
887
Schema Manager
OrientDB can work in schema-less mode, schema mode or a mix of both. Here we'll
discuss the schema mode. To know more about schema in OrientDB go here
888
Create a new Class
To create a new Class, just click the New Class button. Some information is required to
create the new class.
Name
SuperClass
Alias (Optional)
Abstract
889
View all indexes
When you want to have an overview of all indexes created in your database, just click
the All indexes button in the Schema UI. This will provide quick access to some
information about indexes (name, type, properties, etc) and you can drop or rebuild them
from here.
890
Class Edit
891
Property
Add Property
892
Indexes
893
Graph Editor
Since Studio 2.0 we have a new brand graph editor. Not only you can visualize your data
in a graph way but you can also interact with the graph and modify it.
To populate the graph area just type a query in the query editor or use the functionality
Send To Graph from the Browse UI
Add Vertices
Save the Graph Rendering Configuration
Clear the Graph Rendering Canvas
Delete Vertices
Remove Vertices from Canvas
Edit Vertices
Inspect Vertices
Change the Rendering Configuration of Vertices
Navigating Relationships
Create Edges between Vertices
Delete Edges between Vertices
Inspect Edges
Edit Edges
894
Add Vertices
To add a new Vertex in your Graph Database and in the Graph Canvas area you have to
press the button Add Vertex. This operation is done in two steps.
The first step you have to choose the class for the new Vertex and then click Next
In the second step you have to insert the fields values of the new vertex, you can also
add custom fields as OrientDB supports Schema-Less mode. To make the new vertex
persistent click to Save changes and the vertex will be saved into the database and
added to the canvas area
895
Delete Vertices
Open the circular menu by clicking on the Vertex that you want to delete, open the sub-
menu by passing hover the mouse to the menu entry more (...) and then click the trash
icon.
896
Remove Vertices from Canvas
Open the circular menu , open the sub-menu by passing hover the mouse to the menu
entry more (...) and then click the eraser icon.
897
Edit Vertices
Open the circular menu and then click to the edit icon, Studio will open a popup where
you can edit the vertex properties.
898
Inspect Vertices
If you want to take a quick look to the Vertex property, click to the eye icon.
899
Change the Rendering Configuration of
Vertices
900
Navigating Relationships
Inspect Edges
Edit Edges
901
Functions
902
Security
Studio 2.0 includes the new Security Management where you can manage Users and
Roles in a graphical way. For detailed information about Security in OrientDB, visit here
903
Users
Here you can manage the database users:
Search Users
Add Users
Delete Users
Edit User: roles can be edited in-line, for name, status and password click the Edit
button
Add Users
To add a new User, click the Add User button, complete the information for the new
user (name, password, status, roles) and then save to add the new user to the database.
904
Roles
Here you can manage the database roles:
Search Role
Add Role
Delete Role
Edit Role
Add Role
To add a new User, click the Add Role button, complete the information for the new role
(name, parent role, mode) and then save to add the new role to the database.
905
Add Rule to a Role
To add a new security rule for the selected role, click the Add Rule button. This will ask
you the string of the resource that you want to secure. For a list of available resources,
visit the official documentation here
Then you can configure the CRUD permissions on the newly created resource.
906
Database Management
Structure
907
Configuration
908
Export
909
Server Management
Connections
910
Configuration
911
Storage
912
Console Tool
The OrientDB Console is a Java Application made to work against OrientDB databases
and Server instances.
913
Interactive mode
This is the default mode. Just launch the console by executing the script bin/console.sh
(or bin/console.bat in MS Windows systems). Assure to have execution permission on
it.
orientdb>
914
Batch mode
To execute commands in batch mode run the bin/console.sh (or bin/console.bat in
MS Windows systems) script passing all the commands separated with semicolon ";".
Example:
Or call the console script passing the name of the file in text format containing the list of
commands to execute. Commands must be separated with semicolon ";". Example:
In batch mode you can ignore errors to let the script to continue the execution by setting
the "ignoreErrors" variable to true:
915
Enable echo
When you run console commands in pipeline, you could need to display them. Enable
"echo" of commands by setting it as property at the beginning:
916
Console commands
To know all the commands supported by the Orient console open it and type help or ?.
Command Description
alter
database Changes the database attributes
create
class Creates a new class
create
cluster Creates a new record cluster
create
Creates a new database
database
917
create Create a new index
index
drop
Drop a property from a schema class
property
export
database Exports a database
918
get Returns the value of a property
Display
pwd current
path
rebuild
index Rebuild an index
reload
schema Reloads the schema
show
holes Displays the database's holes
919
traverse Traverse a graph of records
truncate Remove all the records of a class (by truncating all the
class underlying configured clusters)
920
Extend the console with custom command
Edit the OConsoleDatabaseApp class and add a new method. There's an auto
discovering system that put the new method between the available commands. To
provide a description of the command use the annotations (look below). The command
name must follow the Java code convention where to separate works just use the
Camel-case.
So, for example, if you want to create the brand new "move cluster" command:
If you type:
orientdb> help
921
Console - BACKUP
Executes a complete backup against the currently opened database. The backup file is
compressed using the ZIP algorithm. To restore the database use the Restore Database
command. Backup is much faster than Export Database. Look also to Export Database
and Import Database commands. Backup can be done automatically by enabling the
Automatic-Backup Server plugin.
NOTE: Backup of remote databases is not supported in Community Edition, but only in
Enterprise Edition. If you're using the Enterprise Edition look at Remote Backup.
922
Syntax
Where:
923
Example
924
Backup API
Backup can be executed in Java and any language on top of the JVM by using the
method backup() against the database instance:
Where:
Example:
925
See also
Restore Database
Export Database
Import Database
Console-Commands
ODatabaseExport Java class
926
Console - BEGIN
OrientDB supports Transactions. To begin a new transaction use the begin command.
Once a transaction is begun to make persistent the changes you have to call the commit
command. To abort the changes call rollback command instead.
927
Syntax
begin
928
See also
Transactions
Console-Command-Commit
Console-Command-Rollback
Console-Commands
929
Example
orientdb> begin
Transaction 1 is running
orientdb> begin
Error: an active transaction is currently open (id=1). Commit or rollback before starting a new one.
---+---------+--------------------
#| RID |name
---+---------+--------------------
0| #9:-2|tx test
---+---------+--------------------
Until the commit all the new records will have a temporary RID with negative numbers.
930
Console - BROWSE CLASS
This command displays all the records of a class.
931
Syntax
Where:
932
Example
---+--------+-------------------
#| REC ID |NAME
---+--------+-------------------
0| -6:0|Rome
1| -6:1|London
2| -6:2|Honolulu
---+--------+-------------------
This is a command of the Orient console. To know all the commands go to Console-
Commands.
933
Console - BROWSE CLUSTER
This command displays all the records of a cluster.
934
Syntax
Where:
935
Example
---+--------+-------------------
#| REC ID |NAME
---+--------+-------------------
0| -6:0|Rome
1| -6:1|London
2| -6:2|Honolulu
---+--------+-------------------
This is a command of the Orient console. To know all the commands go to Console-
Commands.
936
Console - CLASSES
Displays all the classes configured in the current database.
937
Syntax
classes
938
Example
> classes
CLASSES:
--------------------+------+------------------------------------------+-----------+
NAME | ID | CLUSTERS | ELEMENTS |
--------------------+------+------------------------------------------+-----------+
Person | 0| person | 7 |
Animal | 1| animal | 5 |
AnimalRace | 2| AnimalRace | 0 |
AnimalType | 3| AnimalType | 1 |
OrderItem | 4| OrderItem | 0 |
Order | 5| Order | 0 |
City | 6| City | 3 |
--------------------+------+------------------------------------------+-----------+
TOTAL 16 |
----------------------------------------------------------------------------------+
This is a command of the Orient console. To know all the commands go to Console-
Commands.
939
Console - CLUSTERS
Displays all the clusters configured in the current database.
940
Syntax
clusters
941
Example
> clusters
CLUSTERS:
--------------------+------+--------------------+-----------+
NAME | ID | TYPE | ELEMENTS |
--------------------+------+--------------------+-----------+
metadata | 0|Physical | 11 |
index | 1|Physical | 0 |
default | 2|Physical | 779 |
csv | 3|Physical | 1000 |
binary | 4|Physical | 1001 |
person | 5|Physical | 7 |
animal | 6|Physical | 5 |
animalrace | -2|Logical | 0 |
animaltype | -3|Logical | 1 |
orderitem | -4|Logical | 0 |
order | -5|Logical | 0 |
city | -6|Logical | 3 |
--------------------+------+--------------------+-----------+
TOTAL 2807 |
------------------------------------------------------------+
942
See also
To create a new cluster in the current database use the command create cluster.
This is a command of the Orient console. To know all the commands go to Console-
Commands.
943
Console - COMMIT
OrientDB supports Transactions. To begin a new transaction use the begin command.
Once a transaction is begun to make persistent the changes you have to call the commit
command. To abort the changes call rollback command instead.
944
Syntax
commit
945
See also
Transactions
Console Command Begin
Console Command Rollback
Console Commands
946
Example
orientdb> begin
Transaction 2 is running
orientdb> begin
Error: an active transaction is currently open (id=2). Commit or rollback before starting a new one.
orientdb> commit
Transaction 2 has been committed in 4ms
---+---------+--------------------
#| RID |name
---+---------+--------------------
0| #9:1107|tx test
---+---------+--------------------
orientdb>
Until the commit all the new records will have a temporary RID with negative numbers.
947
Console - CONFIG
Displays the configuration where the opened database is located (local or remote)
948
Syntax
config
949
Example
> config
950
See also
To change a configuration value use the config set.
This is a command of the Orient console. To know all the commands go to Console-
Commands.
951
Console - CONFIG GET
Returns the value of the requested configuration value.
952
Syntax
Where:
953
Example
954
See also
To display the entire configuration use the config.
This is a command of the Orient console. To know all the commands go to Console-
Commands.
955
Console - CONFIG SET
Changes the value of a property.
956
Syntax
Where:
957
Example
958
See also
To know all the configuration values use the config. To read a configuration value use
the config get.
This is a command of the Orient console. To know all the commands go to Console-
Commands.
959
Console - CONNECT
Opens a database using a URL.
960
Syntax
Where:
961
Example: connect to a local database
To connect to a local database loading it directly into the console.
Example:
962
Example: Connect to a remote database
To connect to a local or remote database by using a Orient Server.
Example:
This is a command of the Orient console. To know all the commands go to Console-
Commands.
963
Console - CREATE CLUSTER
Creates a new cluster in the current database. The cluster can be "physical" or
"memory".
964
Syntax
Where:
965
Example
966
See also
To display all the cluster configured in the current database use the command clusters.
This is a command of the Orient console. To know all the commands go to Console-
Commands.
967
Console - CREATE DATABASE
Creates a new database.
968
Syntax
Where:
database-url The url of the database to create in the format ' <mode>:<path> '
user on remote database is the Server's administrator name
password on remote database is the Server's administrator password
storage-type The type of the storage between 'plocal' for disk-based database and
'memory' for in memory only database. Look at Storage types.
db-type Optional, is the database type between "graph" (the default) and
"document"
969
See also
Console Command Drop Database
SQL Alter Database
970
Example: create a local database
971
Example: create a remote database
972
Create a static database into the server
configuration
To create a static database to use it from the server look at: Server pre-configured
storages.
This is a command of the Orient console. To know all the commands go to Console-
Commands.
973
Console - CREATE INDEX
The SQL Create Index command creates an index on a property defined in the schema.
974
Syntax
Where:
975
Examples
This is a command of the Orient console. To know all the commands go to Console-
Commands.
976
Console - CREATE LINK
The Create Link command creates links between two or more records of type
Document. This is very useful when you're importing data from a Relational database. In
facts in the Relational world relationships are resolved as foreign keys.
Consider this example where the class "Post" has a relationship 1-N to "Comment":
Table Post
+----+----------------+
| Id | Title |
+----+----------------+
| 10 | NoSQL movement |
| 20 | New OrientDB |
+----+----------------+
Table Comment
+----+--------+--------------+
| Id | PostId | Text |
+----+--------+--------------+
| 0 | 10 | First |
| 1 | 10 | Second |
| 21 | 10 | Another |
| 41 | 20 | First again |
| 82 | 20 | Second Again |
+----+--------+--------------+
Using OrientDB, instead, you have direct relationship as in your object model. So the
navigation is from Post to Comment and not viceversa as for Relational model. For this
reason you need to create a link as INVERSE.
977
Syntax
Where:
link-name is the name of the property for the link. If not expressed will be
overwritten the destination-property field
source-class, is the source class
source-property, is the source property
destination-class, is the destination class
destination-property, is the destination property
978
Examples
CREATE LINK comments FROM comments.!PostId To posts.Id INVERSE
To know more about other SQL commands look at SQL SQL commands.
This is a command of the Orient console. To know all the commands go to Console-
Commands.
979
Console - CREATE PROPERTY
The SQL Create Property command creates a new property in the schema. You need
to create the class before.
980
Syntax
Where:
981
string
binary
embedded
link
byte
982
Examples
Create the property 'name' of type 'STRING' in class 'User':
Create a list of Strings as property 'tags' of type 'EMBEDDEDLIST' in class 'Profile'. The
linked type is 'STRING':
Create the property 'friends' of type 'EMBEDDEDMAP' in class 'Profile'. The linked class
is profile itself (circular references):
This is a command of the Orient console. To know all the commands go to Console-
Commands.
983
Console - DECLARE INTENT
Declares an intent on current database. Intents are a way to tell to OrientDB what you're
going to do.
984
Syntax
Where:
intent-name The name of the intent. "null" means remove the current intent.
Supported ones are:
massiveinsert
massiveread
985
Example
This is a command of the Orient console. To know all the commands go to Console-
Commands.
986
987
Console - DICTIONARY GET
Displays the value of the requested key loaded from the database dictionary.
988
Syntax
Where:
989
Example
To know all the keys stored in the database dictionary use the dictionary keys command.
This is a command of the Orient console. To know all the commands go to Console-
Commands.
990
Console - DICTIONARY KEYS
Displays all the keys stored in the database dictionary.
991
Syntax
dictionary keys
992
Example
Found 4 keys:
#0: key-148
#1: key-147
#2: key-146
#3: key-145
This is a command of the Orient console. To know all the commands go to Console-
Commands.
993
Console - DISCTIONARY PUT
Associates in the database dictionary a record to a key to be found later using a
dictionary get command.
994
Syntax
Where:
995
Example
To know all the keys stored in the database dictionary use the dictionary keys command.
This is a command of the Orient console. To know all the commands go to Console-
Commands.
996
Console - DICTIONARY REMOVE
Removes the association from the database dictionary.
997
Syntax
Where:
998
Example
To know all the keys stored in the database dictionary use the dictionary keys command.
This is a command of the Orient console. To know all the commands go to Console-
Commands.
999
Console - DISCONNECT
Closes the current opened database.
1000
Syntax
disconnect
1001
Example
> disconnect
This is a command of the Orient console. To know all the commands go to Console-
Commands.
1002
Console - DISPLAYS RECORD
Displays the details of the record of the last result set returned. This command needs the
relative position of the record in the result set.
1003
Syntax
display [<number>](<number>.md)record])
Where:
1004
Example
---+--------+--------------------+--------------------+--------------------+--------------------+--------
#| REC ID |PARENT |CHILDREN |NAME |SURNAME |CITY
---+--------+--------------------+--------------------+--------------------+--------------------+--------
0| 5:0|null |null |Giuseppe |Garibaldi |-
1| 5:1|5:0 |null |Napoleone |Bonaparte |-
2| 5:2|5:3 |null |Nicholas |Churcill |-
3| 5:3|5:2 |null |Winston |Churcill |-
4| 5:4|null |[2] |Barack |Obama |-
5| 5:5|5:4 |null |Malia Ann |Obama |
6| 5:6|5:4 |null |Natasha |Obama |
---+--------+--------------------+--------------------+--------------------+--------------------+--------
7 item(s) found. Query executed in 0.038 sec(s).
This is a command of the Orient console. To know all the commands go to Console-
Commands.
1005
Console - DROP CLUSTER
The Drop Cluster command definitely deletes a cluster. This will delete the cluster, all
its records and will clear all caches. NOTE: Unless you've made backups there is no way
to restore a deleted cluster.
1006
Syntax
Where:
1007
Examples
Delete the current local database:
This is a command of the Orient console. To know all the commands go to Console-
Commands.
1008
Console - DROP DATABASE
The Drop Database command definitely deletes a database. If a database is open and
no database name is used, then the current database will be deleted. NOTE: Unless
you've made backups there is no way to restore a deleted database.
1009
Syntax
For database opened using "local" protocol:
DROP DATABASE
To remove a database hosted in a remote OrientDB Server you need the credential to
do it at the target OrientDB server:
Where:
1010
See also
Console Command Create Database
SQL Alter Database
1011
Examples
Delete the current local database:
DROP DATABASE
This is a command of the Orient console. To know all the commands go to Console-
Commands.
1012
Console - EXPORT
Exports the current opened database to a file. The exported file is in JSON format using
the Export-Format. By default the file is compressed using the GZIP algorithm. The
Export/Import commands allow to migrate the database between different releases of
OrientDB without loosing data. If you receive an error about the database version, export
the database using the same version of OrientDB that has generated the database.
Export doesn't lock your database, but browses it. This means that concurrent operation
can be executed during the export, but the exported database couldn't be the exact
replica when you issued the command because concurrent updates could occurs. If you
need a snapshot of database at a point in a time, please use Backup.
Once exported, use the Import to restore it. The database will be imported and will be
ready to be used. Look also to Backup Database and Restore Database commands.
1013
Syntax
By default the export command exports the full database, but there are some flags to
disable some parts.
Where:
1014
-compressionLevel set the compression level between 0 (=no compression) and 9
(maximum compression). Default is 1 (since 1.7.6)
-compressionBuffer Set the buffer size in bytes used by compression. By default
is 16Kb (since 1.7.6)
1015
Examples
1016
Export API
Export command can be used in Java and any language on top of the JVM by using the
class ODatabaseExport. Example:
1017
See also
Export File Format
Import Database
Backup Database
Restore Database
Console Commands
ODatabaseExport Java class
1018
Console - EXPORT RECORD
This command exports the current record in the format requested. The format must be
between the supported ones. In case of error the supported format list will be displayed.
1019
Syntax
1020
Example
This is a command of the Orient console. To know all the commands go to Console-
Commands.
1021
Console - FREEZE DATABASE
Flushes all cached content to the disk storage and allows to perform only read
commands. Database will be "frozen" till release database command will not been
executed.
This command requires presence of server administration rights and can be executed
only on remote DBs. If you would like to freeze/release local DB use methods
ODatabase.freeze() and ODatabase.release() directly from OrientDB API.
This command is very useful in case you would like to do "live" database backups. You
can "freeze" database, do file system snapshot, "release" database, copy snapshot
anywhere you want. Using such approach you can perform backup in short term.
1022
Syntax
FREEZE DATABASE
1023
See also
release database, to release the frozen database
SQL commands
Console-Commands
1024
Examples
Freezes the current database:
FREEZE DATABASE
1025
Console - GET
Returns the value of the requested property
1026
Syntax
get <property-name>
Where:
1027
Example
limit = 20
1028
See also
To know all the properties setted use the properties.
This is a command of the Orient console. To know all the commands go to Console-
Commands.
1029
Console - GRANT
The SQL Grant command changes the permission of a role granting the access to one
or more resources.
1030
Syntax
Where:
1031
Examples
Grant the permission to update any records in cluster Account to the role "backoffice".
This is a command of the Orient console. To know all the commands go to Console-
Commands.
1032
Console - IMPORT
Imports a database to the current one opened. The input file is in JSON format using the
Export-Format generated by Console Command Export tool. By default the file is
compressed using the GZIP algorithm. The Export/Import commands allow to migrate
between engine releases without loosing data. Use the Export command to generate the
JSON file to import. Look also to Backup Database and Restore Database commands.
1033
Syntax
Where:
1034
See also
Export File Format
Export Database
Backup Database
Restore Database
Console-Commands
ODatabaseImport Java class
1035
Example
1036
Troubleshooting
If during the importing you experience that "Imported cluster 'XXX' has id=6 different
from the original: 5" means that your database was created with an ancient version of
OrientDB:
- Creating cluster 'company'...Error on database import happened just before line 16, column 52
com.orientechnologies.orient.core.exception.OConfigurationException: Imported cluster 'company' has id=6
at com.orientechnologies.orient.core.db.tool.ODatabaseImport.importClusters(ODatabaseImport.java:
at com.orientechnologies.orient.core.db.tool.ODatabaseImport.importDatabase(ODatabaseImport.java:
To fix it just drop the ORIDs class before to import the database:
1037
Import API
Import command can be used in Java and any language on top of the JVM by using the
class ODatabaseImport. Example:
1038
Console - INFO
Displays all the information about the current database.
1039
Syntax
info
1040
Example
CLASSES:
--------------------+------+------------------------------------------+-----------+
NAME | ID | CLUSTERS | ELEMENTS |
--------------------+------+------------------------------------------+-----------+
Person | 0| person | 7 |
Animal | 1| animal | 5 |
AnimalRace | 2| AnimalRace | 0 |
AnimalType | 3| AnimalType | 1 |
OrderItem | 4| OrderItem | 0 |
Order | 5| Order | 0 |
City | 6| City | 3 |
--------------------+------+------------------------------------------+-----------+
TOTAL 16 |
----------------------------------------------------------------------------------+
This is a command of the Orient console. To know all the commands go to Console-
Commands.
1041
Console - INFO CLASS
Displays all the information about the selected class
1042
Syntax
1043
Example
This is a command of the Orient console. To know all the commands go to Console-
Commands.
1044
Console - insert
Insert
Insert a new record into the current database. Remember that Orient can work also in
schema-less mode, so you can create any field at-the-fly.
1045
Syntax
1046
Example
nsert a new record with name 'Jay' and surname 'Miner':
To know more about the SQL syntax used in Orient take a look to: SQL-Query.
This is a command of the Orient console. To know all the commands go to Console-
Commands.
1047
Console - LOAD RECORD
Loads a record by its record-id from the current database.
1048
Syntax
Where:
record-id The unique Record Id of the record to load. If you don't have the Record Id
execute a query first
1049
Example
--------------------------------------------------
Class: Person id: #5:5 v.0
--------------------------------------------------
parent : Person@5:4{parent:null,children:[Person@5:5, Person@5:6],name:Barack,surname:Obama
children : null
name : Malia Ann
surname : Obama
city : null
--------------------------------------------------
This is a command of the Orient console. To know all the commands go to Console-
Commands.
1050
Console - PROFILER
Controls the Profiler.
1051
Syntax
profiler on|off|dump|reset
Where:
1052
Example
orientdb> profiler on
orientdb> profiler dump
This is a command of the Orient console. To know all the commands go to Console-
Commands.
1053
Console - PROPERTIES
Returns all the properties setted.
1054
Syntax
properties
1055
Example
> properties
PROPERTIES:
+---------------------+----------------------+
| NAME | VALUE |
+---------------------+----------------------+
| limit = 20 |
+---------------------+----------------------+
1056
See also
To change a property value use the set.
This is a command of the Orient console. To know all the commands go to Console-
Commands.
1057
Console - RELEASE DATABASE
Switches database from "frozen" state (where only read operations are allowed) to
normal mode.
This command is very usefull in case you would like to do "live" database backups. You
can "freeze" database, do file system snapshot, "release" database, copy snapshot
anywhere you want. Using such approach you can perform backup in short term.
1058
Syntax
RELEASE DATABASE
1059
See also
Freeze Database, to freeze a database
SQL commands
Console-Commands
1060
Examples
Release the current database:
RELEASE DATABASE
1061
Console - RELOAD RECORD
Reloads a record by its record-id from the current database ignoring the cache. This is
useful when external applications change the record and you need to see latest update.
1062
Syntax
Where:
record-id The unique Record Id of the record to reload. If you don't have the Record
Id execute a query first
1063
Example
--------------------------------------------------
Class: Person id: 5:5 v.0
--------------------------------------------------
parent : Person@5:4{parent:null,children:[Person@5:5, Person@5:6],name:Barack,surname:Obama
children : null
name : Malia Ann
surname : Obama
city : null
--------------------------------------------------
This is a command of the Orient console. To know all the commands go to Console-
Commands.
1064
Console - RESTORE
Executes a restore of current opened database. The backup file is created using the
Backup Database command. Look also to Export Database and Import Database
commands.
1065
Syntax
Where:
1066
Example
1067
Restore API
Restore can be executed in Java and any language on top of the JVM by using the
method restore() against the database instance:
Where:
in: InputStream used to read the backup content. Use a FileInputStream to read the
backup content from disk
options: Backup options as Map object
callable: Callback to execute when the database is locked iListener: Listener called
for backup messages
compressionLevel: ZIP Compression level between 0 (no compression) and 9
(maximum). The bigger is the compression, the smaller will be the final backup
content, but will consume more CPU and time to execute
bufferSize: Buffer size in bytes, the bigger is the buffer, the more efficient will be
the compression
Example:
1068
See also
Backup Database
Export Database
Import Database
Console-Commands
1069
Console - REVOKE
The SQL Revoke command changes the permission of a role revoking the access to
one or more resources.
1070
Syntax
Where:
1071
Examples
Revoke the permission to delete any records in any cluster to the role "backoffice".
This is a command of the Orient console. To know all the commands go to Console-
Commands.
1072
Console - ROLLBACK
OrientDB supports Transactions. Once a transaction is begun you can abort changes in
transactions by using the rollback command.
1073
Syntax
rollback
1074
See also
Transactions
Console Command Commit
Console Command Rollback
Console Commands
1075
Example
orientdb> begin
Transaction 1 is running
orientdb> begin
Error: an active transaction is currently open (id=1). Commit or rollback before starting a new one.
---+---------+--------------------
#| RID |name
---+---------+--------------------
0| #9:-2|tx test
---+---------+--------------------
orientdb> rollback
Transaction 1 has been rollbacked in 4ms
1076
Console - SET
Changes the value of a property.
1077
Syntax
Where:
1078
Example
limit = 100
1079
See also
To know all the properties setted use the properties. To read the property value use the
get.
This is a command of the Orient console. To know all the commands go to Console-
Commands.
1080
Operations
This is the main page for DBA and DevOps.
1081
Tuning
Performance Tuning
1082
In & Out
ETL (Extract-Transform-Load)
Distributed Architecture
Backup & Restore
Export & Import
1083
Install
Install as Service on Unix/Linux
Install as Service on Windows
1084
Installation
OrientDB is available in two editions:
Community Edition This edition is released as an open source project under the
Apache 2 license. This license allows unrestricted free usage for both open source
and commercial projects.
Enterprise Edition OrientDB Enterprise edition is commercial software built on top
of the Community Edition. Enterprise is developed by the same team that developed
the OrientDB engine. It serves as an extension of the Community Edition by
providing Enterprise features such as:
Query Profiler
Distributed Clustering configuration
Metrics Recording
Live Monitoring with configurable Alerts
Prerequisites
Both editions run on every operating system that has an implementation of the Java
Virtual Machine (JVM), for example:
This means the only requirement for using OrientDB is to have Java version 1.6 or
higher installed.
Download Binaries
The easiest and fastest way to start using OrientDB is to download binaries from the
Official OrientDB Download Page.
1085
Alternatively, you can clone the Community Edition project from GitHub and compile it.
This allows you access to the latest functionality without waiting for a distribution binary.
To build the Community Edition, you must first install the Apache Ant tool and follow
these steps:
After the compilation, all the binaries are placed under the ../releases directory.
Change Permissions
The Mac OS X, Linux, and UNIX based operating systems typically require you to
change the permissions to execute scripts. The following command will apply the
necessary permissions for these scripts in the bin directory of the OrientDB distribution:
Other Resources
To learn more about how to install OrientDB on specific environments, please refer to
the guides below:
1086
Install with Docker
Install on Linux Ubuntu
Install on JBoss AS
Install on GlassFish
Install on Ubuntu 12.04 VPS (DigitalOcean)
Install on Vagrant
1087
orientdb-docker
OrientDB is the first Multi-Model Open Source NoSQL DBMS that combines the power
of graphs and the flexibility of documents into one scalable, high-performance
operational database.
1088
Building the image on your own
1. Checkout this project to a local folder cding to it
3. Push it to your Docker Hub repository (it will ask for your login credentials):
All examples below are using my own image nesrait/orientdb-2.0. If you build your own
image please find/replace "nesrait" with your Docker Hub user.
1089
Running orientdb
To run the image, run:
The docker image contains a unconfigured orientdb installation and for running it you
need to provide your own config folder from which OrientDB will read its startup settings.
The same applies for the databases folder which if local to the running container would
go away as soon as it died/you killed it.
The backup folder only needs to be mapped if you activate that setting on your OrientDB
configuration file.
1090
Persistent distributed storage using BTSync
If you're not running OrientDB in a distributed configuration you need to take special care
to backup your database (in case your host goes down).
Below is a simple, yet hackish, way to do this: using BTSync data containers to
propagate the OrientDB config, LIVE databases and backup folders to remote
location(s). Note: don't trust the remote copy of the LIVE database folder unless the
server is down and it has correctly flushed changes to disk.
1. Create BTSync shared folders on any remote location for the various folder you
want to replicate
1.3. backup: the place where OrientDB will store the zipped backups (if you activate
the backup in the configuration file)
3. Launch BTSync data containers for each of the synched folder you created giving
them proper names:
4. Wait until all files have magically appeared inside your BTSync data volumes:
1091
--volumes-from orientdb_config \
--volumes-from orientdb_databases \
--volumes-from orientdb_backup \
-p 2424 -p 2480 \
nesrait/orientdb-2.0
1092
OrientDB distributed
If you're running OrientDB distributed* you won't have the problem of losing the contents
of your databases folder since they are already replicated to the other OrientDB nodes.
From the setup above simply leave out the "--volumes-from orientdb_databases"
argument and OrientDB will use the container storage to hold your databases' files.
*note: some extra work might be needed to correctly setup hazelcast running inside
docker containers (see this discussion).
1093
Ad-hoc backups
With OrientDB 2.0 we can now create ad-hoc backups by taking advantage of the new
backup.sh script:
Either way, when the backup completes you will have the backup file located outside of
the OrientDB container and read for safekeeping.
Note: I haven't tried the non-blocking backup (type=lvm) yet but found this discussion
about a docker LVM dependency issue.
1094
Running the orientdb console
1095
Install as Service on Unix/Linux
OrientDB is shipped with the script $ORIENTDB_HOME/bin/orientdb.sh that can be
used to run OrientDB like a daemon. It supports the following parameters:
start
stop
status
Before to install it as service open the file and change the following lines:
ORIENTDB_DIR="YOUR_ORIENTDB_INSTALLATION_PATH"
ORIENTDB_USER="USER_YOU_WANT_ORIENTDB_RUN_WITH"
`
By setting the installation path and the user as stated, save the script, and deploy like
other scripts for the other daemon.
Different Unix, Linux and MacOSX distribution uses different ways to manage the
start/stop process at the system bootstrap/shutdown.
1096
Other resources
To learn more about how to install OrientDB on specific environment please follow the
guide below:
1097
Install as Service on Windows
OrientDB is a Java server application. As most server applications, they have to perform
several tasks before being able to shut down the Virtual Machine process hence they
need a portable way to be notified of the imminent Virtual Machine shutdown. At the
moment, the only way to properly shut down an OrientDB server instance (not
embedded) is to execute the shutdown.bat (or shutdown.sh) script shipped with the
OrientDB distribution but it's up to the user to take care of this. This implies that the
server instance isn't stopped correctly when the computer on which it is deployed is
shutted down without executing the above script.
1098
Apache Commons Daemon
Apache Commons Daemon is a set of applications and API enabling Java server
application to run as native non interactive server applications under Unix and Windows.
In Unix, server applications running in background are called daemons and are
controlled by the operating system with a set of specified signals. Under Windows such
programs are called services and are controlled by appropriate calls to specific functions
defined in the application binary. Although the ways of dealing with the problem are
different, in both cases the operating system can notify a server application of its
imminent shutdown, and the underlying application has the ability to perform certain
tasks before its process of execution is destroyed. Wrapping OrientDB as a Unix
daemon or as a Windows service enables the management of this server application
lifecycle through the mechanisms provided natively by both Unix and Windows operating
systems.
1099
Installation
This tutorial is focused on Windows so you have to download procrun. Procrun is a set
of applications that allow Windows users to wrap (mostly) Java applications (e.g.
Tomcat) as a Windows service. The service can be set to automatically start when the
machine boots and will continue to run with no user logged onto the machine.
commons-daemon-1.0.7-bin-windows
|
\---amd64
|
\---prunsrv.exe
|
\---ia64
|
\---prunsrv.exe
|
\---LICENCE.txt
|
\---NOTICE.txt
|
\---prunmgr.exe
|
\---prunsrv.exe
|
\---RELEASE-NOTES.txt
prunmgr is a GUI application for monitoring and configuring Windows services wrapped
with procrun. prunsrv is a service application for running applications as services. It can
convert any application (not just Java applications) to run as a service. The directory
amd64 contains a version of prunsrv for x86-64 machines while the directory ia64
contains a version of prunsrv for Itanium 64 machines.
Once you downloaded the applications, you have to put them in a folder under the
1100
OrientDB installation folder.
1101
Configuration
In this section, we will show how to wrap OrientDB GraphEd 1.0rc5 as a Windows
Service. In order to wrap OrientDB as a service, you have to execute a short script that
uses the prunsrv application to configure a Windows Service.
Before defining the Windows Service, you have to rename prunsrv and prunmgr
according to the name of the service. Both applications require the name of the service
to manage and monitor as parameter but you can avoid it by naming them with the name
of the service. In this case, rename them respectively OrientDBGraph and
OrientDBGraphw as OrientDBGraph is the name of the service that you are going to
configure with the script below. If you want to use a difference service name, you have to
rename both application respectively myservicename and myservicenamew (for
example, if you are wrapping OrientDB and the name of the service is OrientDB, you
could rename prunsrv as OrientDB and prunmgr as OrientDBw). After that, create the
file %ORIENTDB_HOME%\service\installService.bat with the content depicted below:
set CONFIG_FILE=%ORIENTDB_HOME%/config/orientdb-server-config.xml
set LOG_FILE=%ORIENTDB_HOME%/config/orientdb-server-log.properties
set LOG_CONSOLE_LEVEL=info
set LOG_FILE_LEVEL=fine
set WWW_PATH=%ORIENTDB_HOME%/www
set ORIENTDB_SETTINGS=-Dprofiler.enabled=true -Dcache.level1.enabled=false -Dcache.level2.strategy=1
set JAVA_OPTS_SCRIPT=-XX:+HeapDumpOnOutOfMemoryError
EXIT /B
:missingJVM
echo Insert the JVM DLL location
1102
goto printUsage
:missingOrientDBHome
echo Insert the OrientDB Home
goto printUsage
:printUsage
echo usage:
echo installService JVM_DLL_location OrientDB_Home
EXIT /B
The description
displayed in the
--Description Windows Services Custom
Management
Console
1103
to be called is the
main method
For a complete reference to all available parameters and arguments for prunsrv and
prunmgr, visit the Procrun page.
3. Execute the installService.bat specifying the jvm.dll location and the OrientDB
Home as full paths, for example typing in the shell > installService.bat "C:\Program
Files\Java\jdk1.6.0_26\jre\bin\server\jvm.dll" D:\orientdb-graphed-1.0rc5
4. Open the Windows Services Management Console - from the taskbar, click on
1104
Start, Control Panel, Administrative Tools and then Service - and check the
existance of a service with the same name specified as value of the --DisplayName
parameter (in this case OrientDB GraphEd 1.0rc5). You can also use
%ORIENTDB_HOME%\service\OrientDBGraphw.exe to manage and monitor the
OrientDBGraph service.
Other resources
To learn more about how to install OrientDB on specific environment please follow the
guide below:
1105
Performance Tuning
This guide contains the general tips to optimize your application that use the OrientDB.
Below you can find links for the specific guides different per database type used. Look at
the specific guides based on the database type you're using:
1106
Configuration
To tune OrientDB look at the Configuration settings.
1107
Platforms
Performance analysis on ZFS
1108
Memory settings
These settings are valid for both Server component and the JVM where is running the
Java application that use OrientDB in Embedded Mode, by using directly plocal.
The most important thing on tuning is assuring the memory settings are correct. What
can make the real difference is the right balancing between the heap and the virtual
memory used by Memory Mapping, specially on large datasets (GBs, TBs and more)
where the in memory cache structures count less than raw IO.
For example if you can assign maximum 8GB to the Java process, it's usually better
assigning small heap and large disk cache buffer (off-heap memory). So rather than:
NOTE: If the sum of maximum heap and disk cache buffer is too high, could cause the
OS to swap with huge slow down.
1109
JVM settings
JVM settings are encoded in server.sh (and server.bat) batch files. You can change
them to tune the JVM according to your usage and hw/sw settings. We found these
setting work well on most configurations:
OrientDB has an optimistic concurrency control system, but on very high concurrent
updates on the few records it could be more efficient locking records to avoid retries.
You could synchronize the access by yourself or by using the storage API. Note that this
works only with non-remote databases.
try{
((OStorageEmbedded)db.getStorage()).acquireWriteLock(record.getIdentity());
// DO SOMETHING
} finally {
((OStorageEmbedded)db.getStorage()).releaseWriteLock(record.getIdentity());
}
Reader threads:
try{
((OStorageEmbedded)db.getStorage()).acquireSharedLock(record.getIdentity());
// DO SOMETHING
} finally {
((OStorageEmbedded)db.getStorage()).releaseSharedLock(record.getIdentity());
}
1110
Remote connections
There are many ways to improve performance when you access to the database using
the remote connection.
Fetching strategy
When you work with a remote database you've to pay attention to the fetching strategy
used. By default OrientDB Client loads only the record contained in the result set. For
example if a query returns 100 elements, but then you cross these elements from the
client, then OrientDB client lazily loads the elements with one more network call to the
server foreach missed record.
By specifying a fetch plan when you execute a command you're telling to OrientDB to
prefetch the elements you know the client application will access. By specifying a
complete fetch plan you could receive the entire result in just one network call.
Each client, by default, uses only one network connection to talk with the server. Multiple
threads on the same client share the same network connection pool.
When you've multiple threads could be a bottleneck since a lot of time is spent on
waiting for a free network connection. This is the reason why is much important to
configure the network connection pool.
minPool, is the initial size of the connection pool. The default value is configured as
global parameters "client.channel.minPool" (see parameters)
maxPool, is the maximum size the connection pool can reach. The default value is
configured as global parameters "client.channel.maxPool" (see parameters)
At first connection the minPool is used to pre-create network connections against the
server. When a client thread is asking for a connection and all the pool is busy, then it
tries to create a new connection until maxPool is reached.
If all the pool connections are busy, then the client thread will wait for the first free
connection.
1111
Example of configuration by using database properties:
database.open("admin", "admin");
Enlarge timeouts
WARNING: Connection re-acquired transparently after XXXms and Y retries: no errors will be thrown at appl
means that probably default timeouts are too low and server side operation need more
time to complete. It's strongly suggested you enlarge your timeout only after tried to
enlarge the Network Connection Pool. The timeout parameters to tune are:
1112
Query
Use of indexes
The first improvement to speed up queries is to create Indexes against the fields used in
WHERE conditions. For example this query:
Browses the entire "profile" cluster looking for records that satisfy the conditions. The
solution is to create an index against the 'name' property with:
Moreover, because of partial match searching, this index will be used for optimizing
query like
1113
For deep understanding of query optimization look at the unit test:
http://code.google.com/p/orient/source/browse/trunk/tests/src/test/java/com/orientechnol
ogies/orient/test/database/auto/SQLSelectIndexReuseTest.java
Using @rid in where conditions slow down queries. Much better to use the RecordID as
target. Example:
Change this:
With this:
Also
With this:
1114
Massive Insertion
Intents suggest to OrientDB what you're going to do. In this case you're telling to
OrientDB that you're executing a massive insertion. OrientDB auto-reconfigure itself to
obtain the best performance. When done you can remove the intent just setting it to null.
Example:
db.declareIntent( null );
Disable Journal
In case of massive insertion, specially when this operation is made just once, you could
disable the journal (WAL) to improve insertion speed:
-storage.useWAL=false
This setting avoids to execute a sync at OS level when a page is flushed. Disabling this
setting will improve throughput on writes:
-Dstorage.wal.syncOnPageFlush=false
1115
Massive Updates
Updates generates "holes" at Storage level because rarely the new record fits perfectly
the size of the previous one. Holes are free spaces between data. Holes are recycled
but an excessive number of small holes it's the same as having a highly defragmented
File System: space is wasted (because small holes can't be easily recycled) and
performance degrades when the database growth.
Oversize
If you know you will update certain type of records, create a class for them and set the
Oversize (default is 0) to 2 or more.
By default the OGraphVertex class has an oversize value setted at 2. If you define your
own classes set this value at least at 2.
1116
Wise use of transactions
To obtain real linear performance with OrientDB you should avoid to use Transactions
as far as you can. In facts OrientDB keeps in memory all the changes until you flush it
with a commit. So the bottleneck is your Heap space and the management of local
transaction cache (implemented as a Map).
Transactions slow down massive inserts unless you're using a "remote" connection. In
that case it speeds up all the insertion because the client/server communication happens
only at commit time.
If you need to group operations to speed up remote execution in a logical transaction but
renouncing to the Transaction Log, just disable it by setting the property tx.useLog to
false.
or via API:
OGlobalConfiguration.TX_USE_LOG.setValue(false);
NOTE: Please note that in case of crash of the JVM the pending transaction OrientDB
could not be able to rollback it.
1117
Keep the database small
The smaller the database you have, the bigger are the number of records you can cache
in memory. Furthermore small database means faster seek in filesystem and minor
loading time from disk/network. In order to keep your database small follow the following
suggestions:
OrientDB is schema-less that means field names are stored with the values too. So if
you call a field "out" instead of "outVertices" you saves 8 characters, namely 8 bytes per
record. Applying this to millions of records allows you to save several Megabytes.
1118
Global Configuration
OrientDB can be configured in several ways. To know the current settings use the
console with the config command.
1119
Change settings
By command line
You can pass settings via command line when the JVM is launched. This is typically
stored inside server.sh (or server.bat on Windows):
By server configuration
...
<properties>
<entry name="cache.size" value="10000" />
<entry name="storage.keepOpen" value="true" />
</properties>
...
At run-time
OGlobalConfiguration.MVRBTREE_NODE_PAGE_SIZE.setValue(2048);
1120
Dump the configuration
To dump the OrientDB configuration you can set a parameter at JVM launch:
OGlobalConfiguration.dumpConfiguration(System.out);
1121
Parameters
To know more look at the Java enumeration: OGlobalConfiguration.java .
Environment
Memory
Storage
Def.Server Def.Server
Parameter Def.32bit Def.64bit 32bit 64bit
1122
storage.keepOpen true true true true
Cache
cache.level1.size -1 -1 0 0
cache.level2.size -1 -1 0 0
1123
Database
Transactions
true or
tx.useLog true true true true false
'classic'
tx.log.fileType classic classic classic classic or
'mmap'
1124
true or
tx.log.synch false false false false false
TinkerPop Blueprints
Def.Server Def.Server
Parameter Def.32bit Def.64bit 32bit 64bit
blueprints.graph.txMode 0 0 0 0
Index
Def.Server Def.Server
Parameter Def.32bit Def.64bit
32bit
1125
mvrbtree.lazyUpdates 20000 20000 1 1
mvrbtree.entryPoints 16 16 16 16
mvrbtree.ridBinaryThreshold 8 8 8 8
mvrbtree.ridNodePageSize 16 16 16 16
1126
Lazy Collections
File (I/O)
Def. Def.
Parameter 32bit Def. 64bit Server
32bit
file.defrag.strategy 0 0 0
32768 32768
file.defrag.holeMaxDistance 32768 (32Kb)
(32Kb) (32Kb)
1127
file.mmap.strategy 0 0 0
file.mmap.blockSize
1048576 1048576 (1Mb) 1048576
(1Mb) (1Mb)
file.mmap.bufferSize
8192 8192 (8Kb) 8192
(8Kb) (8Kb)
(maxOsMem -
like Def.
file.mmap.maxMemory 134Mb maxProcessHeapMem) 32 bit
/2
file.mmap.overlapStrategy 2 2 2
1128
500 500
file.mmap.forceDelay
(0.5sec) 500 (0.5sec) (0.5sec)
file.mmap.forceRetry 20 20 20
JNA
Def.Server Def.Server
Parameter Def.32bit Def.64bit 32bit 64bit
Networking (I/O)
network.lockTimeout
15000 15000 15000 15000
(15secs) (15secs) (15secs) (15secs)
network.socketTimeout
10000 10000 10000 10000
(10secs) (10secs) (10secs) (10secs)
network.retry 5 5 5 5
1129
network.retryDelay
500 500 500 500
(0.5sec) (0.5sec) (0.5sec) (0.5sec)
network.binary.maxLength
100000 100000 100000 100000
(100Kb) (100Kb) (100Kb) (100Kb)
network.binary.readResponse.maxTime 30 30 30 30
network.http.maxLength
100000 100000 100000 100000
(100Kb) (100Kb) (100Kb) (100Kb)
300 300
network.http.sessionExpireTimeout
(5min) (5min) 300 (5min) 300 (5min)
Profiler
1130
Def.Server Def.Server
Parameter Def.32bit Def.64bit
32bit 64bit
profiler.autoDump.interval 0 0 0 0
Log
fine,
info,
log.console.level info info info info warn,
error
fine,
log.file.level fine fine fine fine info,
warn,
error
Client
Def.Server Def.Server
Parameter Def.32bit Def.64bit 32bit 64bit
1131
client.channel.minPool 1 1 1 1
client.channel.maxPool 5 5 5 5
Server
Distributed cluster
distributed.async.timeDelay 0 0 0 0
1132
NOTE: On 64-bit systems you have not the limitation of 32-bit systems with memory.
1133
Logging
Logging is configured in a separate file, look at Logging for more information.
1134
Storage configuration
OrientDB allows modifications to the storage configuration. Even though this will be
supported with high level commands, for now it's pretty "internal" using Java API.
Look at OStorageConfiguration to discover all the properties you can change. To change
the configuration of a cluster get it by ID;
To change the default settings for new clusters get the file template object. In this
example we change the initial file size from the default 500Kb down to 10Kb:
cfg.update();
1135
Tuning the Graph API
This guide is specific for the TinkerPop Blueprints Graph Database. Please be sure to
read the generic guide to the Performance-Tuning.
1136
Connect to the database locally
Local connection is much faster than remote. So use "plocal" based on the storage
engine used on database creation. If you need to connect to the database from the
network you can use the "Embed the server technique".
1137
Avoid putting properties on edges
Even though supports properties on edges, this is much expensive because it creates a
new record per edge. So if you need them you've to know that the database will be
bigger and insertion time will be much longer.
1138
Set properties all together
It's much lighter to set properties in block than one by one. Look at this paragraph:
Graph-Database-Tinkerpop#setting-multiple-properties.
1139
Set properties on vertex and edge creation
It's even faster if you set properties directly on creation of vertices and edges. Look at
this paragraph: Graph-Database-Tinkerpop#create-element-and-properties.
1140
Massive Insertion
See Generic improvement on massive insertion. To access to the underlying database
use:
database.getRawGraph().declareIntent( null );
1141
Avoid transactions if you can
Use the OrientGraphNoTx implementation that doesn't use transaction at all.
OrientGraphNoTx is not compatible with OrientBatchGraph so use it plain:
1142
Use the schema
Even if you can model your graph with only the entities (V)ertex and (E)dge it's much
better to use schema for your types extending Vertex and Edge classes. In this way
traversing will be faster and vertices and edges will be split on different files. For more
information look at: Graph Schema.
Example:
1143
Use indexes to lookup vertices by an ID
If you've your own ID on vertices and you need to lookup them to create edges then
create an index against it:
If the ID is unique then create an UNIQUE index that is much faster and lighter:
1144
Disable validation
Every time a graph element is modified, OrientDB executes a validation to assure the
graph rules are all respected, that means:
Now if you use the Graph API without bypassing graph element manipulation this could
be turned off with a huge gain in performance:
graph.setValidationEnabled(false);
1145
Reduce vertex objects
You can avoid the creation of a new ODocument for each new vertex by reusing it with
ODocument.reset() method that clears the instance making it ready for a new insert
operation. Bear in mind that you will need to assign the document with the proper class
after resetting as it is done in the code below.
Example:
db.declareIntent( null );
1146
Cache management
Graph Database, by default, caches the most used elements. For massive insertion is
strongly suggested to disable cache to avoid to keep all the element in memory. Massive
Insert Intent automatically sets it to false.
graph.setRetainObjects(false);
1147
Tuning the Document API
This guide is specific for the Document Database. Please be sure to read the generic
guide to the Performance-Tuning.
1148
Massive Insertion
See Generic improvement on massive insertion.
You can avoid the creation of a new ODocument for each insertion by using the
ODocument.reset() method that clears the instance making it ready for a new insert
operation. Bear in mind that you will need to assign the document with the proper class
after resetting as it is done in the code below.
Example:
db.declareIntent( null );
1149
Tuning the Object API
This guide is specific for the Object Database. Please be sure to read the generic guide
to the Performance-Tuning.
1150
Massive Insertion
See Generic improvement on massive insertion.
1151
Profiler
OrientDB Enterprise Edition comes with a profiler that collects all the metrics about the
engine and the system where is running.
1152
Automatic dump
When you incur in problems, the best way to produce information about OrientDB is
activating a regular dump of the profiler. Set this configuration variable at start:
This will dump the profiler in the console every 60 seconds and resets the metrics after
the dump. For more information about settings look at Parameters.
1153
Retrieve profiler metrics via HTTP
http://<server>[<:port>]/profiler/<command>/[<config>]|[<from>/<to>]
Where:
Example:
http://localhost:2480/profiler/realtime
1154
Metric type
Chrono
Chrono are recording of operation. Each Chrono has the following values:
Counter
HookValues
Are generic values of any type between the supported ones: string, number, boolean or
null.
A hook value is not collected in central way, but it's gathered at runtime by calling the
hooks as callbacks.
1155
Metric main categories
Follows the main categories of metrics:
Example of profiler values extracted from the server after test suite is run
(http://localhost:2480/profiler/realtime):
{
"realtime": {
"from": 1344531312356,
"to": 9223372036854776000,
"hookValues": {
"db.0$db.cache.level1.current": 0,
"db.0$db.cache.level1.enabled": false,
"db.0$db.cache.level1.max": -1,
"db.0$db.cache.level2.current": 0,
"db.0$db.cache.level2.enabled": true,
"db.0$db.cache.level2.max": -1,
"db.0$db.data.holeSize": 0,
"db.0$db.data.holes": 0,
"db.0$db.index.dictionary.entryPointSize": 64,
"db.0$db.index.dictionary.items": 0,
"db.0$db.index.dictionary.maxUpdateBeforeSave": 5000,
"db.0$db.index.dictionary.optimizationThreshold": 100000,
"db.1$db.cache.level1.current": 0,
"db.1$db.cache.level1.enabled": false,
"db.1$db.cache.level1.max": -1,
"db.1$db.cache.level2.current": 0,
"db.1$db.cache.level2.enabled": true,
"db.1$db.cache.level2.max": -1,
"db.1$db.data.holeSize": 0,
"db.1$db.data.holes": 0,
"db.1$db.index.dictionary.entryPointSize": 64,
"db.1$db.index.dictionary.items": 0,
"db.1$db.index.dictionary.maxUpdateBeforeSave": 5000,
"db.1$db.index.dictionary.optimizationThreshold": 100000,
"db.2$db.cache.level1.current": 0,
"db.2$db.cache.level1.enabled": false,
1156
"db.2$db.cache.level1.max": -1,
"db.2$db.cache.level2.current": 0,
"db.2$db.cache.level2.enabled": true,
"db.2$db.cache.level2.max": -1,
"db.2$db.data.holeSize": 0,
"db.2$db.data.holes": 0,
"db.2$db.index.dictionary.entryPointSize": 64,
"db.2$db.index.dictionary.items": 0,
"db.2$db.index.dictionary.maxUpdateBeforeSave": 5000,
"db.2$db.index.dictionary.optimizationThreshold": 100000,
"db.demo.cache.level1.current": 0,
"db.demo.cache.level1.enabled": false,
"db.demo.cache.level1.max": -1,
"db.demo.cache.level2.current": 20520,
"db.demo.cache.level2.enabled": true,
"db.demo.cache.level2.max": -1,
"db.demo.data.holeSize": 47553,
"db.demo.data.holes": 24,
"db.demo.index.BaseTestClass.testParentProperty.entryPointSize": 64,
"db.demo.index.BaseTestClass.testParentProperty.items": 2,
"db.demo.index.BaseTestClass.testParentProperty.maxUpdateBeforeSave": 5000,
"db.demo.index.BaseTestClass.testParentProperty.optimizationThreshold": 100000,
"db.demo.index.ClassIndexTestCompositeEmbeddedList.entryPointSize": 64,
"db.demo.index.ClassIndexTestCompositeEmbeddedList.items": 0,
"db.demo.index.ClassIndexTestCompositeEmbeddedList.maxUpdateBeforeSave": 5000,
"db.demo.index.ClassIndexTestCompositeEmbeddedList.optimizationThreshold": 100000
"db.demo.index.ClassIndexTestCompositeEmbeddedMap.entryPointSize": 64,
"db.demo.index.ClassIndexTestCompositeEmbeddedMap.items": 0,
"db.demo.index.ClassIndexTestCompositeEmbeddedMap.maxUpdateBeforeSave": 5000,
"db.demo.index.ClassIndexTestCompositeEmbeddedMap.optimizationThreshold": 100000,
"db.demo.index.ClassIndexTestCompositeEmbeddedMapByKey.entryPointSize": 64,
"db.demo.index.ClassIndexTestCompositeEmbeddedMapByKey.items": 0,
"db.demo.index.ClassIndexTestCompositeEmbeddedMapByKey.maxUpdateBeforeSave": 5000
"db.demo.index.ClassIndexTestCompositeEmbeddedMapByKey.optimizationThreshold": 100000
"db.demo.index.ClassIndexTestCompositeEmbeddedMapByValue.entryPointSize": 64,
"db.demo.index.ClassIndexTestCompositeEmbeddedMapByValue.items": 0,
"db.demo.index.ClassIndexTestCompositeEmbeddedMapByValue.maxUpdateBeforeSave": 5000
"db.demo.index.ClassIndexTestCompositeEmbeddedMapByValue.optimizationThreshold":
"db.demo.index.ClassIndexTestCompositeEmbeddedSet.entryPointSize": 64,
"db.demo.index.ClassIndexTestCompositeEmbeddedSet.items": 0,
"db.demo.index.ClassIndexTestCompositeEmbeddedSet.maxUpdateBeforeSave": 5000,
"db.demo.index.ClassIndexTestCompositeEmbeddedSet.optimizationThreshold": 100000,
"db.demo.index.ClassIndexTestCompositeLinkList.entryPointSize": 64,
"db.demo.index.ClassIndexTestCompositeLinkList.items": 0,
"db.demo.index.ClassIndexTestCompositeLinkList.maxUpdateBeforeSave": 5000,
"db.demo.index.ClassIndexTestCompositeLinkList.optimizationThreshold": 100000,
"db.demo.index.ClassIndexTestCompositeLinkMapByValue.entryPointSize": 64,
"db.demo.index.ClassIndexTestCompositeLinkMapByValue.items": 0,
"db.demo.index.ClassIndexTestCompositeLinkMapByValue.maxUpdateBeforeSave": 5000,
"db.demo.index.ClassIndexTestCompositeLinkMapByValue.optimizationThreshold": 100000
"db.demo.index.ClassIndexTestCompositeOne.entryPointSize": 64,
"db.demo.index.ClassIndexTestCompositeOne.items": 0,
"db.demo.index.ClassIndexTestCompositeOne.maxUpdateBeforeSave": 5000,
"db.demo.index.ClassIndexTestCompositeOne.optimizationThreshold": 100000,
"db.demo.index.ClassIndexTestCompositeTwo.entryPointSize": 64,
"db.demo.index.ClassIndexTestCompositeTwo.items": 0,
"db.demo.index.ClassIndexTestCompositeTwo.maxUpdateBeforeSave": 5000,
"db.demo.index.ClassIndexTestCompositeTwo.optimizationThreshold": 100000,
"db.demo.index.ClassIndexTestDictionaryIndex.entryPointSize": 64,
1157
"db.demo.index.ClassIndexTestDictionaryIndex.items": 0,
"db.demo.index.ClassIndexTestDictionaryIndex.maxUpdateBeforeSave": 5000,
"db.demo.index.ClassIndexTestDictionaryIndex.optimizationThreshold": 100000,
"db.demo.index.ClassIndexTestFulltextIndex.entryPointSize": 64,
"db.demo.index.ClassIndexTestFulltextIndex.items": 0,
"db.demo.index.ClassIndexTestFulltextIndex.maxUpdateBeforeSave": 5000,
"db.demo.index.ClassIndexTestFulltextIndex.optimizationThreshold": 100000,
"db.demo.index.ClassIndexTestNotUniqueIndex.entryPointSize": 64,
"db.demo.index.ClassIndexTestNotUniqueIndex.items": 0,
"db.demo.index.ClassIndexTestNotUniqueIndex.maxUpdateBeforeSave": 5000,
"db.demo.index.ClassIndexTestNotUniqueIndex.optimizationThreshold": 100000,
"db.demo.index.ClassIndexTestParentPropertyNine.entryPointSize": 64,
"db.demo.index.ClassIndexTestParentPropertyNine.items": 0,
"db.demo.index.ClassIndexTestParentPropertyNine.maxUpdateBeforeSave": 5000,
"db.demo.index.ClassIndexTestParentPropertyNine.optimizationThreshold": 100000,
"db.demo.index.ClassIndexTestPropertyByKeyEmbeddedMap.entryPointSize": 64,
"db.demo.index.ClassIndexTestPropertyByKeyEmbeddedMap.items": 0,
"db.demo.index.ClassIndexTestPropertyByKeyEmbeddedMap.maxUpdateBeforeSave": 5000,
"db.demo.index.ClassIndexTestPropertyByKeyEmbeddedMap.optimizationThreshold": 100000
"db.demo.index.ClassIndexTestPropertyByValueEmbeddedMap.entryPointSize": 64,
"db.demo.index.ClassIndexTestPropertyByValueEmbeddedMap.items": 0,
"db.demo.index.ClassIndexTestPropertyByValueEmbeddedMap.maxUpdateBeforeSave": 5000
"db.demo.index.ClassIndexTestPropertyByValueEmbeddedMap.optimizationThreshold": 100000
"db.demo.index.ClassIndexTestPropertyEmbeddedMap.entryPointSize": 64,
"db.demo.index.ClassIndexTestPropertyEmbeddedMap.items": 0,
"db.demo.index.ClassIndexTestPropertyEmbeddedMap.maxUpdateBeforeSave": 5000,
"db.demo.index.ClassIndexTestPropertyEmbeddedMap.optimizationThreshold": 100000,
"db.demo.index.ClassIndexTestPropertyLinkedMap.entryPointSize": 64,
"db.demo.index.ClassIndexTestPropertyLinkedMap.items": 0,
"db.demo.index.ClassIndexTestPropertyLinkedMap.maxUpdateBeforeSave": 5000,
"db.demo.index.ClassIndexTestPropertyLinkedMap.optimizationThreshold": 100000,
"db.demo.index.ClassIndexTestPropertyLinkedMapByKey.entryPointSize": 64,
"db.demo.index.ClassIndexTestPropertyLinkedMapByKey.items": 0,
"db.demo.index.ClassIndexTestPropertyLinkedMapByKey.maxUpdateBeforeSave": 5000,
"db.demo.index.ClassIndexTestPropertyLinkedMapByKey.optimizationThreshold": 100000
"db.demo.index.ClassIndexTestPropertyLinkedMapByValue.entryPointSize": 64,
"db.demo.index.ClassIndexTestPropertyLinkedMapByValue.items": 0,
"db.demo.index.ClassIndexTestPropertyLinkedMapByValue.maxUpdateBeforeSave": 5000,
"db.demo.index.ClassIndexTestPropertyLinkedMapByValue.optimizationThreshold": 100000
"db.demo.index.ClassIndexTestPropertyOne.entryPointSize": 64,
"db.demo.index.ClassIndexTestPropertyOne.items": 0,
"db.demo.index.ClassIndexTestPropertyOne.maxUpdateBeforeSave": 5000,
"db.demo.index.ClassIndexTestPropertyOne.optimizationThreshold": 100000,
"db.demo.index.Collector.stringCollection.entryPointSize": 64,
"db.demo.index.Collector.stringCollection.items": 0,
"db.demo.index.Collector.stringCollection.maxUpdateBeforeSave": 5000,
"db.demo.index.Collector.stringCollection.optimizationThreshold": 100000,
"db.demo.index.DropPropertyIndexCompositeIndex.entryPointSize": 64,
"db.demo.index.DropPropertyIndexCompositeIndex.items": 0,
"db.demo.index.DropPropertyIndexCompositeIndex.maxUpdateBeforeSave": 5000,
"db.demo.index.DropPropertyIndexCompositeIndex.optimizationThreshold": 100000,
"db.demo.index.Fruit.color.entryPointSize": 64,
"db.demo.index.Fruit.color.items": 0,
"db.demo.index.Fruit.color.maxUpdateBeforeSave": 5000,
"db.demo.index.Fruit.color.optimizationThreshold": 100000,
"db.demo.index.IndexCountPlusCondition.entryPointSize": 64,
"db.demo.index.IndexCountPlusCondition.items": 5,
"db.demo.index.IndexCountPlusCondition.maxUpdateBeforeSave": 5000,
"db.demo.index.IndexCountPlusCondition.optimizationThreshold": 100000,
1158
"db.demo.index.IndexNotUniqueIndexKeySize.entryPointSize": 64,
"db.demo.index.IndexNotUniqueIndexKeySize.items": 5,
"db.demo.index.IndexNotUniqueIndexKeySize.maxUpdateBeforeSave": 5000,
"db.demo.index.IndexNotUniqueIndexKeySize.optimizationThreshold": 100000,
"db.demo.index.IndexNotUniqueIndexSize.entryPointSize": 64,
"db.demo.index.IndexNotUniqueIndexSize.items": 5,
"db.demo.index.IndexNotUniqueIndexSize.maxUpdateBeforeSave": 5000,
"db.demo.index.IndexNotUniqueIndexSize.optimizationThreshold": 100000,
"db.demo.index.MapPoint.x.entryPointSize": 64,
"db.demo.index.MapPoint.x.items": 9999,
"db.demo.index.MapPoint.x.maxUpdateBeforeSave": 5000,
"db.demo.index.MapPoint.x.optimizationThreshold": 100000,
"db.demo.index.MapPoint.y.entryPointSize": 64,
"db.demo.index.MapPoint.y.items": 10000,
"db.demo.index.MapPoint.y.maxUpdateBeforeSave": 5000,
"db.demo.index.MapPoint.y.optimizationThreshold": 100000,
"db.demo.index.MyFruit.color.entryPointSize": 64,
"db.demo.index.MyFruit.color.items": 10,
"db.demo.index.MyFruit.color.maxUpdateBeforeSave": 5000,
"db.demo.index.MyFruit.color.optimizationThreshold": 100000,
"db.demo.index.MyFruit.flavor.entryPointSize": 64,
"db.demo.index.MyFruit.flavor.items": 0,
"db.demo.index.MyFruit.flavor.maxUpdateBeforeSave": 5000,
"db.demo.index.MyFruit.flavor.optimizationThreshold": 100000,
"db.demo.index.MyFruit.name.entryPointSize": 64,
"db.demo.index.MyFruit.name.items": 5000,
"db.demo.index.MyFruit.name.maxUpdateBeforeSave": 5000,
"db.demo.index.MyFruit.name.optimizationThreshold": 100000,
"db.demo.index.MyProfile.name.entryPointSize": 64,
"db.demo.index.MyProfile.name.items": 3,
"db.demo.index.MyProfile.name.maxUpdateBeforeSave": 5000,
"db.demo.index.MyProfile.name.optimizationThreshold": 100000,
"db.demo.index.Profile.hash.entryPointSize": 64,
"db.demo.index.Profile.hash.items": 5,
"db.demo.index.Profile.hash.maxUpdateBeforeSave": 5000,
"db.demo.index.Profile.hash.optimizationThreshold": 100000,
"db.demo.index.Profile.name.entryPointSize": 64,
"db.demo.index.Profile.name.items": 20,
"db.demo.index.Profile.name.maxUpdateBeforeSave": 5000,
"db.demo.index.Profile.name.optimizationThreshold": 100000,
"db.demo.index.Profile.nick.entryPointSize": 64,
"db.demo.index.Profile.nick.items": 38,
"db.demo.index.Profile.nick.maxUpdateBeforeSave": 5000,
"db.demo.index.Profile.nick.optimizationThreshold": 100000,
"db.demo.index.PropertyIndexFirstIndex.entryPointSize": 64,
"db.demo.index.PropertyIndexFirstIndex.items": 0,
"db.demo.index.PropertyIndexFirstIndex.maxUpdateBeforeSave": 5000,
"db.demo.index.PropertyIndexFirstIndex.optimizationThreshold": 100000,
"db.demo.index.PropertyIndexSecondIndex.entryPointSize": 64,
"db.demo.index.PropertyIndexSecondIndex.items": 0,
"db.demo.index.PropertyIndexSecondIndex.maxUpdateBeforeSave": 5000,
"db.demo.index.PropertyIndexSecondIndex.optimizationThreshold": 100000,
"db.demo.index.PropertyIndexTestClass.prop1.entryPointSize": 64,
"db.demo.index.PropertyIndexTestClass.prop1.items": 0,
"db.demo.index.PropertyIndexTestClass.prop1.maxUpdateBeforeSave": 5000,
"db.demo.index.PropertyIndexTestClass.prop1.optimizationThreshold": 100000,
"db.demo.index.SQLDropClassCompositeIndex.entryPointSize": 64,
"db.demo.index.SQLDropClassCompositeIndex.items": 0,
"db.demo.index.SQLDropClassCompositeIndex.maxUpdateBeforeSave": 5000,
1159
"db.demo.index.SQLDropClassCompositeIndex.optimizationThreshold": 100000,
"db.demo.index.SQLDropIndexCompositeIndex.entryPointSize": 64,
"db.demo.index.SQLDropIndexCompositeIndex.items": 0,
"db.demo.index.SQLDropIndexCompositeIndex.maxUpdateBeforeSave": 5000,
"db.demo.index.SQLDropIndexCompositeIndex.optimizationThreshold": 100000,
"db.demo.index.SQLDropIndexTestClass.prop1.entryPointSize": 64,
"db.demo.index.SQLDropIndexTestClass.prop1.items": 0,
"db.demo.index.SQLDropIndexTestClass.prop1.maxUpdateBeforeSave": 5000,
"db.demo.index.SQLDropIndexTestClass.prop1.optimizationThreshold": 100000,
"db.demo.index.SQLDropIndexWithoutClass.entryPointSize": 64,
"db.demo.index.SQLDropIndexWithoutClass.items": 0,
"db.demo.index.SQLDropIndexWithoutClass.maxUpdateBeforeSave": 5000,
"db.demo.index.SQLDropIndexWithoutClass.optimizationThreshold": 100000,
"db.demo.index.SQLSelectCompositeIndexDirectSearchTestIndex.entryPointSize": 64,
"db.demo.index.SQLSelectCompositeIndexDirectSearchTestIndex.items": 0,
"db.demo.index.SQLSelectCompositeIndexDirectSearchTestIndex.maxUpdateBeforeSave":
"db.demo.index.SQLSelectCompositeIndexDirectSearchTestIndex.optimizationThreshold
"db.demo.index.SchemaSharedIndexCompositeIndex.entryPointSize": 64,
"db.demo.index.SchemaSharedIndexCompositeIndex.items": 0,
"db.demo.index.SchemaSharedIndexCompositeIndex.maxUpdateBeforeSave": 5000,
"db.demo.index.SchemaSharedIndexCompositeIndex.optimizationThreshold": 100000,
"db.demo.index.TRPerson.name.entryPointSize": 64,
"db.demo.index.TRPerson.name.items": 4,
"db.demo.index.TRPerson.name.maxUpdateBeforeSave": 5000,
"db.demo.index.TRPerson.name.optimizationThreshold": 100000,
"db.demo.index.TRPerson.surname.entryPointSize": 64,
"db.demo.index.TRPerson.surname.items": 3,
"db.demo.index.TRPerson.surname.maxUpdateBeforeSave": 5000,
"db.demo.index.TRPerson.surname.optimizationThreshold": 100000,
"db.demo.index.TestClass.name.entryPointSize": 64,
"db.demo.index.TestClass.name.items": 2,
"db.demo.index.TestClass.name.maxUpdateBeforeSave": 5000,
"db.demo.index.TestClass.name.optimizationThreshold": 100000,
"db.demo.index.TestClass.testLink.entryPointSize": 64,
"db.demo.index.TestClass.testLink.items": 2,
"db.demo.index.TestClass.testLink.maxUpdateBeforeSave": 5000,
"db.demo.index.TestClass.testLink.optimizationThreshold": 100000,
"db.demo.index.TransactionUniqueIndexWithDotTest.label.entryPointSize": 64,
"db.demo.index.TransactionUniqueIndexWithDotTest.label.items": 1,
"db.demo.index.TransactionUniqueIndexWithDotTest.label.maxUpdateBeforeSave": 5000
"db.demo.index.TransactionUniqueIndexWithDotTest.label.optimizationThreshold": 100000
"db.demo.index.Whiz.account.entryPointSize": 64,
"db.demo.index.Whiz.account.items": 1,
"db.demo.index.Whiz.account.maxUpdateBeforeSave": 5000,
"db.demo.index.Whiz.account.optimizationThreshold": 100000,
"db.demo.index.Whiz.text.entryPointSize": 64,
"db.demo.index.Whiz.text.items": 275,
"db.demo.index.Whiz.text.maxUpdateBeforeSave": 5000,
"db.demo.index.Whiz.text.optimizationThreshold": 100000,
"db.demo.index.a.entryPointSize": 64,
"db.demo.index.a.items": 0,
"db.demo.index.a.maxUpdateBeforeSave": 5000,
"db.demo.index.a.optimizationThreshold": 100000,
"db.demo.index.anotherproperty.entryPointSize": 64,
"db.demo.index.anotherproperty.items": 0,
"db.demo.index.anotherproperty.maxUpdateBeforeSave": 5000,
"db.demo.index.anotherproperty.optimizationThreshold": 100000,
"db.demo.index.byte-array-manualIndex-notunique.entryPointSize": 64,
"db.demo.index.byte-array-manualIndex-notunique.items": 6,
1160
"db.demo.index.byte-array-manualIndex-notunique.maxUpdateBeforeSave": 5000,
"db.demo.index.byte-array-manualIndex-notunique.optimizationThreshold": 100000,
"db.demo.index.byte-array-manualIndex.entryPointSize": 64,
"db.demo.index.byte-array-manualIndex.items": 11,
"db.demo.index.byte-array-manualIndex.maxUpdateBeforeSave": 5000,
"db.demo.index.byte-array-manualIndex.optimizationThreshold": 100000,
"db.demo.index.byteArrayKeyIndex.entryPointSize": 64,
"db.demo.index.byteArrayKeyIndex.items": 2,
"db.demo.index.byteArrayKeyIndex.maxUpdateBeforeSave": 5000,
"db.demo.index.byteArrayKeyIndex.optimizationThreshold": 100000,
"db.demo.index.classIndexManagerComposite.entryPointSize": 64,
"db.demo.index.classIndexManagerComposite.items": 0,
"db.demo.index.classIndexManagerComposite.maxUpdateBeforeSave": 5000,
"db.demo.index.classIndexManagerComposite.optimizationThreshold": 100000,
"db.demo.index.classIndexManagerTestClass.prop1.entryPointSize": 64,
"db.demo.index.classIndexManagerTestClass.prop1.items": 0,
"db.demo.index.classIndexManagerTestClass.prop1.maxUpdateBeforeSave": 5000,
"db.demo.index.classIndexManagerTestClass.prop1.optimizationThreshold": 100000,
"db.demo.index.classIndexManagerTestClass.prop2.entryPointSize": 64,
"db.demo.index.classIndexManagerTestClass.prop2.items": 0,
"db.demo.index.classIndexManagerTestClass.prop2.maxUpdateBeforeSave": 5000,
"db.demo.index.classIndexManagerTestClass.prop2.optimizationThreshold": 100000,
"db.demo.index.classIndexManagerTestClass.prop4.entryPointSize": 64,
"db.demo.index.classIndexManagerTestClass.prop4.items": 0,
"db.demo.index.classIndexManagerTestClass.prop4.maxUpdateBeforeSave": 5000,
"db.demo.index.classIndexManagerTestClass.prop4.optimizationThreshold": 100000,
"db.demo.index.classIndexManagerTestClass.prop6.entryPointSize": 64,
"db.demo.index.classIndexManagerTestClass.prop6.items": 0,
"db.demo.index.classIndexManagerTestClass.prop6.maxUpdateBeforeSave": 5000,
"db.demo.index.classIndexManagerTestClass.prop6.optimizationThreshold": 100000,
"db.demo.index.classIndexManagerTestIndexByKey.entryPointSize": 64,
"db.demo.index.classIndexManagerTestIndexByKey.items": 0,
"db.demo.index.classIndexManagerTestIndexByKey.maxUpdateBeforeSave": 5000,
"db.demo.index.classIndexManagerTestIndexByKey.optimizationThreshold": 100000,
"db.demo.index.classIndexManagerTestIndexByValue.entryPointSize": 64,
"db.demo.index.classIndexManagerTestIndexByValue.items": 0,
"db.demo.index.classIndexManagerTestIndexByValue.maxUpdateBeforeSave": 5000,
"db.demo.index.classIndexManagerTestIndexByValue.optimizationThreshold": 100000,
"db.demo.index.classIndexManagerTestIndexValueAndCollection.entryPointSize": 64,
"db.demo.index.classIndexManagerTestIndexValueAndCollection.items": 0,
"db.demo.index.classIndexManagerTestIndexValueAndCollection.maxUpdateBeforeSave":
"db.demo.index.classIndexManagerTestIndexValueAndCollection.optimizationThreshold
"db.demo.index.classIndexManagerTestSuperClass.prop0.entryPointSize": 64,
"db.demo.index.classIndexManagerTestSuperClass.prop0.items": 0,
"db.demo.index.classIndexManagerTestSuperClass.prop0.maxUpdateBeforeSave": 5000,
"db.demo.index.classIndexManagerTestSuperClass.prop0.optimizationThreshold": 100000
"db.demo.index.compositeByteArrayKey.entryPointSize": 64,
"db.demo.index.compositeByteArrayKey.items": 4,
"db.demo.index.compositeByteArrayKey.maxUpdateBeforeSave": 5000,
"db.demo.index.compositeByteArrayKey.optimizationThreshold": 100000,
"db.demo.index.compositeIndexWithoutSchema.entryPointSize": 64,
"db.demo.index.compositeIndexWithoutSchema.items": 0,
"db.demo.index.compositeIndexWithoutSchema.maxUpdateBeforeSave": 5000,
"db.demo.index.compositeIndexWithoutSchema.optimizationThreshold": 100000,
"db.demo.index.compositeone.entryPointSize": 64,
"db.demo.index.compositeone.items": 0,
"db.demo.index.compositeone.maxUpdateBeforeSave": 5000,
"db.demo.index.compositeone.optimizationThreshold": 100000,
"db.demo.index.compositetwo.entryPointSize": 64,
1161
"db.demo.index.compositetwo.items": 0,
"db.demo.index.compositetwo.maxUpdateBeforeSave": 5000,
"db.demo.index.compositetwo.optimizationThreshold": 100000,
"db.demo.index.curotorCompositeIndex.entryPointSize": 64,
"db.demo.index.curotorCompositeIndex.items": 0,
"db.demo.index.curotorCompositeIndex.maxUpdateBeforeSave": 5000,
"db.demo.index.curotorCompositeIndex.optimizationThreshold": 100000,
"db.demo.index.dictionary.entryPointSize": 64,
"db.demo.index.dictionary.items": 2,
"db.demo.index.dictionary.maxUpdateBeforeSave": 5000,
"db.demo.index.dictionary.optimizationThreshold": 100000,
"db.demo.index.diplomaThesisUnique.entryPointSize": 64,
"db.demo.index.diplomaThesisUnique.items": 3,
"db.demo.index.diplomaThesisUnique.maxUpdateBeforeSave": 5000,
"db.demo.index.diplomaThesisUnique.optimizationThreshold": 100000,
"db.demo.index.equalityIdx.entryPointSize": 64,
"db.demo.index.equalityIdx.items": 0,
"db.demo.index.equalityIdx.maxUpdateBeforeSave": 5000,
"db.demo.index.equalityIdx.optimizationThreshold": 100000,
"db.demo.index.idx.entryPointSize": 64,
"db.demo.index.idx.items": 2,
"db.demo.index.idx.maxUpdateBeforeSave": 5000,
"db.demo.index.idx.optimizationThreshold": 100000,
"db.demo.index.idxTerm.entryPointSize": 64,
"db.demo.index.idxTerm.items": 1,
"db.demo.index.idxTerm.maxUpdateBeforeSave": 5000,
"db.demo.index.idxTerm.optimizationThreshold": 100000,
"db.demo.index.idxTransactionUniqueIndexTest.entryPointSize": 64,
"db.demo.index.idxTransactionUniqueIndexTest.items": 1,
"db.demo.index.idxTransactionUniqueIndexTest.maxUpdateBeforeSave": 5000,
"db.demo.index.idxTransactionUniqueIndexTest.optimizationThreshold": 100000,
"db.demo.index.idxTxAwareMultiValueGetEntriesTest.entryPointSize": 64,
"db.demo.index.idxTxAwareMultiValueGetEntriesTest.items": 0,
"db.demo.index.idxTxAwareMultiValueGetEntriesTest.maxUpdateBeforeSave": 5000,
"db.demo.index.idxTxAwareMultiValueGetEntriesTest.optimizationThreshold": 100000,
"db.demo.index.idxTxAwareMultiValueGetTest.entryPointSize": 64,
"db.demo.index.idxTxAwareMultiValueGetTest.items": 0,
"db.demo.index.idxTxAwareMultiValueGetTest.maxUpdateBeforeSave": 5000,
"db.demo.index.idxTxAwareMultiValueGetTest.optimizationThreshold": 100000,
"db.demo.index.idxTxAwareMultiValueGetValuesTest.entryPointSize": 64,
"db.demo.index.idxTxAwareMultiValueGetValuesTest.items": 0,
"db.demo.index.idxTxAwareMultiValueGetValuesTest.maxUpdateBeforeSave": 5000,
"db.demo.index.idxTxAwareMultiValueGetValuesTest.optimizationThreshold": 100000,
"db.demo.index.idxTxAwareOneValueGetEntriesTest.entryPointSize": 64,
"db.demo.index.idxTxAwareOneValueGetEntriesTest.items": 0,
"db.demo.index.idxTxAwareOneValueGetEntriesTest.maxUpdateBeforeSave": 5000,
"db.demo.index.idxTxAwareOneValueGetEntriesTest.optimizationThreshold": 100000,
"db.demo.index.idxTxAwareOneValueGetTest.entryPointSize": 64,
"db.demo.index.idxTxAwareOneValueGetTest.items": 0,
"db.demo.index.idxTxAwareOneValueGetTest.maxUpdateBeforeSave": 5000,
"db.demo.index.idxTxAwareOneValueGetTest.optimizationThreshold": 100000,
"db.demo.index.idxTxAwareOneValueGetValuesTest.entryPointSize": 64,
"db.demo.index.idxTxAwareOneValueGetValuesTest.items": 0,
"db.demo.index.idxTxAwareOneValueGetValuesTest.maxUpdateBeforeSave": 5000,
"db.demo.index.idxTxAwareOneValueGetValuesTest.optimizationThreshold": 100000,
"db.demo.index.inIdx.entryPointSize": 64,
"db.demo.index.inIdx.items": 0,
"db.demo.index.inIdx.maxUpdateBeforeSave": 5000,
"db.demo.index.inIdx.optimizationThreshold": 100000,
1162
"db.demo.index.indexForMap.entryPointSize": 64,
"db.demo.index.indexForMap.items": 0,
"db.demo.index.indexForMap.maxUpdateBeforeSave": 5000,
"db.demo.index.indexForMap.optimizationThreshold": 100000,
"db.demo.index.indexWithoutSchema.entryPointSize": 64,
"db.demo.index.indexWithoutSchema.items": 0,
"db.demo.index.indexWithoutSchema.maxUpdateBeforeSave": 5000,
"db.demo.index.indexWithoutSchema.optimizationThreshold": 100000,
"db.demo.index.indexfive.entryPointSize": 64,
"db.demo.index.indexfive.items": 0,
"db.demo.index.indexfive.maxUpdateBeforeSave": 5000,
"db.demo.index.indexfive.optimizationThreshold": 100000,
"db.demo.index.indexfour.entryPointSize": 64,
"db.demo.index.indexfour.items": 0,
"db.demo.index.indexfour.maxUpdateBeforeSave": 5000,
"db.demo.index.indexfour.optimizationThreshold": 100000,
"db.demo.index.indexone.entryPointSize": 64,
"db.demo.index.indexone.items": 0,
"db.demo.index.indexone.maxUpdateBeforeSave": 5000,
"db.demo.index.indexone.optimizationThreshold": 100000,
"db.demo.index.indexsix.entryPointSize": 64,
"db.demo.index.indexsix.items": 0,
"db.demo.index.indexsix.maxUpdateBeforeSave": 5000,
"db.demo.index.indexsix.optimizationThreshold": 100000,
"db.demo.index.indexthree.entryPointSize": 64,
"db.demo.index.indexthree.items": 0,
"db.demo.index.indexthree.maxUpdateBeforeSave": 5000,
"db.demo.index.indexthree.optimizationThreshold": 100000,
"db.demo.index.indextwo.entryPointSize": 64,
"db.demo.index.indextwo.items": 0,
"db.demo.index.indextwo.maxUpdateBeforeSave": 5000,
"db.demo.index.indextwo.optimizationThreshold": 100000,
"db.demo.index.linkCollectionIndex.entryPointSize": 64,
"db.demo.index.linkCollectionIndex.items": 0,
"db.demo.index.linkCollectionIndex.maxUpdateBeforeSave": 5000,
"db.demo.index.linkCollectionIndex.optimizationThreshold": 100000,
"db.demo.index.lpirtCurator.name.entryPointSize": 64,
"db.demo.index.lpirtCurator.name.items": 0,
"db.demo.index.lpirtCurator.name.maxUpdateBeforeSave": 5000,
"db.demo.index.lpirtCurator.name.optimizationThreshold": 100000,
"db.demo.index.lpirtCurator.salary.entryPointSize": 64,
"db.demo.index.lpirtCurator.salary.items": 0,
"db.demo.index.lpirtCurator.salary.maxUpdateBeforeSave": 5000,
"db.demo.index.lpirtCurator.salary.optimizationThreshold": 100000,
"db.demo.index.lpirtDiploma.GPA.entryPointSize": 64,
"db.demo.index.lpirtDiploma.GPA.items": 3,
"db.demo.index.lpirtDiploma.GPA.maxUpdateBeforeSave": 5000,
"db.demo.index.lpirtDiploma.GPA.optimizationThreshold": 100000,
"db.demo.index.lpirtDiploma.thesis.entryPointSize": 64,
"db.demo.index.lpirtDiploma.thesis.items": 54,
"db.demo.index.lpirtDiploma.thesis.maxUpdateBeforeSave": 5000,
"db.demo.index.lpirtDiploma.thesis.optimizationThreshold": 100000,
"db.demo.index.lpirtGroup.curator.entryPointSize": 64,
"db.demo.index.lpirtGroup.curator.items": 0,
"db.demo.index.lpirtGroup.curator.maxUpdateBeforeSave": 5000,
"db.demo.index.lpirtGroup.curator.optimizationThreshold": 100000,
"db.demo.index.lpirtGroup.name.entryPointSize": 64,
"db.demo.index.lpirtGroup.name.items": 0,
"db.demo.index.lpirtGroup.name.maxUpdateBeforeSave": 5000,
1163
"db.demo.index.lpirtGroup.name.optimizationThreshold": 100000,
"db.demo.index.lpirtStudent.group.entryPointSize": 64,
"db.demo.index.lpirtStudent.group.items": 0,
"db.demo.index.lpirtStudent.group.maxUpdateBeforeSave": 5000,
"db.demo.index.lpirtStudent.group.optimizationThreshold": 100000,
"db.demo.index.lpirtStudent.name.entryPointSize": 64,
"db.demo.index.lpirtStudent.name.items": 0,
"db.demo.index.lpirtStudent.name.maxUpdateBeforeSave": 5000,
"db.demo.index.lpirtStudent.name.optimizationThreshold": 100000,
"db.demo.index.manualTxIndexTest.entryPointSize": 64,
"db.demo.index.manualTxIndexTest.items": 1,
"db.demo.index.manualTxIndexTest.maxUpdateBeforeSave": 5000,
"db.demo.index.manualTxIndexTest.optimizationThreshold": 100000,
"db.demo.index.mapIndexTestKey.entryPointSize": 64,
"db.demo.index.mapIndexTestKey.items": 0,
"db.demo.index.mapIndexTestKey.maxUpdateBeforeSave": 5000,
"db.demo.index.mapIndexTestKey.optimizationThreshold": 100000,
"db.demo.index.mapIndexTestValue.entryPointSize": 64,
"db.demo.index.mapIndexTestValue.items": 0,
"db.demo.index.mapIndexTestValue.maxUpdateBeforeSave": 5000,
"db.demo.index.mapIndexTestValue.optimizationThreshold": 100000,
"db.demo.index.newV.f_int.entryPointSize": 64,
"db.demo.index.newV.f_int.items": 3,
"db.demo.index.newV.f_int.maxUpdateBeforeSave": 5000,
"db.demo.index.newV.f_int.optimizationThreshold": 100000,
"db.demo.index.nullkey.entryPointSize": 64,
"db.demo.index.nullkey.items": 0,
"db.demo.index.nullkey.maxUpdateBeforeSave": 5000,
"db.demo.index.nullkey.optimizationThreshold": 100000,
"db.demo.index.nullkeytwo.entryPointSize": 64,
"db.demo.index.nullkeytwo.items": 0,
"db.demo.index.nullkeytwo.maxUpdateBeforeSave": 5000,
"db.demo.index.nullkeytwo.optimizationThreshold": 100000,
"db.demo.index.propOne1.entryPointSize": 64,
"db.demo.index.propOne1.items": 0,
"db.demo.index.propOne1.maxUpdateBeforeSave": 5000,
"db.demo.index.propOne1.optimizationThreshold": 100000,
"db.demo.index.propOne2.entryPointSize": 64,
"db.demo.index.propOne2.items": 0,
"db.demo.index.propOne2.maxUpdateBeforeSave": 5000,
"db.demo.index.propOne2.optimizationThreshold": 100000,
"db.demo.index.propOne3.entryPointSize": 64,
"db.demo.index.propOne3.items": 0,
"db.demo.index.propOne3.maxUpdateBeforeSave": 5000,
"db.demo.index.propOne3.optimizationThreshold": 100000,
"db.demo.index.propOne4.entryPointSize": 64,
"db.demo.index.propOne4.items": 0,
"db.demo.index.propOne4.maxUpdateBeforeSave": 5000,
"db.demo.index.propOne4.optimizationThreshold": 100000,
"db.demo.index.propertyone.entryPointSize": 64,
"db.demo.index.propertyone.items": 0,
"db.demo.index.propertyone.maxUpdateBeforeSave": 5000,
"db.demo.index.propertyone.optimizationThreshold": 100000,
"db.demo.index.simplekey.entryPointSize": 64,
"db.demo.index.simplekey.items": 0,
"db.demo.index.simplekey.maxUpdateBeforeSave": 5000,
"db.demo.index.simplekey.optimizationThreshold": 100000,
"db.demo.index.simplekeytwo.entryPointSize": 64,
"db.demo.index.simplekeytwo.items": 0,
1164
"db.demo.index.simplekeytwo.maxUpdateBeforeSave": 5000,
"db.demo.index.simplekeytwo.optimizationThreshold": 100000,
"db.demo.index.sqlCreateIndexCompositeIndex.entryPointSize": 64,
"db.demo.index.sqlCreateIndexCompositeIndex.items": 0,
"db.demo.index.sqlCreateIndexCompositeIndex.maxUpdateBeforeSave": 5000,
"db.demo.index.sqlCreateIndexCompositeIndex.optimizationThreshold": 100000,
"db.demo.index.sqlCreateIndexCompositeIndex2.entryPointSize": 64,
"db.demo.index.sqlCreateIndexCompositeIndex2.items": 0,
"db.demo.index.sqlCreateIndexCompositeIndex2.maxUpdateBeforeSave": 5000,
"db.demo.index.sqlCreateIndexCompositeIndex2.optimizationThreshold": 100000,
"db.demo.index.sqlCreateIndexEmbeddedListIndex.entryPointSize": 64,
"db.demo.index.sqlCreateIndexEmbeddedListIndex.items": 0,
"db.demo.index.sqlCreateIndexEmbeddedListIndex.maxUpdateBeforeSave": 5000,
"db.demo.index.sqlCreateIndexEmbeddedListIndex.optimizationThreshold": 100000,
"db.demo.index.sqlCreateIndexEmbeddedMapByKeyIndex.entryPointSize": 64,
"db.demo.index.sqlCreateIndexEmbeddedMapByKeyIndex.items": 0,
"db.demo.index.sqlCreateIndexEmbeddedMapByKeyIndex.maxUpdateBeforeSave": 5000,
"db.demo.index.sqlCreateIndexEmbeddedMapByKeyIndex.optimizationThreshold": 100000
"db.demo.index.sqlCreateIndexEmbeddedMapByValueIndex.entryPointSize": 64,
"db.demo.index.sqlCreateIndexEmbeddedMapByValueIndex.items": 0,
"db.demo.index.sqlCreateIndexEmbeddedMapByValueIndex.maxUpdateBeforeSave": 5000,
"db.demo.index.sqlCreateIndexEmbeddedMapByValueIndex.optimizationThreshold": 100000
"db.demo.index.sqlCreateIndexEmbeddedMapIndex.entryPointSize": 64,
"db.demo.index.sqlCreateIndexEmbeddedMapIndex.items": 0,
"db.demo.index.sqlCreateIndexEmbeddedMapIndex.maxUpdateBeforeSave": 5000,
"db.demo.index.sqlCreateIndexEmbeddedMapIndex.optimizationThreshold": 100000,
"db.demo.index.sqlCreateIndexTestClass.prop1.entryPointSize": 64,
"db.demo.index.sqlCreateIndexTestClass.prop1.items": 0,
"db.demo.index.sqlCreateIndexTestClass.prop1.maxUpdateBeforeSave": 5000,
"db.demo.index.sqlCreateIndexTestClass.prop1.optimizationThreshold": 100000,
"db.demo.index.sqlCreateIndexTestClass.prop3.entryPointSize": 64,
"db.demo.index.sqlCreateIndexTestClass.prop3.items": 0,
"db.demo.index.sqlCreateIndexTestClass.prop3.maxUpdateBeforeSave": 5000,
"db.demo.index.sqlCreateIndexTestClass.prop3.optimizationThreshold": 100000,
"db.demo.index.sqlCreateIndexTestClass.prop5.entryPointSize": 64,
"db.demo.index.sqlCreateIndexTestClass.prop5.items": 0,
"db.demo.index.sqlCreateIndexTestClass.prop5.maxUpdateBeforeSave": 5000,
"db.demo.index.sqlCreateIndexTestClass.prop5.optimizationThreshold": 100000,
"db.demo.index.sqlCreateIndexWithoutClass.entryPointSize": 64,
"db.demo.index.sqlCreateIndexWithoutClass.items": 0,
"db.demo.index.sqlCreateIndexWithoutClass.maxUpdateBeforeSave": 5000,
"db.demo.index.sqlCreateIndexWithoutClass.optimizationThreshold": 100000,
"db.demo.index.sqlSelectIndexReuseTestEmbeddedList.entryPointSize": 64,
"db.demo.index.sqlSelectIndexReuseTestEmbeddedList.items": 0,
"db.demo.index.sqlSelectIndexReuseTestEmbeddedList.maxUpdateBeforeSave": 5000,
"db.demo.index.sqlSelectIndexReuseTestEmbeddedList.optimizationThreshold": 100000
"db.demo.index.sqlSelectIndexReuseTestEmbeddedListTwoProp8.entryPointSize": 64,
"db.demo.index.sqlSelectIndexReuseTestEmbeddedListTwoProp8.items": 0,
"db.demo.index.sqlSelectIndexReuseTestEmbeddedListTwoProp8.maxUpdateBeforeSave":
"db.demo.index.sqlSelectIndexReuseTestEmbeddedListTwoProp8.optimizationThreshold":
"db.demo.index.sqlSelectIndexReuseTestEmbeddedMapByKey.entryPointSize": 64,
"db.demo.index.sqlSelectIndexReuseTestEmbeddedMapByKey.items": 0,
"db.demo.index.sqlSelectIndexReuseTestEmbeddedMapByKey.maxUpdateBeforeSave": 5000
"db.demo.index.sqlSelectIndexReuseTestEmbeddedMapByKey.optimizationThreshold": 100000
"db.demo.index.sqlSelectIndexReuseTestEmbeddedMapByKeyProp8.entryPointSize": 64,
"db.demo.index.sqlSelectIndexReuseTestEmbeddedMapByKeyProp8.items": 0,
"db.demo.index.sqlSelectIndexReuseTestEmbeddedMapByKeyProp8.maxUpdateBeforeSave":
"db.demo.index.sqlSelectIndexReuseTestEmbeddedMapByKeyProp8.optimizationThreshold
"db.demo.index.sqlSelectIndexReuseTestEmbeddedMapByValue.entryPointSize": 64,
1165
"db.demo.index.sqlSelectIndexReuseTestEmbeddedMapByValue.items": 0,
"db.demo.index.sqlSelectIndexReuseTestEmbeddedMapByValue.maxUpdateBeforeSave": 5000
"db.demo.index.sqlSelectIndexReuseTestEmbeddedMapByValue.optimizationThreshold":
"db.demo.index.sqlSelectIndexReuseTestEmbeddedMapByValueProp8.entryPointSize": 64
"db.demo.index.sqlSelectIndexReuseTestEmbeddedMapByValueProp8.items": 0,
"db.demo.index.sqlSelectIndexReuseTestEmbeddedMapByValueProp8.maxUpdateBeforeSave
"db.demo.index.sqlSelectIndexReuseTestEmbeddedMapByValueProp8.optimizationThreshold
"db.demo.index.sqlSelectIndexReuseTestEmbeddedSetProp8.entryPointSize": 64,
"db.demo.index.sqlSelectIndexReuseTestEmbeddedSetProp8.items": 0,
"db.demo.index.sqlSelectIndexReuseTestEmbeddedSetProp8.maxUpdateBeforeSave": 5000
"db.demo.index.sqlSelectIndexReuseTestEmbeddedSetProp8.optimizationThreshold": 100000
"db.demo.index.sqlSelectIndexReuseTestProp9EmbeddedSetProp8.entryPointSize": 64,
"db.demo.index.sqlSelectIndexReuseTestProp9EmbeddedSetProp8.items": 0,
"db.demo.index.sqlSelectIndexReuseTestProp9EmbeddedSetProp8.maxUpdateBeforeSave":
"db.demo.index.sqlSelectIndexReuseTestProp9EmbeddedSetProp8.optimizationThreshold
"db.demo.index.studentDiplomaAndNameIndex.entryPointSize": 64,
"db.demo.index.studentDiplomaAndNameIndex.items": 0,
"db.demo.index.studentDiplomaAndNameIndex.maxUpdateBeforeSave": 5000,
"db.demo.index.studentDiplomaAndNameIndex.optimizationThreshold": 100000,
"db.demo.index.testIdx.entryPointSize": 64,
"db.demo.index.testIdx.items": 1,
"db.demo.index.testIdx.maxUpdateBeforeSave": 5000,
"db.demo.index.testIdx.optimizationThreshold": 100000,
"db.demo.index.test_class_by_data.entryPointSize": 64,
"db.demo.index.test_class_by_data.items": 0,
"db.demo.index.test_class_by_data.maxUpdateBeforeSave": 5000,
"db.demo.index.test_class_by_data.optimizationThreshold": 100000,
"db.demo.index.twoclassproperty.entryPointSize": 64,
"db.demo.index.twoclassproperty.items": 0,
"db.demo.index.twoclassproperty.maxUpdateBeforeSave": 5000,
"db.demo.index.twoclassproperty.optimizationThreshold": 100000,
"db.demo.index.vertexA_name_idx.entryPointSize": 64,
"db.demo.index.vertexA_name_idx.items": 2,
"db.demo.index.vertexA_name_idx.maxUpdateBeforeSave": 5000,
"db.demo.index.vertexA_name_idx.optimizationThreshold": 100000,
"db.demo.index.vertexB_name_idx.entryPointSize": 64,
"db.demo.index.vertexB_name_idx.items": 2,
"db.demo.index.vertexB_name_idx.maxUpdateBeforeSave": 5000,
"db.demo.index.vertexB_name_idx.optimizationThreshold": 100000,
"db.subTest.cache.level1.current": 0,
"db.subTest.cache.level1.enabled": false,
"db.subTest.cache.level1.max": -1,
"db.subTest.cache.level2.current": 0,
"db.subTest.cache.level2.enabled": false,
"db.subTest.cache.level2.max": -1,
"db.subTest.data.holeSize": 0,
"db.subTest.data.holes": 0,
"db.subTest.index.dictionary.entryPointSize": 64,
"db.subTest.index.dictionary.items": 0,
"db.subTest.index.dictionary.maxUpdateBeforeSave": 5000,
"db.subTest.index.dictionary.optimizationThreshold": 100000,
"db.temp.cache.level1.current": 0,
"db.temp.cache.level1.enabled": false,
"db.temp.cache.level1.max": -1,
"db.temp.cache.level2.current": 3,
"db.temp.cache.level2.enabled": true,
"db.temp.cache.level2.max": -1,
"db.temp.index.dictionary.entryPointSize": 64,
"db.temp.index.dictionary.items": 0,
1166
"db.temp.index.dictionary.maxUpdateBeforeSave": 5000,
"db.temp.index.dictionary.optimizationThreshold": 100000,
"process.network.channel.binary./0:0:0:0:0:0:0:1:451822480.flushes": 0,
"process.network.channel.binary./0:0:0:0:0:0:0:1:451822480.receivedBytes": 513,
"process.network.channel.binary./0:0:0:0:0:0:0:1:451822480.transmittedBytes": 0,
"process.network.channel.binary./127.0.0.1:451282424.flushes": 3,
"process.network.channel.binary./127.0.0.1:451282424.receivedBytes": 98,
"process.network.channel.binary./127.0.0.1:451282424.transmittedBytes": 16,
"process.network.channel.binary./127.0.0.1:451292424.flushes": 3,
"process.network.channel.binary./127.0.0.1:451292424.receivedBytes": 72,
"process.network.channel.binary./127.0.0.1:451292424.transmittedBytes": 17,
"process.network.channel.binary./127.0.0.1:451352424.flushes": 3,
"process.network.channel.binary./127.0.0.1:451352424.receivedBytes": 79,
"process.network.channel.binary./127.0.0.1:451352424.transmittedBytes": 134,
"process.network.channel.binary./127.0.0.1:451362424.flushes": 3,
"process.network.channel.binary./127.0.0.1:451362424.receivedBytes": 105,
"process.network.channel.binary./127.0.0.1:451362424.transmittedBytes": 16,
"process.network.channel.binary./127.0.0.1:451382424.flushes": 3,
"process.network.channel.binary./127.0.0.1:451382424.receivedBytes": 79,
"process.network.channel.binary./127.0.0.1:451382424.transmittedBytes": 16,
"process.network.channel.binary./127.0.0.1:451392424.flushes": 3,
"process.network.channel.binary./127.0.0.1:451392424.receivedBytes": 79,
"process.network.channel.binary./127.0.0.1:451392424.transmittedBytes": 134,
"process.network.channel.binary./127.0.0.1:451402424.flushes": 3,
"process.network.channel.binary./127.0.0.1:451402424.receivedBytes": 105,
"process.network.channel.binary./127.0.0.1:451402424.transmittedBytes": 16,
"process.network.channel.binary./127.0.0.1:451422424.flushes": 3,
"process.network.channel.binary./127.0.0.1:451422424.receivedBytes": 79,
"process.network.channel.binary./127.0.0.1:451422424.transmittedBytes": 16,
"process.network.channel.binary./127.0.0.1:451432424.flushes": 3,
"process.network.channel.binary./127.0.0.1:451432424.receivedBytes": 72,
"process.network.channel.binary./127.0.0.1:451432424.transmittedBytes": 127,
"process.network.channel.binary./127.0.0.1:451442424.flushes": 3,
"process.network.channel.binary./127.0.0.1:451442424.receivedBytes": 98,
"process.network.channel.binary./127.0.0.1:451442424.transmittedBytes": 16,
"process.network.channel.binary./127.0.0.1:451452424.flushes": 3,
"process.network.channel.binary./127.0.0.1:451452424.receivedBytes": 72,
"process.network.channel.binary./127.0.0.1:451452424.transmittedBytes": 17,
"process.network.channel.binary./127.0.0.1:451462424.flushes": 7,
"process.network.channel.binary./127.0.0.1:451462424.receivedBytes": 194,
"process.network.channel.binary./127.0.0.1:451462424.transmittedBytes": 2606,
"process.network.channel.binary./127.0.0.1:451472424.flushes": 3,
"process.network.channel.binary./127.0.0.1:451472424.receivedBytes": 72,
"process.network.channel.binary./127.0.0.1:451472424.transmittedBytes": 127,
"process.network.channel.binary./127.0.0.1:451482424.flushes": 3,
"process.network.channel.binary./127.0.0.1:451482424.receivedBytes": 98,
"process.network.channel.binary./127.0.0.1:451482424.transmittedBytes": 16,
"process.network.channel.binary./127.0.0.1:451492424.flushes": 3,
"process.network.channel.binary./127.0.0.1:451492424.receivedBytes": 72,
"process.network.channel.binary./127.0.0.1:451492424.transmittedBytes": 17,
"process.network.channel.binary./127.0.0.1:451502424.flushes": 7,
"process.network.channel.binary./127.0.0.1:451502424.receivedBytes": 194,
"process.network.channel.binary./127.0.0.1:451502424.transmittedBytes": 2606,
"process.network.channel.binary./127.0.0.1:451512424.flushes": 3,
"process.network.channel.binary./127.0.0.1:451512424.receivedBytes": 72,
"process.network.channel.binary./127.0.0.1:451512424.transmittedBytes": 127,
"process.network.channel.binary./127.0.0.1:451522424.flushes": 3,
"process.network.channel.binary./127.0.0.1:451522424.receivedBytes": 98,
"process.network.channel.binary./127.0.0.1:451522424.transmittedBytes": 16,
1167
"process.network.channel.binary./127.0.0.1:451532424.flushes": 3,
"process.network.channel.binary./127.0.0.1:451532424.receivedBytes": 72,
"process.network.channel.binary./127.0.0.1:451532424.transmittedBytes": 17,
"process.network.channel.binary./127.0.0.1:451542424.flushes": 7,
"process.network.channel.binary./127.0.0.1:451542424.receivedBytes": 194,
"process.network.channel.binary./127.0.0.1:451542424.transmittedBytes": 2606,
"process.network.channel.binary./127.0.0.1:451552424.flushes": 3,
"process.network.channel.binary./127.0.0.1:451552424.receivedBytes": 72,
"process.network.channel.binary./127.0.0.1:451552424.transmittedBytes": 17,
"process.network.channel.binary./127.0.0.1:451562424.flushes": 3,
"process.network.channel.binary./127.0.0.1:451562424.receivedBytes": 72,
"process.network.channel.binary./127.0.0.1:451562424.transmittedBytes": 16,
"process.network.channel.binary./127.0.0.1:451572424.flushes": 3,
"process.network.channel.binary./127.0.0.1:451572424.receivedBytes": 72,
"process.network.channel.binary./127.0.0.1:451572424.transmittedBytes": 17,
"process.network.channel.binary./127.0.0.1:451582424.flushes": 3,
"process.network.channel.binary./127.0.0.1:451582424.receivedBytes": 72,
"process.network.channel.binary./127.0.0.1:451582424.transmittedBytes": 17,
"process.network.channel.binary./127.0.0.1:451592424.flushes": 3,
"process.network.channel.binary./127.0.0.1:451592424.receivedBytes": 72,
"process.network.channel.binary./127.0.0.1:451592424.transmittedBytes": 16,
"process.network.channel.binary./127.0.0.1:451602424.flushes": 3,
"process.network.channel.binary./127.0.0.1:451602424.receivedBytes": 72,
"process.network.channel.binary./127.0.0.1:451602424.transmittedBytes": 17,
"process.network.channel.binary./127.0.0.1:451612424.flushes": 3,
"process.network.channel.binary./127.0.0.1:451612424.receivedBytes": 72,
"process.network.channel.binary./127.0.0.1:451612424.transmittedBytes": 17,
"process.network.channel.binary./127.0.0.1:451622424.flushes": 3,
"process.network.channel.binary./127.0.0.1:451622424.receivedBytes": 72,
"process.network.channel.binary./127.0.0.1:451622424.transmittedBytes": 16,
"process.network.channel.binary./127.0.0.1:451632424.flushes": 3,
"process.network.channel.binary./127.0.0.1:451632424.receivedBytes": 72,
"process.network.channel.binary./127.0.0.1:451632424.transmittedBytes": 17,
"process.network.channel.binary./127.0.0.1:451642424.flushes": 3,
"process.network.channel.binary./127.0.0.1:451642424.receivedBytes": 72,
"process.network.channel.binary./127.0.0.1:451642424.transmittedBytes": 16,
"process.network.channel.binary./127.0.0.1:451652424.flushes": 3,
"process.network.channel.binary./127.0.0.1:451652424.receivedBytes": 98,
"process.network.channel.binary./127.0.0.1:451652424.transmittedBytes": 16,
"process.network.channel.binary./127.0.0.1:451672424.flushes": 3,
"process.network.channel.binary./127.0.0.1:451672424.receivedBytes": 72,
"process.network.channel.binary./127.0.0.1:451672424.transmittedBytes": 16,
"process.network.channel.binary./127.0.0.1:451682424.flushes": 3,
"process.network.channel.binary./127.0.0.1:451682424.receivedBytes": 98,
"process.network.channel.binary./127.0.0.1:451682424.transmittedBytes": 16,
"process.network.channel.binary./127.0.0.1:451692424.flushes": 3,
"process.network.channel.binary./127.0.0.1:451692424.receivedBytes": 72,
"process.network.channel.binary./127.0.0.1:451692424.transmittedBytes": 17,
"process.network.channel.binary./127.0.0.1:451702424.flushes": 76545,
"process.network.channel.binary./127.0.0.1:451702424.receivedBytes": 4937639,
"process.network.channel.binary./127.0.0.1:451702424.transmittedBytes": 53391585,
"process.network.channel.binary./127.0.0.1:451712424.flushes": 3,
"process.network.channel.binary./127.0.0.1:451712424.receivedBytes": 72,
"process.network.channel.binary./127.0.0.1:451712424.transmittedBytes": 17,
"process.network.channel.binary./127.0.0.1:451762424.flushes": 16176,
"process.network.channel.binary./127.0.0.1:451762424.receivedBytes": 435578,
"process.network.channel.binary./127.0.0.1:451762424.transmittedBytes": 7744941,
"process.network.channel.binary./127.0.0.1:451772424.flushes": 16181,
"process.network.channel.binary./127.0.0.1:451772424.receivedBytes": 446949,
1168
"process.network.channel.binary./127.0.0.1:451772424.transmittedBytes": 7932617,
"process.network.channel.binary./127.0.0.1:451782424.flushes": 16103,
"process.network.channel.binary./127.0.0.1:451782424.receivedBytes": 437708,
"process.network.channel.binary./127.0.0.1:451782424.transmittedBytes": 7192022,
"process.network.channel.binary./127.0.0.1:451792424.flushes": 15663,
"process.network.channel.binary./127.0.0.1:451792424.receivedBytes": 422013,
"process.network.channel.binary./127.0.0.1:451792424.transmittedBytes": 1128841,
"process.network.channel.binary.flushes": 140851,
"process.network.channel.binary.receivedBytes": 6687263,
"process.network.channel.binary.transmittedBytes": 77419866,
"process.runtime.availableMemory": 311502288,
"process.runtime.maxMemory": 939524096,
"process.runtime.totalMemory": 442368000,
"server.connections.actives": 101,
"system.config.cpus": 8,
"system.disk.C.freeSpace": 50445692928,
"system.disk.C.totalSpace": 127928365056,
"system.disk.C.usableSpace": 50445692928,
"system.disk.D.freeSpace": 0,
"system.disk.D.totalSpace": 0,
"system.disk.D.usableSpace": 0,
"system.disk.G.freeSpace": 12820815872,
"system.disk.G.totalSpace": 500103213056,
"system.disk.G.usableSpace": 12820815872,
"system.file.mmap.mappedPages": 177,
"system.file.mmap.nonPooledBufferUsed": 0,
"system.file.mmap.pooledBufferCreated": 0,
"system.file.mmap.pooledBufferUsed": 0,
"system.file.mmap.reusedPages": 31698774,
"system.memory.alerts": 0,
"system.memory.stream.resize": 21154
},
"chronos": {
"db.0$db.close": {
"entries": 4,
"last": 16,
"min": 0,
"max": 16,
"average": 4,
"total": 16
},
"db.0$db.create": {
"entries": 1,
"last": 13,
"min": 13,
"max": 13,
"average": 13,
"total": 13
},
"db.0$db.createRecord": {
"entries": 10,
"last": 1,
"min": 0,
"max": 1,
"average": 0,
"total": 6
},
"db.0$db.data.createHole": {
"entries": 14,
1169
"last": 2,
"min": 0,
"max": 2,
"average": 0,
"total": 8
},
"db.0$db.data.findClosestHole": {
"entries": 11,
"last": 0,
"min": 0,
"max": 0,
"average": 0,
"total": 0
},
"db.0$db.data.move": {
"entries": 6,
"last": 1,
"min": 0,
"max": 1,
"average": 0,
"total": 3
},
"db.0$db.data.recycled.notFound": {
"entries": 7,
"last": 0,
"min": 0,
"max": 0,
"average": 0,
"total": 0
},
"db.0$db.data.recycled.partial": {
"entries": 11,
"last": 0,
"min": 0,
"max": 0,
"average": 0,
"total": 0
},
"db.0$db.data.updateHole": {
"entries": 21,
"last": 0,
"min": 0,
"max": 1,
"average": 0,
"total": 2
},
"db.0$db.delete": {
"entries": 1,
"last": 101,
"min": 101,
"max": 101,
"average": 101,
"total": 101
},
"db.0$db.metadata.load": {
"entries": 3,
"last": 0,
"min": 0,
"max": 0,
1170
"average": 0,
"total": 0
},
"db.0$db.open": {
"entries": 3,
"last": 0,
"min": 0,
"max": 0,
"average": 0,
"total": 0
},
"db.0$db.readRecord": {
"entries": 15,
"last": 0,
"min": 0,
"max": 1,
"average": 0,
"total": 5
},
"db.0$db.updateRecord": {
"entries": 18,
"last": 2,
"min": 0,
"max": 2,
"average": 0,
"total": 9
},
"db.1$db.close": {
"entries": 4,
"last": 13,
"min": 0,
"max": 13,
"average": 3,
"total": 13
},
"db.1$db.create": {
"entries": 1,
"last": 15,
"min": 15,
"max": 15,
"average": 15,
"total": 15
},
"db.1$db.createRecord": {
"entries": 10,
"last": 1,
"min": 0,
"max": 1,
"average": 0,
"total": 5
},
"db.1$db.data.createHole": {
"entries": 14,
"last": 3,
"min": 0,
"max": 3,
"average": 0,
"total": 8
},
1171
"db.1$db.data.findClosestHole": {
"entries": 11,
"last": 0,
"min": 0,
"max": 0,
"average": 0,
"total": 0
},
"db.1$db.data.move": {
"entries": 6,
"last": 0,
"min": 0,
"max": 1,
"average": 0,
"total": 3
},
"db.1$db.data.recycled.notFound": {
"entries": 7,
"last": 0,
"min": 0,
"max": 0,
"average": 0,
"total": 0
},
"db.1$db.data.recycled.partial": {
"entries": 11,
"last": 0,
"min": 0,
"max": 0,
"average": 0,
"total": 0
},
"db.1$db.data.updateHole": {
"entries": 21,
"last": 1,
"min": 0,
"max": 1,
"average": 0,
"total": 1
},
"db.1$db.delete": {
"entries": 1,
"last": 115,
"min": 115,
"max": 115,
"average": 115,
"total": 115
},
"db.1$db.metadata.load": {
"entries": 3,
"last": 0,
"min": 0,
"max": 0,
"average": 0,
"total": 0
},
"db.1$db.open": {
"entries": 3,
"last": 0,
1172
"min": 0,
"max": 0,
"average": 0,
"total": 0
},
"db.1$db.readRecord": {
"entries": 15,
"last": 0,
"min": 0,
"max": 1,
"average": 0,
"total": 4
},
"db.1$db.updateRecord": {
"entries": 18,
"last": 3,
"min": 0,
"max": 3,
"average": 0,
"total": 7
},
"db.2$db.close": {
"entries": 4,
"last": 15,
"min": 0,
"max": 15,
"average": 3,
"total": 15
},
"db.2$db.create": {
"entries": 1,
"last": 17,
"min": 17,
"max": 17,
"average": 17,
"total": 17
},
"db.2$db.createRecord": {
"entries": 10,
"last": 1,
"min": 0,
"max": 1,
"average": 0,
"total": 5
},
"db.2$db.data.createHole": {
"entries": 14,
"last": 1,
"min": 0,
"max": 1,
"average": 0,
"total": 5
},
"db.2$db.data.findClosestHole": {
"entries": 11,
"last": 0,
"min": 0,
"max": 0,
"average": 0,
1173
"total": 0
},
"db.2$db.data.move": {
"entries": 6,
"last": 0,
"min": 0,
"max": 1,
"average": 0,
"total": 1
},
"db.2$db.data.recycled.notFound": {
"entries": 7,
"last": 0,
"min": 0,
"max": 0,
"average": 0,
"total": 0
},
"db.2$db.data.recycled.partial": {
"entries": 11,
"last": 0,
"min": 0,
"max": 0,
"average": 0,
"total": 0
},
"db.2$db.data.updateHole": {
"entries": 21,
"last": 0,
"min": 0,
"max": 1,
"average": 0,
"total": 1
},
"db.2$db.delete": {
"entries": 1,
"last": 61,
"min": 61,
"max": 61,
"average": 61,
"total": 61
},
"db.2$db.metadata.load": {
"entries": 3,
"last": 0,
"min": 0,
"max": 0,
"average": 0,
"total": 0
},
"db.2$db.open": {
"entries": 3,
"last": 0,
"min": 0,
"max": 0,
"average": 0,
"total": 0
},
"db.2$db.readRecord": {
1174
"entries": 15,
"last": 0,
"min": 0,
"max": 1,
"average": 0,
"total": 1
},
"db.2$db.updateRecord": {
"entries": 18,
"last": 1,
"min": 0,
"max": 1,
"average": 0,
"total": 5
},
"db.demo.close": {
"entries": 1396,
"last": 0,
"min": 0,
"max": 31,
"average": 0,
"total": 51
},
"db.demo.create": {
"entries": 3,
"last": 19,
"min": 19,
"max": 40,
"average": 27,
"total": 81
},
"db.demo.createRecord": {
"entries": 35716,
"last": 0,
"min": 0,
"max": 12,
"average": 0,
"total": 1187
},
"db.demo.data.createHole": {
"entries": 58886,
"last": 0,
"min": 0,
"max": 23,
"average": 0,
"total": 9822
},
"db.demo.data.findClosestHole": {
"entries": 51022,
"last": 0,
"min": 0,
"max": 1,
"average": 0,
"total": 181
},
"db.demo.data.move": {
"entries": 1327946,
"last": 0,
"min": 0,
1175
"max": 16,
"average": 0,
"total": 4091
},
"db.demo.data.recycled.complete": {
"entries": 24,
"last": 0,
"min": 0,
"max": 0,
"average": 0,
"total": 0
},
"db.demo.data.recycled.notFound": {
"entries": 16070,
"last": 0,
"min": 0,
"max": 1,
"average": 0,
"total": 59
},
"db.demo.data.recycled.partial": {
"entries": 57638,
"last": 0,
"min": 0,
"max": 1,
"average": 0,
"total": 102
},
"db.demo.data.updateHole": {
"entries": 108613,
"last": 0,
"min": 0,
"max": 12,
"average": 0,
"total": 451
},
"db.demo.delete": {
"entries": 2,
"last": 61,
"min": 61,
"max": 124,
"average": 92,
"total": 185
},
"db.demo.deleteRecord": {
"entries": 12362,
"last": 0,
"min": 0,
"max": 24,
"average": 0,
"total": 4626
},
"db.demo.metadata.load": {
"entries": 1423,
"last": 0,
"min": 0,
"max": 1,
"average": 0,
"total": 49
1176
},
"db.demo.open": {
"entries": 1423,
"last": 0,
"min": 0,
"max": 1,
"average": 0,
"total": 6
},
"db.demo.readRecord": {
"entries": 476697,
"last": 0,
"min": 0,
"max": 16,
"average": 0,
"total": 3071
},
"db.demo.synch": {
"entries": 484,
"last": 2,
"min": 0,
"max": 34,
"average": 2,
"total": 1251
},
"db.demo.updateRecord": {
"entries": 180667,
"last": 0,
"min": 0,
"max": 12,
"average": 0,
"total": 2343
},
"db.subTest.close": {
"entries": 10,
"last": 0,
"min": 0,
"max": 16,
"average": 3,
"total": 31
},
"db.subTest.create": {
"entries": 2,
"last": 44,
"min": 18,
"max": 44,
"average": 31,
"total": 62
},
"db.subTest.createRecord": {
"entries": 20,
"last": 1,
"min": 0,
"max": 1,
"average": 0,
"total": 11
},
"db.subTest.data.createHole": {
"entries": 28,
1177
"last": 2,
"min": 0,
"max": 2,
"average": 0,
"total": 12
},
"db.subTest.data.findClosestHole": {
"entries": 22,
"last": 0,
"min": 0,
"max": 1,
"average": 0,
"total": 1
},
"db.subTest.data.move": {
"entries": 12,
"last": 0,
"min": 0,
"max": 1,
"average": 0,
"total": 4
},
"db.subTest.data.recycled.notFound": {
"entries": 14,
"last": 0,
"min": 0,
"max": 0,
"average": 0,
"total": 0
},
"db.subTest.data.recycled.partial": {
"entries": 22,
"last": 0,
"min": 0,
"max": 0,
"average": 0,
"total": 0
},
"db.subTest.data.updateHole": {
"entries": 42,
"last": 0,
"min": 0,
"max": 1,
"average": 0,
"total": 2
},
"db.subTest.delete": {
"entries": 2,
"last": 118,
"min": 76,
"max": 118,
"average": 97,
"total": 194
},
"db.subTest.metadata.load": {
"entries": 6,
"last": 0,
"min": 0,
"max": 1,
1178
"average": 0,
"total": 1
},
"db.subTest.open": {
"entries": 6,
"last": 0,
"min": 0,
"max": 0,
"average": 0,
"total": 0
},
"db.subTest.readRecord": {
"entries": 30,
"last": 0,
"min": 0,
"max": 1,
"average": 0,
"total": 3
},
"db.subTest.updateRecord": {
"entries": 36,
"last": 2,
"min": 0,
"max": 2,
"average": 0,
"total": 16
},
"db.temp.createRecord": {
"entries": 10,
"last": 0,
"min": 0,
"max": 1,
"average": 0,
"total": 2
},
"db.temp.readRecord": {
"entries": 7,
"last": 0,
"min": 0,
"max": 1,
"average": 0,
"total": 1
},
"db.temp.updateRecord": {
"entries": 21,
"last": 0,
"min": 0,
"max": 1,
"average": 0,
"total": 2
},
"process.file.mmap.commitPages": {
"entries": 2034,
"last": 1,
"min": 0,
"max": 21,
"average": 0,
"total": 1048
},
1179
"process.mvrbtree.clear": {
"entries": 16007,
"last": 0,
"min": 0,
"max": 1,
"average": 0,
"total": 141
},
"process.mvrbtree.commitChanges": {
"entries": 165235,
"last": 0,
"min": 0,
"max": 55,
"average": 0,
"total": 5730
},
"process.mvrbtree.entry.fromStream": {
"entries": 5408,
"last": 0,
"min": 0,
"max": 1,
"average": 0,
"total": 45
},
"process.mvrbtree.entry.toStream": {
"entries": 60839,
"last": 0,
"min": 0,
"max": 26,
"average": 0,
"total": 3013
},
"process.mvrbtree.fromStream": {
"entries": 7424,
"last": 0,
"min": 0,
"max": 1,
"average": 0,
"total": 54
},
"process.mvrbtree.get": {
"entries": 97863,
"last": 0,
"min": 0,
"max": 1,
"average": 0,
"total": 233
},
"process.mvrbtree.put": {
"entries": 151070,
"last": 0,
"min": 0,
"max": 55,
"average": 0,
"total": 5002
},
"process.mvrbtree.putAll": {
"entries": 1847,
"last": 0,
1180
"min": 0,
"max": 8,
"average": 0,
"total": 84
},
"process.mvrbtree.remove": {
"entries": 41000,
"last": 0,
"min": 0,
"max": 10,
"average": 0,
"total": 2226
},
"process.mvrbtree.toStream": {
"entries": 124870,
"last": 0,
"min": 0,
"max": 6,
"average": 0,
"total": 543
},
"process.mvrbtree.unload": {
"entries": 7424,
"last": 0,
"min": 0,
"max": 10,
"average": 0,
"total": 519
},
"process.serializer.record.string.binary2string": {
"entries": 1867,
"last": 0,
"min": 0,
"max": 1,
"average": 0,
"total": 18
},
"process.serializer.record.string.bool2string": {
"entries": 43,
"last": 0,
"min": 0,
"max": 0,
"average": 0,
"total": 0
},
"process.serializer.record.string.byte2string": {
"entries": 1143,
"last": 0,
"min": 0,
"max": 0,
"average": 0,
"total": 0
},
"process.serializer.record.string.date2string": {
"entries": 114176,
"last": 0,
"min": 0,
"max": 6,
"average": 0,
1181
"total": 464
},
"process.serializer.record.string.datetime2string": {
"entries": 2,
"last": 0,
"min": 0,
"max": 0,
"average": 0,
"total": 0
},
"process.serializer.record.string.decimal2string": {
"entries": 2,
"last": 1,
"min": 0,
"max": 1,
"average": 0,
"total": 1
},
"process.serializer.record.string.double2string": {
"entries": 30237,
"last": 0,
"min": 0,
"max": 1,
"average": 0,
"total": 104
},
"process.serializer.record.string.embed2string": {
"entries": 122581,
"last": 0,
"min": 0,
"max": 1,
"average": 0,
"total": 117
},
"process.serializer.record.string.embedList2string": {
"entries": 29922,
"last": 0,
"min": 0,
"max": 2,
"average": 0,
"total": 87
},
"process.serializer.record.string.embedMap2string": {
"entries": 3160,
"last": 0,
"min": 0,
"max": 1,
"average": 0,
"total": 25
},
"process.serializer.record.string.embedSet2string": {
"entries": 32280,
"last": 1,
"min": 0,
"max": 8,
"average": 0,
"total": 1430
},
"process.serializer.record.string.float2string": {
1182
"entries": 20640,
"last": 0,
"min": 0,
"max": 1,
"average": 0,
"total": 63
},
"process.serializer.record.string.fromStream": {
"entries": 1735665,
"last": 0,
"min": 0,
"max": 82,
"average": 0,
"total": 7174
},
"process.serializer.record.string.int2string": {
"entries": 246700,
"last": 0,
"min": 0,
"max": 1,
"average": 0,
"total": 101
},
"process.serializer.record.string.link2string": {
"entries": 18664,
"last": 0,
"min": 0,
"max": 6,
"average": 0,
"total": 62
},
"process.serializer.record.string.linkList2string": {
"entries": 2648,
"last": 0,
"min": 0,
"max": 2,
"average": 0,
"total": 52
},
"process.serializer.record.string.linkMap2string": {
"entries": 28,
"last": 0,
"min": 0,
"max": 1,
"average": 0,
"total": 1
},
"process.serializer.record.string.linkSet2string": {
"entries": 1269,
"last": 0,
"min": 0,
"max": 33,
"average": 0,
"total": 80
},
"process.serializer.record.string.long2string": {
"entries": 1620,
"last": 0,
"min": 0,
1183
"max": 1,
"average": 0,
"total": 6
},
"process.serializer.record.string.string2string": {
"entries": 358585,
"last": 0,
"min": 0,
"max": 3,
"average": 0,
"total": 183
},
"process.serializer.record.string.toStream": {
"entries": 183912,
"last": 0,
"min": 0,
"max": 34,
"average": 0,
"total": 3149
},
"server.http.0:0:0:0:0:0:0:1.request": {
"entries": 2,
"last": 2,
"min": 2,
"max": 19,
"average": 10,
"total": 21
}
},
"statistics": {},
"counters": {
"db.0$db.cache.level2.cache.found": 7,
"db.0$db.cache.level2.cache.notFound": 8,
"db.0$db.data.update.notReused": 11,
"db.0$db.data.update.reusedAll": 7,
"db.1$db.cache.level2.cache.found": 7,
"db.1$db.cache.level2.cache.notFound": 8,
"db.1$db.data.update.notReused": 11,
"db.1$db.data.update.reusedAll": 7,
"db.2$db.cache.level2.cache.found": 7,
"db.2$db.cache.level2.cache.notFound": 8,
"db.2$db.data.update.notReused": 11,
"db.2$db.data.update.reusedAll": 7,
"db.demo.cache.level2.cache.found": 364467,
"db.demo.cache.level2.cache.notFound": 393509,
"db.demo.data.update.notReused": 38426,
"db.demo.data.update.reusedAll": 140921,
"db.demo.data.update.reusedPartial": 100,
"db.demo.query.compositeIndexUsed": 46,
"db.demo.query.compositeIndexUsed.2": 42,
"db.demo.query.compositeIndexUsed.2.1": 20,
"db.demo.query.compositeIndexUsed.2.2": 18,
"db.demo.query.compositeIndexUsed.3": 4,
"db.demo.query.compositeIndexUsed.3.1": 1,
"db.demo.query.compositeIndexUsed.3.2": 1,
"db.demo.query.compositeIndexUsed.3.3": 2,
"db.demo.query.indexUsed": 2784,
"db.subTest.cache.level2.cache.found": 14,
"db.subTest.cache.level2.cache.notFound": 16,
1184
"db.subTest.data.update.notReused": 22,
"db.subTest.data.update.reusedAll": 14,
"db.temp.cache.level2.cache.found": 5,
"db.temp.cache.level2.cache.notFound": 4,
"process.file.mmap.pagesCommitted": 2034,
"process.mvrbtree.entry.serializeKey": 4617509,
"process.mvrbtree.entry.serializeValue": 68620,
"process.mvrbtree.entry.unserializeKey": 6127,
"process.mvrbtree.entry.unserializeValue": 225,
"process.serializer.record.string.linkList2string.cached": 19,
"server.http.0:0:0:0:0:0:0:1.requests": 3,
"server.http.0:0:0:0:0:0:0:1.timeout": 1
}
}
}
1185
ETL
The OrientDB-ETL module is an amazing tool to move data from and to OrientDB by
executing an ETL process. It's super easy to use. OrientDB ETL is based on the
following principles:
1186
How ETL works
Example of a process that extract from a CSV file, apply some change, lookup if the
record has already been created and then store the record as document against
OrientDB database:
+-----------+-----------------------+-----------+
| | PIPELINE |
+ EXTRACTOR +-----------------------+-----------+
| | TRANSFORMERS | LOADER |
+-----------+-----------------------+-----------+
| FILE ==> CSV->FIELD->MERGE ==> OrientDB |
+-----------+-----------------------+-----------+
The pipeline, made of transformation and loading phases, can run in parallel by setting
the configuration {"parallel":true} .
1187
Installation
Starting from OrientDB v2.0 the ETL module will be distributed in bundle with the official
release. If you want to use it, then follow these steps:
1188
Usage
$ cd $ORIENTDB_HOME/bin
$ ./oetl.sh config-dbpedia.json
1189
Available Components
Blocks
Sources
Extractors
Transformers
Loaders
Examples:
1190
ETL - Configuration
One of the most important OrientDB-ETL module features is the simplicity to configure
complex ETL processed, just by working to a single JSON file.
config, to manage all the settings and context's variables used by any component
of the process
source, to manage the source to process
begin, as a list of Blocks to execute in order. This section is executed when the
process begins
extractor, contains the Extractor configuration
transformers, contains the list of Transformers configuration to execute in pipeline
loader, contains the Loader configuration
end, as a list of Blocks to execute in order. This section is executed when the
process is finished
1191
Syntax
{
"config": {
<name>: <value>
},
"begin": [
{ <block-name>: { <configuration> } }
],
"source" : {
{ <source-name>: { <configuration> } }
},
"extractor" : {
{ <extractor-name>: { <configuration> } }
},
"transformers" : [
{ <transformer-name>: { <configuration> } }
],
"loader" : { <loader-name>: { <configuration> } },
"end": [
{ <block-name>: { <configuration> } }
]
}
Example:
{
"config": {
"log": "debug",
"fileDirectory": "/temp/databases/dbpedia_csv/",
"fileName": "Person.csv.gz"
},
"begin": [
{ "let": { "name": "$filePath", "value": "$fileDirectory.append( $fileName )"} },
{ "let": { "name": "$className", "value": "$fileName.substring( 0, $fileName.indexOf(".") )"
],
"source" : {
"file": { "path": "$filePath", "lock" : true }
},
"extractor" : {
"row": {}
},
"transformers" : [
{ "csv": { "separator": ",", "nullValue": "NULL", "skipFrom": 1, "skipTo": 3 } },
{ "merge": { "joinFieldName":"URI", "lookup":"V.URI" } },
{ "vertex": { "class": "$className"} }
],
"loader" : {
"orientdb": {
"dbURL": "plocal:/temp/databases/dbpedia",
"dbUser": "admin",
"dbPassword": "admin",
1192
"dbAutoCreate": true,
"tx": false,
"batchCommit": 1000,
"dbType": "graph",
"indexes": [{"class":"V", "fields":["URI:string"], "type":"UNIQUE" }]
}
}
}
1193
Generic rules
context variables can be used by prefixing them with $
$input is the context variable assigned before each transformation
to execute an expression using OrientDB SQL, use ={<expression>} , example: =
{eval('3 * 5')}
1194
Conditional execution
All executable blocks, like Transformers and Blocks, can be executed only if a condition
is true by using the if conditional expression using the OrientDB SQL syntax. Example:
{ "let": {
"name": "path",
"value": "C:/Temp",
"if": "${os.name} = 'Windows'"
}
},
{ "let": {
"name": "path",
"value": "/tmp",
"if": "${os.name}.indexOf('nux')"
}
}
`
1195
Log setting
Most of the blocks, like Transformers and Blocks, supports the log setting. Log can be
one of the following values (case insensitive): [NONE, ERROR, INFO, DEBUG] . By default is
INFO .
Set the log level to DEBUG to display more information on execution. Remember that
logging slows down execution, so use it only for development and debug purpose.
Example:
{ "http": {
"url": "http://ip.jsontest.com/",
"method": "GET",
"headers": {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_4) AppleWebKit/537.36 (KHTML, like Gecko
},
"log": "DEBUG"
}
}
1196
Configuration variables
All the variables declared in "config" block are bound in the execution context and can
be used by ETL processing.
Default
Variable Description Type Mandatory value
Maximum number of
retries in case the
maxRetries loader raises a integer false 10
ONeedRetryException:
concurrent modification
of the same records
Executes pipelines in
parallel parallel by using all the boolean false false
available cores
1197
ETL - BLocks
Block components execute operations.
1198
Available Blocks
let
Syntax
Expression in OrientDB
expression SQL language, to evaluate string false -
and assign
Example
Concats the $fileName variable to $fileDirectory to create the new variable $filePath:
code
Execute a snippet of code in any of the JVM supported languages. Default is Javascript.
1199
Syntax
Programming language
language used string false Javascript
Example
Console
Syntax
Example
{ "console": {
"commands": [
"CONNECT plocal:/temp/db/mydb admin admin",
1200
"INSERT INTO Account set name = 'Luca'"
] }
}
1201
ETL - Sources
Source components represent the source where to extract the content. Source is
optional, some Extractor like JDBCExtractor works without a source.
1202
Available Sources
File
Represents a source file where to start reading. Files can be text files or compressed
with tar.gz.
Syntax
Example
Input
Extracts data from console input. This is useful when the ETL works in PIPE with other
tools
Syntax
1203
Example
HTTP
Syntax
HTTP Method
between "GET",
method "POST", "PUT", String false GET
"DELETE", "HEAD",
"OPTIONS", "TRACE"
Request headers as
headers inner document Document false
key/value
Example
Execute a HTTP request against the URL "http://ip.jsontest.com/" in GET setting the
User-Agent in headers:
{ "http": {
"url": "http://ip.jsontest.com/",
"method": "GET",
"headers": {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_4) AppleWebKit/537.36 (KHTML, like Gecko
}
}
}
1204
ETL - Extractors
Extractor components are the first part of the ETL process responsible of extracting
data.
1205
Available Extractors
row
Syntax
Example
{ "row": {} }
JDBC
Extracts data from any DBMS that support JDBC driver. In order to get the ETL
component to connect to the source database, put the DBMS's JDBC driver in the
classpath or $ORIENTDB_HOME/lib directory.
Syntax
1206
userPassword DBMS User password string true -
Example
Extracts all the Client from the MySQL database "test" hosted on localhost:
{ "jdbc": {
"driver": "com.mysql.jdbc.Driver",
"url": "jdbc:mysql://localhost/test",
"userName": "root",
"userPassword": "",
"query": "select * from Client"
}
}
json
Extracts content by parsing json objects. If the content has more json items must be
enclosed between [].
Syntax
Example
{ "json": {} }
1207
ETL Transformers
Transformer components are executed in pipeline. They work against the received input
returning an output.
Before the execution, the $input variable is always assigned, so you can get at run-time
and use if needed.
1208
Available Transformers
CSV
Component description.
Syntax
Columns are
columnsOnFirstLine described in boolean false true
the first line
Columns array
containing
names, and
optionally types
by postfixing
columns string[] false -
names with :.
Specifying type
guarantee
better
performance
value to
consider as
nullValue NULL. Default string false -
is not declared
String
stringCharacter character char false "
delimiter
Line number
skipFrom where start to integer true -
1209
skip
Line number
skipTo where skip integer true -
ends
Example
1210
FIELD
Execute a SQL transformation against a field.
Component description.
Syntax
Expression to evaluate.
expression You can use OrientDB string true -
SQL syntax
Operation to execute
operation against the field: set, string false set
remove. Default is set
Save the
vertex/edge/document
save right after the setting of boolean false false
the field
Examples
Transforms the field 'class' into the ODocument's class by prefixing it with '_':
1211
Assigns to the "name" field the last part of a path:
MERGE
Merges input ODocument with another one, loaded by a lookup. Lookup can be a lookup
against an index or a SELECT query.
Component description.
Syntax
Default
Parameter Description Type Mandatory value
Field name
joinFieldName where the string true -
join value is
saved
Can be the
index name
where to
lookup execute the string true -
lookup, or a
SELECT
query
1212
Action to
execute in
case the
JOIN hasn't
been
resolved.
Actions can
be:
'NOTHING'
unresolvedLinkAction (do nothing), string false NOTHING
WARNING
(increment
warnings),
ERROR
(increment
errors), HALT
(interrupt the
process),
SKIP (skip
current row).
Example
Merges current record against the record returned by the lookup on index "V.URI" with
the value contained in the field "URI" of the input's document:
VERTEX
Component description.
Syntax
Vertices with
1213
duplicate keys are
skipped. If
skipDuplicates:true
skipDuplicates and a UNIQUE boolean false false
constraint is defined
on vertices ETL will
ignore it with no
exceptions.
Available v. 2.1
Example
EDGE
Transform a JOIN value in one or more EDGEs between current vertex and all the
vertices returned by the lookup. Lookup can be a lookup against an index or a SELECT
query.
Component description.
Syntax
Default
Parameter Description Type Mandatory value
Field name
joinFieldName where the string true -
join value is
saved
Edge
direction direction string false 'out'
Edge's class
class string false 'E'
name
Can be the
index name
1214
where to
lookup execute the string true -
lookup, or a
SELECT
query
Action to
execute in
case the
JOIN hasn't
been
resolved.
Actions can
be:
'NOTHING'
(do nothing),
CREATE
(create a
OrientVertex
unresolvedLinkAction setting as string false NOTHING
primary key
the join
value),
WARNING
(increment
warnings),
ERROR
(increment
errors), HALT
(interrupt the
process),
SKIP (skip
current row).
Example
Creates an EDGE from the current vertex, with class "Parent", to all the vertices returned
by the lookup on "D.inode" index with the value contained in the field "inode_parent" of
the input's vertex:
SKIP
Component description.
1215
Supported inputs types: [ODocument, OrientVertex]
Output: same type as input
Syntax
SQL expression to
expression evaluate. If true the current string true -
execution is skipped
Example
CODE
Component description.
Syntax
Default
Parameter Description Mandatory value
1216
code Code to execute string true -
Example
LINK
Transform a JOIN value in LINK in current record with the result of the lookup. Lookup
can be a lookup against an index or a SELECT query.
Component description.
Syntax
Field name
joinFieldName where the string false -
join value is
saved
Value to
joinValue lookup string false -
Field name
linkFieldName containing string true -
the link to set
Type of link
between:
linkFieldType LINK, string true -
LINKSET and
LINKLIST
Can be the
index name
where to
1217
lookup execute the string true -
lookup, or a
SELECT
query
Action to
execute in
case the
JOIN hasn't
been
resolved.
Actions can
be:
'NOTHING'
(do nothing),
CREATE
(create a
ODocument
unresolvedLinkAction setting as string false NOTHING
primary key
the join
value),
WARNING
(increment
warnings),
ERROR
(increment
errors), HALT
(interrupt the
process),
SKIP (skip
current row).
Example
Transform a JOIN value in LINK in current record (set as "parent" of type LINK) with the
result of the lookup on index "D.inode" with the value contained in the field
"inode_parent" of the input's document:
LOG
Component description.
1218
Supported inputs types: [Any]
Output: Any
Syntax
Example
{ "log": {} }
Block
Component description.
Syntax
Block to
block execute document true -
1219
Example
{ "block": {
"let": {
"name": "id",
"value": "={eval('$input.amount * 2')}"
}
}
}
Command
Executes a command.
Component description.
Syntax
Command language.
language Available are: sql (default) string false sql
and gremlin
Example
{
"command" : {
"command" : "select from E where id = ${edgeid}",
"output" : "edge"
}
}
1220
ETL - Loaders
Loader components are the last part of the ETL process responsible of the saving of
records.
1221
Available Loaders
Output OrientDB
Output
It's the default Loader. It prints the transformation result to the console output.
OrientDB
Syntax
If the database
dbAutoCreate not exists, create boolean false true
it automatically
With transactions
enabled, commit
every X entries.
1222
batchCommit Use this to avoid integer false 0
having one huge
transaction in
memory
Database type,
dbType between 'graph' string false document
or 'document'
Contains the
indexes used on
ETL process.
Before starting
any declared
index not present
in database will inner
indexes be created document false -
automatically.
Index
configuration
must have "type",
"class" and
"fields"
Example
"orientdb": {
"dbURL": "plocal:/temp/databases/dbpedia",
"dbUser": "importer",
"dbPassword": "IMP",
"dbAutoCreate": true,
"tx": false,
"batchCommit": 1000,
"wal" : false,
"dbType": "graph",
"indexes": [{"class":"V", "fields":["URI:string"], "type":"UNIQUE" }]
}
1223
Import from a CSV file to a Graph
This example describes the process for importing from a CSV file into OrientDB as a
Graph. For the sake of simplicity, consider only these 2 entities:
POST
COMMENT
Where the relationship is between Post and Comment as One-2-Many. One Post can
have multiple Comments. We're representing them as they would appear in a RDBMS,
but the source could be anything.
TABLE POST:
+----+----------------+
| id | title |
+----+----------------+
| 10 | NoSQL movement |
| 20 | New OrientDB |
+----+----------------+
TABLE COMMENT:
+----+--------+--------------+
| id | postId | text |
+----+--------+--------------+
| 0 | 10 | First |
| 1 | 10 | Second |
| 21 | 10 | Another |
| 41 | 20 | First again |
| 82 | 20 | Second Again |
+----+--------+--------------+
With an RDBMS, one-2-many references are inverted from the target table (Comment)
to the source one (Post). This is due to the inability of an RDBMS to handle a collection
of values.
In comparison, using the OrientDB Graph model, relationships are modeled as you think
when you design an application: POSTs have edges to COMMENTs.
1224
With OrientDB, the Graph model uses Edges to manage relationships:
1225
(1) Export to CSV
If you're using an RDBMS or any other source, export your data in CSV format. The ETL
module is also able to extract from JSON and an RDBMS directly through JDBC drivers.
However, for the sake of simplicity, in this example we're going to use CSV as the
source format.
File posts.csv
id,title
10,NoSQL movement
20,New OrientDB
File comments.csv
comments.csv file, containing all the comments, with the relationship to the commented
post
id,postId,text
0,10,First
1,10,Second
21,10,Another
41,20,First again
82,20,Second Again
1226
(2) ETL Configuration
The OrientDB ETL tool requires only a JSON file to define the ETL process as Extractor,
a list of Transformers to be executed in the pipeline, and a Loader, to load graph
elements into the OrientDB database.
Below are 2 files containing the ETL to import Posts and Comments separately.
{
"source": { "file": { "path": "/temp/datasets/posts.csv" } },
"extractor": { "row": {} },
"transformers": [
{ "csv": {} },
{ "vertex": { "class": "Post" } }
],
"loader": {
"orientdb": {
"dbURL": "plocal:/temp/databases/blog",
"dbType": "graph",
"classes": [
{"name": "Post", "extends": "V"},
{"name": "Comment", "extends": "V"},
{"name": "HasComments", "extends": "E"}
], "indexes": [
{"class":"Post", "fields":["id:integer"], "type":"UNIQUE" }
]
}
}
}
The Loader contains all the information to connect to an OrientDB database. We have
used plocal because it's faster, but if you have an OrientDB server up & running, use
"remote:" instead. Note the classes and indexes declared in Loader. As soon as the
Loader is configured, the classes and indexes are created if they do not already exist.
We have created the index on the Post.id field to assure that there are no duplicates and
that the lookup on the created edges (see below) will be fast enough.
{
"source": { "file": { "path": "/temp/datasets/comments.csv" } },
"extractor": { "row": {} },
"transformers": [
1227
{ "csv": {} },
{ "vertex": { "class": "Comment" } },
{ "edge": { "class": "HasComments",
"joinFieldName": "postId",
"lookup": "Post.id",
"direction": "in"
}
}
],
"loader": {
"orientdb": {
"dbURL": "plocal:/temp/databases/blog",
"dbType": "graph",
"classes": [
{"name": "Post", "extends": "V"},
{"name": "Comment", "extends": "V"},
{"name": "HasComments", "extends": "E"}
], "indexes": [
{"class":"Post", "fields":["id:integer"], "type":"UNIQUE" }
]
}
}
}
This file is similar to the previous one, but the Edge transformer does the job. Since the
link found in the CSV goes in the opposite direction (Comment->Post), while we want to
model directly (Post->Comment), we used the direction "in" (default is always "out").
1228
(3) Run the ETL process
Now allow the ETL to run by executing both imports in sequence. Open a shell under the
OrientDB home directory, and execute the following steps:
$ cd bin
$ ./oetl.sh post.json
$ ./oetl.sh comment.json
Once both scripts execute successfully, you'll have your Blog imported into OrientDB as
a Graph!
1229
(4) Check the database
Open the database under the OrientDB console and execute the following commands to
check that the import is ok:
$ ./console.sh
----+-----+-------+----+------+-------+--------------
# |@RID |@CLASS |id |postId|text |in_HasComments
----+-----+-------+----+------+-------+--------------
0 |#12:0|Comment|0 |10 |First |[size=1]
1 |#12:1|Comment|1 |10 |Second |[size=1]
2 |#12:2|Comment|21 |10 |Another|[size=1]
----+-----+-------+----+------+-------+--------------
----+-----+-------+----+------+------------+--------------
# |@RID |@CLASS |id |postId|text |in_HasComments
----+-----+-------+----+------+------------+--------------
0 |#12:3|Comment|41 |20 |First again |[size=1]
1 |#12:4|Comment|82 |20 |Second Again|[size=1]
----+-----+-------+----+------+------------+--------------
1230
Import form JSON
If you are migrating from MongoDB or any other DBMS that exports data in JSON
format, the JSON extractor is what you need. For more information look also at: Import-
from-PARSE.
[
{
"name": "Joe",
"id": 1,
"friends": [2,4,5],
"enemies": [6]
},
{
"name": "Suzie",
"id": 2,
"friends": [1,4,6],
"enemies": [5,2]
}
]
Note that friends and enemies represents a relationship with nodes of the same type.
They are under form of array if IDs. This is what we need:
And this pipeline (log is at debug level to show all the messages):
{
"config": {
"log": "debug"
},
"source" : {
"file": { "path": "/tmp/database.json" }
},
"extractor" : {
"json": {}
},
"transformers" : [
1231
{ "merge": { "joinFieldName": "id", "lookup": "Account.id" } },
{ "vertex": { "class": "Account"} },
{ "edge": {
"class": "Friend",
"joinFieldName": "friends",
"lookup": "Account.id",
"unresolvedLinkAction": "CREATE"
} },
{ "edge": {
"class": "Enemy",
"joinFieldName": "enemies",
"lookup": "Account.id",
"unresolvedLinkAction": "CREATE"
} }
],
"loader" : {
"orientdb": {
"dbURL": "plocal:/tmp/databases/db",
"dbUser": "admin",
"dbPassword": "admin",
"dbAutoDropIfExists": true,
"dbAutoCreate": true,
"standardElementConstraints": false,
"tx": false,
"wal": false,
"batchCommit": 1000,
"dbType": "graph",
"classes": [{"name": "Account", "extends":"V"}, {"name": "Friend", "extends":"E"}, {"name
"indexes": [{"class":"Account", "fields":["id:integer"], "type":"UNIQUE_HASH_INDEX" }]
}
}
}
"standardElementConstraints": false,
In OrientDB Loader to allow importing the property "id". Without this option the Blueprints
standard would reject it because "id" is a reserved name.
1232
[orientdb] DEBUG - OrientDBLoader: created edge class 'Friend' extends 'E'
[orientdb] DEBUG orientdb: found 0 vertices in class 'null'
[orientdb] DEBUG - OrientDBLoader: created edge class 'Enemy' extends 'E'
[orientdb] DEBUG orientdb: found 0 vertices in class 'null'
[orientdb] DEBUG - OrientDBLoader: created property 'Account.id' of type: integer
[orientdb] DEBUG - OrientDocumentLoader: created index 'Account.id' type 'UNIQUE_HASH_INDEX' against Clas
[0:merge] DEBUG Transformer input: {name:Joe,id:1,friends:[3],enemies:[1]}
[0:merge] DEBUG joinValue=1, lookupResult=null
[0:merge] DEBUG Transformer output: {name:Joe,id:1,friends:[3],enemies:[1]}
[0:vertex] DEBUG Transformer input: {name:Joe,id:1,friends:[3],enemies:[1]}
[0:vertex] DEBUG Transformer output: v(Account)[#11:0]
[0:edge] DEBUG Transformer input: v(Account)[#11:0]
[0:edge] DEBUG joinCurrentValue=2, lookupResult=null
[0:edge] DEBUG created new vertex=Account#11:1{id:2} v1
[0:edge] DEBUG created new edge=e[#12:0][#11:0-Friend->#11:1]
[0:edge] DEBUG joinCurrentValue=4, lookupResult=null
[0:edge] DEBUG created new vertex=Account#11:2{id:4} v1
[0:edge] DEBUG created new edge=e[#12:1][#11:0-Friend->#11:2]
[0:edge] DEBUG joinCurrentValue=5, lookupResult=null
[0:edge] DEBUG created new vertex=Account#11:3{id:5} v1
[0:edge] DEBUG created new edge=e[#12:2][#11:0-Friend->#11:3]
[0:edge] DEBUG Transformer output: v(Account)[#11:0]
[0:edge] DEBUG Transformer input: v(Account)[#11:0]
[0:edge] DEBUG joinCurrentValue=6, lookupResult=null
[0:edge] DEBUG created new vertex=Account#11:4{id:6} v1
[0:edge] DEBUG created new edge=e[#13:0][#11:0-Enemy->#11:4]
[0:edge] DEBUG Transformer output: v(Account)[#11:0]
[1:merge] DEBUG Transformer input: {name:Suzie,id:2,friends:[3],enemies:[2]}
[1:merge] DEBUG joinValue=2, lookupResult=Account#11:1{id:2,in_Friend:[#12:0]} v2
[1:merge] DEBUG merged record Account#11:1{id:2,in_Friend:[#12:0],name:Suzie,friends:[3],enemies:[2]} v2
[1:merge] DEBUG Transformer output: Account#11:1{id:2,in_Friend:[#12:0],name:Suzie,friends:[3],enemies:[2
[1:vertex] DEBUG Transformer input: Account#11:1{id:2,in_Friend:[#12:0],name:Suzie,friends:[3],enemies:[2
[1:vertex] DEBUG Transformer output: v(Account)[#11:1]
[1:edge] DEBUG Transformer input: v(Account)[#11:1]
[1:edge] DEBUG joinCurrentValue=1, lookupResult=Account#11:0{name:Joe,id:1,friends:[3],enemies:[1],out_Fr
[1:edge] DEBUG created new edge=e[#12:3][#11:1-Friend->#11:0]
[1:edge] DEBUG joinCurrentValue=4, lookupResult=Account#11:2{id:4,in_Friend:[#12:1]} v2
[1:edge] DEBUG created new edge=e[#12:4][#11:1-Friend->#11:2]
[1:edge] DEBUG joinCurrentValue=6, lookupResult=Account#11:4{id:6,in_Enemy:[#13:0]} v2
[1:edge] DEBUG created new edge=e[#12:5][#11:1-Friend->#11:4]
[1:edge] DEBUG Transformer output: v(Account)[#11:1]
[1:edge] DEBUG Transformer input: v(Account)[#11:1]
[1:edge] DEBUG joinCurrentValue=5, lookupResult=Account#11:3{id:5,in_Friend:[#12:2]} v2
[1:edge] DEBUG created new edge=e[#13:1][#11:1-Enemy->#11:3]
[1:edge] DEBUG joinCurrentValue=2, lookupResult=Account#11:1{id:2,in_Friend:[#12:0],name:Suzie,friends:[3
[1:edge] DEBUG created new edge=e[#13:2][#11:1-Enemy->#11:1]
[1:edge] DEBUG Transformer output: v(Account)[#11:1]
END ETL PROCESSOR
+ extracted 2 entries (0 entries/sec) - 2 entries -> loaded 2 vertices (0 vertices/sec) Total time: 228ms
Once ready, let's open the database with Studio and this is the result:
1233
1234
ETL - Import from RDBMS
Most of DBMSs support JDBC driver. All you need is to gather the JDBC driver and put it
in classpath or simply in the $ORIENTDB_HOME/lib directory.
With the configuration below all the records from the table "Client" are imported in
OrientDB from MySQL database.
1235
Example importing a flat table
{
"config": {
"log": "debug"
},
"extractor" : {
"jdbc": { "driver": "com.mysql.jdbc.Driver",
"url": "jdbc:mysql://localhost/mysqlcrm",
"userName": "root",
"userPassword": "",
"query": "select * from Client" }
},
"transformers" : [
{ "vertex": { "class": "Client"} }
],
"loader" : {
"orientdb": {
"dbURL": "plocal:/temp/databases/orientdbcrm",
"dbAutoCreate": true
}
}
}
1236
Example loading records from 2 connected
tables
With this example we want to import a database that contains Blog posts in the following
tables:
Importing of Authors
{
"config": {
"log": "debug"
},
"extractor" : {
"jdbc": { "driver": "com.mysql.jdbc.Driver",
"url": "jdbc:mysql://localhost/mysql",
"userName": "root",
"userPassword": "",
"query": "select * from Author" }
},
"transformers" : [
{ "vertex": { "class": "Author"} }
],
"loader" : {
"orientdb": {
"dbURL": "plocal:/temp/databases/orientdb",
"dbAutoCreate": true
}
}
}
Importing of Posts
{
"config": {
"log": "debug"
},
"extractor" : {
"jdbc": { "driver": "com.mysql.jdbc.Driver",
"url": "jdbc:mysql://localhost/mysql",
"userName": "root",
"userPassword": "",
"query": "select * from Post" }
1237
},
"transformers" : [
{ "vertex": { "class": "Post"} },
{ "edge": { "class": "Wrote", "direction" : "in",
"joinFieldName": "author_id",
"lookup":"Author.id", "unresolvedLinkAction":"CREATE"} }
],
"loader" : {
"orientdb": {
"dbURL": "plocal:/temp/databases/orientdb",
"dbAutoCreate": true
}
}
}
Note the edge configuration has the direction as "in", that means starts from the Author
and finishes to Post.
1238
Import from DB-Pedia
DBPedia exports all the entities as GZipped CSV files. Features:
First line contains column names, second, third and forth has meta information we'll
skip (look at "skipFrom": 1, "skipTo": 3 in CSV transformer)
The vertex class name is created automatically based on file name, so we can use
the same file against any DBPedia file
The Primary Key is the "URI" field where it has been created a UNIQUE index (look
at "ORIENTDB" loader)
The "merge" transformer is used to allow to reimport or update any file without
generating duplicates
1239
Configuration
{
"config": {
"log": "debug",
"fileDirectory": "/temp/databases/dbpedia_csv/",
"fileName": "Person.csv.gz"
},
"begin": [
{ "let": { "name": "$filePath", "value": "$fileDirectory.append( $fileName )"} },
{ "let": { "name": "$className", "value": "$fileName.substring( 0, $fileName.indexOf('.') )"
],
"source" : {
"file": { "path": "$filePath", "lock" : true }
},
"extractor" : {
"row": {}
},
"transformers" : [
{ "csv": { "separator": ",", "nullValue": "NULL", "skipFrom": 1, "skipTo": 3 } },
{ "merge": { "joinFieldName":"URI", "lookup":"V.URI" } },
{ "vertex": { "class": "$className"} }
],
"loader" : {
"orientdb": {
"dbURL": "plocal:/temp/databases/dbpedia",
"dbUser": "admin",
"dbPassword": "admin",
"dbAutoCreate": true,
"tx": false,
"batchCommit": 1000,
"dbType": "graph",
"indexes": [{"class":"V", "fields":["URI:string"], "type":"UNIQUE" }]
}
}
}
1240
Import from Parse
Parse is a very popular BaaS (Backend as a Service), acquired by Facebook. Parse
uses MongoDB as database and allows to export the database in JSON format. The
format is an array of JSON object. Example:
[
{
"user": {
"__type": "Pointer",
"className": "_User",
"objectId": "Ldlskf4mfS"
},
"address": {
"__type": "Pointer",
"className": "Address",
"objectId": "lvkDfj4dmS"
},
"createdAt": "2013-11-15T18:15:59.336Z",
"updatedAt": "2014-02-27T23:47:00.440Z",
"objectId": "Ldk39fDkcj",
"ACL": {
"Lfo33mfDkf": {
"write": true
},
"*": {
"read": true
}
}
}, {
"user": {
"__type": "Pointer",
"className": "_User",
"objectId": "Lflfem3mFe"
},
"address": {
"__type": "Pointer",
"className": "Address",
"objectId": "Ldldjfj3dd"
},
"createdAt": "2014-01-01T18:04:02.321Z",
"updatedAt": "2014-01-23T20:12:23.948Z",
"objectId": "fkfj49fjFFN",
"ACL": {
"dlfnDJckss": {
"write": true
},
"*": {
"read": true
}
}
}
]
1241
Notes:
Each object has own objectId that identifies the object in the entire database.
Parse has the concept of class , like OrientDB
Links are similar to OrientDB RID (but it requires a costly JOIN to be traversed), but
made if an embedded object containing:
className as target class name
objectIf as target objectId
In order to import a PARSE file, you need to create the ETL configuration using JSON as
Extractor.
1242
Example
In this example we're going to import the file extracted from Parse containing all the
records of user class. Note the creation of class User in OrientDB that extends V
(Base Vertex class). We created an index against property User.objectId to use the
same ID as for Parse. If you execute this ETL importing multiple time, the record in
OrientDB will be updated thanks to the merge .
{
"config": {
"log": "debug"
},
"source" : {
"file": { "path": "/temp/parse-user.json", "lock" : true }
},
"extractor" : {
"json": {}
},
"transformers" : [
{ "merge": { "joinFieldName":"objectId", "lookup":"User.objectId" } },
{ "vertex": { "class": "User"} }
],
"loader" : {
"orientdb": {
"dbURL": "plocal:/temp/databases/parse",
"dbUser": "admin",
"dbPassword": "admin",
"dbAutoCreate": true,
"tx": false,
"batchCommit": 1000,
"dbType": "graph",
"classes": [
{"name": "User", "extends": "V"}
],
"indexes": [
{"class":"User", "fields":["objectId:string"], "type":"UNIQUE_HASH_INDEX" }
]
}
}
}
1243
Distributed Architecture
OrientDB can be distributed across different servers and used in different ways to
achieve the maximum of performance, scalability and robustness.
OrientDB uses the Hazelcast Open Source project to manage the clustering. Many of
the references in this page are linked to the Hazelcast official documentation to get more
information about such topic.
1244
Presentation
1
of
23
1245
Main topics
Distributed Architecture Lifecycle
Configure the Cluster of servers
Replication of databases
Sharding
Distributed Cache
Tutorial to setup a distributed database
1246
Creation of records (documents, vertices
and edges)
In distributed mode the RID is assigned with cluster locality. If you have class Customer
and 3 nodes (node1, node2, node3), you'll have these clusters:
So if you create a new Customer on node1, it will get the RID with cluster-id of
"customer" cluster: #15. The same operation on node2 will generate a RID with cluster-
id=16 and 17 on node3.
In this way RID never collides and each node can be a master on insertion without any
conflicts.
1247
Distributed transactions
Starting from v1.6, OrientDB supports distributed transactions. When a transaction is
committed, all the updated records are sent across all the servers, so each server is
responsible to commit the transaction. In case one or more nodes fail on commit, the
quorum is checked. If the quorum has been respected, then the failing nodes are aligned
to the winner nodes, otherwise all the nodes rollback the transaction.
During the distributed transaction, in case of rollback, there could be an amount of time
when the records appear changed before they are rollbacked.
1248
Limitations
OrientDB v 2.0.x has some limitations you should notice when you work in Distributed
Mode:
1249
Distributed Architecture Lifecycle
In OrientDB Distributed Architecture all the nodes are masters (Multi-Master), while in
most DBMS the replication works in Master-Slave mode where there is only one Master
node and N Slaves that are use only for reads or when the Master is down.
When start a OrientDB server in distributed mode ( bin/dserver.sh ) it looks for an existent
cluster. If exists the starting node joins the cluster, otherwise creates a new one. You
can have multiple clusters in your network, each cluster with a different "group name".
1250
Joining a cluster
Auto discovering
<hazelcast>
<network>
<port auto-increment="true">2434</port>
<join>
<multicast enabled="true">
<multicast-group>235.1.1.1</multicast-group>
<multicast-port>2434</multicast-port>
</multicast>
</join>
</network>
</hazelcast>
Direct IPs
Amazon EC2 Discovering
1251
For more information look at Hazelcast documentation about configuring network.
Security
To join a cluster the Server Node has to configure the cluster group name and password
in hazelcast.xml file. By default these information aren't encrypted. If you wan to encrypt
all the distributed messages, configure it in hazelcast.xml file:
<hazelcast>
...
<network>
...
<!--
Make sure to set enabled=true
Make sure this configuration is exactly the same on
all members
-->
<symmetric-encryption enabled="true">
<!--
encryption algorithm such as
DES/ECB/PKCS5Padding,
PBEWithMD5AndDES,
Blowfish,
DESede
-->
<algorithm>PBEWithMD5AndDES</algorithm>
<!-- salt value to use when generating the secret key -->
<salt>thesalt</salt>
<!-- pass phrase to use when generating the secret key -->
<password>thepass</password>
<!-- iteration count to use when generating the secret key -->
<iteration-count>19</iteration-count>
</symmetric-encryption>
</network>
...
</hazelcast>
All the nodes in the distributed cluster must have the same settings.
1252
For more information look at: Hazelcast Encryption.
You can have multiple OrientDB clusters in the same network, what identifies a cluster is
its name that must be unique in the network. By default OrientDB uses "orientdb", but
for security reasons change it to a different name and password. All the nodes in the
distributed cluster must have the same settings.
<hazelcast>
<group>
<name>orientdb</name>
<password>orientdb</password>
</group>
</hazelcast>
1253
Multiple clusters
Multiple clusters can coexist in the same network. Clusters can't see each others
because are isolated black boxes.
Every time a new Server Node joins or leaves the Cluster, the new Cluster configuration
is broadcasted to all the connected clients. Everybody knows the cluster layout and who
has a database!
1254
1255
Fail over management
When a Server Node becomes unreachable (because its crashed, network problems,
high load, etc.) the Cluster treats this event as if the Server Node left the cluster.
All the clients connected to the unreachable node will switch to another server
transparently without raising errors to the Application User Application doesnt know
what is happening!
1256
Re-distribute the updated configuration again
After the Server #2 left the Cluster the updated configuration is sent again to all the
connected clients.
Continue with:
Distributed Architecture
Replication
Tutorial to setup a distributed database
1257
Distributed Configuration
Look also at Replication and pages.
orientdb-server-config.xml
default-distributed-db-config.json
Asynchronous replication mode
hazelcast.xml
Cloud support
1258
orientdb-server-config.xml
To enable and configure the clustering between nodes, add and enable the
OHazelcastPlugin. This task is configured as a Server handler. The default
configuration is reported below.
File orientdb-server-config.xml:
<handler class="com.orientechnologies.orient.server.hazelcast.OHazelcastPlugin">
<parameters>
<!-- NODE-NAME. IF NOT SET IS AUTO GENERATED THE FIRST TIME THE SERVER RUN -->
<!-- <parameter name="nodeName" value="europe1" /> -->
<parameter name="enabled" value="true" />
<parameter name="configuration.db.default"
value="${ORIENTDB_HOME}/config/default-distributed-db-config.json" />
<parameter name="configuration.hazelcast"
value="${ORIENTDB_HOME}/config/hazelcast.xml" />
</parameters>
</handler>
Where:
Parameter Description
1259
default-distributed-db-config.json
This is the JSON file containing the default configuration for distributed databases. The
first time a database run in distributed version this file is copied in the database's folder,
then every time the cluster shape changes the database specific file is changed.
{
"autoDeploy": true,
"hotAlignment": false,
"executionMode": "undefined",
"readQuorum": 1,
"writeQuorum": 2,
"failureAvailableNodesLessQuorum": false,
"readYourWrites": true,
"clusters": {
"internal": {
},
"index": {
},
"*": {
"servers" : [ "<NEW_NODE>" ]
}
}
}
Where:
. It can be undefined to
let to the client to decide
per call execution if
synchronous (default) or
executionMode asynchronous. undefined
synchronous forces
synchronous mode, and
1260
asynchronous forces
asynchronous mode
On "read" operation
(record read, query and
traverse) is the number
of responses to be
readQuorum coherent before to send 1
the response to the
client. Set to 1 if you
don't want this check at
read time
1261
On "read" operation
(record read, query
and traverse) is the
number of responses
readQuorum to be coherent before 1
to send the response
to the client. Set to 1 if
you don't want this
check at read time
On "write" operation
(any write on
database) is the
number of responses
to be coherent before
to send the response
to the client. Set to 1 if
writeQuorum you don't want this 2
check at write time.
Suggested value is
N/2+1 where N is the
number of replicas. In
this way the quorum is
reached only if the
majority of nodes are
coherent
empty for
internal and
index
Is the array of servers clusters and
[ "
servers where to store the <NEW_NODE>"
records of cluster ] for cluster
*
representing
any cluster
"<NEW_NODE>" is a special tag that put any new joining node name in the array.
Default configuration
1262
In the default configuration all the record clusters are replicated but internal , index ,
because all the changes remain locally to each node (indexing is per node). Every node
that joins the cluster shares all the rest of the clusters ("*" settings). Since "readQuorum"
is 1 all the reads are executed on the first available node where the local node is
preferred if own the requested record. "writeQuorum" to 2 means that all the changes
are in at least 2 nodes. If available nodes are less then 2, no error is given because
"failureAvailableNodesLessQuorum" is false.
By default writeQuorum is 2. This means that it waits and checks the answer from at
least 2 nodes before to send the ACK to the client. If you've more then 2 nodes
configured, then starting from the 3rd node the response will be managed
asynchronously. You could also set this to 1 to have all the writes asynchronous.
1263
hazelcast.xml
A OrientDB cluster is composed by two or more servers that are the nodes of the
cluster. All the server nodes that want to be part of the same cluster must to define the
same Cluster Group. By default "orientdb" is the group name. Look at the default
config/hazelcast.xml configuration file reported below:
NOTE: Change the name and password of the group to prevent external nodes from
joining it!
Network configuration
<hazelcast>
...
<network>
<port auto-increment="true">2434</port>
<join>
<multicast enabled="true">
<multicast-group>235.1.1.1</multicast-group>
1264
<multicast-port>2434</multicast-port>
</multicast>
</join>
</network>
...
</hazelcast>
Manual IP
<hazelcast>
...
<network>
<port auto-increment="true">2434</port>
<join>
<multicast enabled="false">
<multicast-group>235.1.1.1</multicast-group>
<multicast-port>2434</multicast-port>
</multicast>
<tcp-ip enabled="true">
<member>europe0:2434</member>
<member>europe1:2434</member>
<member>usa0:2434</member>
<member>asia0:2434</member>
<member>192.168.1.0-7:2434</member>
</tcp-ip>
</join>
</network>
...
</hazelcast>
Cloud support
Since multicast is disabled on most of the Cloud stacks, you have to change the
config/hazelcast.xml configuration file based on the Cloud used.
Amazon EC2
OrientDB supports natively Amazon EC2 through the Hazelcast's Amazon discovery
plugin. In order to use it include also the hazelcast-cloud.jar library under the lib/
directory.
1265
<hazelcast>
...
<join>
<multicast enabled="false">
<multicast-group>235.1.1.1</multicast-group>
<multicast-port>2434</multicast-port>
</multicast>
<aws enabled="true">
<access-key>my-access-key</access-key>
<secret-key>my-secret-key</secret-key>
<region>us-west-1</region> <!-- optional, default is us-east-1 -->
<host-header>ec2.amazonaws.com</host-header> <!-- optional, default is ec2.amazonaws.
shouldn't be set as it will overrid
<security-group-name>hazelcast-sg</security-group-name> <!-- optional -->
<tag-key>type</tag-key> <!-- optional -->
<tag-value>hz-nodes</tag-value> <!-- optional -->
</aws>
</join>
...
</hazelcast>
For more information look at Hazelcast Config Amazon EC2 Auto Discovery.
1266
Asynchronous replication mode
In order to reduce the latency in WAN, the suggested configuration is to set
executionMode to "asynchronous". In asynchronous mode any operation is executed on
local node and then replicated. In this mode the client doesn't wait for the quorum across
all the servers, but receives the response immediately after the local node answer.
Example:
{
"autoDeploy": true,
"hotAlignment": false,
"executionMode": "asynchronous",
"readQuorum": 1,
"writeQuorum": 2,
"failureAvailableNodesLessQuorum": false,
"readYourWrites": true,
"clusters": {
"internal": {
},
"index": {
},
"*": {
"servers" : [ "<NEW_NODE>" ]
}
}
}
1267
Misc
Load balancing
The simplest and most powerful way to achieve load balancing seems to use some
hidden (to some) properties of DNS. The trick is to create a TXT record listing the
servers.
v=opf<version> (s=<hostname[:<port>]> )*
In this way if you open a database against the URL remote:dbservers.mydomain.com/demo the
OrientDB client library will try to connect to the address 192.168.0.101 port 2424. If the
connection fails, then the next address 192.168.0.133: port 3434 is tried.
OGlobalConfiguration.NETWORK_BINARY_DNS_LOADBALANCING_ENABLED.setValue(true);
1268
History
1.7
1269
Distributed Architecture Plugin
Java class: com.orientechnologies.orient.server.hazelcast.OHazelcastPlugin
1270
Introduction
This is part of Distributed Architecture. Configure a distributed clustered architecture.
This task is configured as a Server handler. The task can be configured easily by
changing these parameters:
<handler class="com.orientechnologies.orient.server.hazelcast.OHazelcastPlugin">
<parameters>
<!-- <parameter name="alias" value="europe1" /> -->
<parameter name="enabled" value="true" />
<parameter name="configuration.db.default" value="${ORIENTDB_HOME}/config/default-distributed-db
<parameter name="configuration.hazelcast" value="${ORIENTDB_HOME}/config/hazelcast.xml"
</parameters>
</handler>
1271
Replication
OrientDB supports the Multi Master replication. This means that all the nodes in the
cluster are Master and are able to read and write to the database. This allows to scale
up horizontally without bottlenecks like most of any other RDBMS and NoSQL solution
do.
1272
Sharing of database
In Distributed Architecture the replicated database must have he same name. When a
OrientDB Server is starting, sends the list of current databases (all the databases
located under $ORIENTDB_HOME/databases directory) to all the nodes in the cluster. If other
nodes have databases with the same name, a replication is automatically set.
If the database configuration has the setting "autoDeploy" : true , then the databases are
automatically deployed across the network to the other nodes as soon as they join the
cluster.
1273
1274
Server unreachable
In case a server becomes unreachable, the node is removed by database configuration
unless the setting "hotAlignment" : true . In this case all the new synchronization
messages are kept in a distributed queue.
As soon as the Server becomes online again, it starts the synchronization phase
(status=SYNCHRONIZING) by polling all the synchronization messages in the queue.
1275
Once the alignment is finished, the node becomes online (status=ONLINE) and the
replication continues like at the beginning.
1276
Further readings
Continue with:
Distributed Architecture
Distributed Sharding
Distributed database configuration
1277
Sharding
OrientDB supports sharding of data at class level, by using multiple clusters[clusters] per
per class, where each cluster has own list of server where data is replicated. From a
logical point of view all the records stored in clusters that are part of the same class, are
records of that class.
This means that OrientDB will consider any record/document/graph element in any of
such clusters as Clients (Client class relies on such clusters). In Distributed-
Architecture each cluster can be assigned to one or multiple server nodes.
1278
Multiple servers per cluster
You can assign each cluster to one or more servers. If more servers are enlisted the
records will be copied in all the servers. This is similar to what RAID stands for Disks.
The first server in the list will be the master server for that cluster.
This is an example of configuration where the Client class has been split in the 3 clusters
client_usa, client_europe and client_china, each one with different configuration:
1279
Configuration
In order to keep things simple, the entire OrientDB Distributed Configuration is stored on
a single JSON file. Example of distributed database configuration for (Multiple servers
per cluster)[Distributed-Sharding#Multiple-servers-per-cluster] use case:
{
"autoDeploy": true,
"hotAlignment": false,
"readQuorum": 1,
"writeQuorum": 2,
"failureAvailableNodesLessQuorum": false,
"readYourWrites": true,
"clusters": {
"internal": {
},
"index": {
},
"client_usa": {
"servers" : [ "usa", "europe" ]
},
"client_europe": {
"servers" : [ "europe" ]
},
"client_china": {
"servers" : [ "china", "usa", "europe" ]
},
"*": {
"servers" : [ "<NEW_NODE>" ]
}
}
}
1280
Cluster Locality
OrientDB automatically creates a new cluster per each class as soon as node joins the
distributed cluster. These cluster names have the node name as suffix: <class>_<node> .
Example: client_usa . When a node goes down, the clusters where the node was master
are reassigned to other servers. As soon as that node returns up and running, OrientDB
will reassign the previous clusters where it was master to the same node again following
the convention <class>_<node> .
This is defined as "Cluster Locality". The local node is always selected when a ne record
is created. This avoids conflicts and allow to insert record in parallel on multiple nodes.
This means also that in distributed mode you can't select the cluster selection strategy,
because "local" strategy is always injected to all the cluster automatically.
If you want to change permanently the mastership of clusters, rename the cluster with
the suffix of the node you want assign as master.
1281
CRUD Operations
In the configuration above, if a new Client record is created on node USA, then the
selected cluster will be client_usa , because it's the local cluster for class Client. Now,
client_usa is managed by both USA and CHINA nodes, so the "create record" operation
is sent to both "usa" (locally) and "china" nodes.
Updating and Deleting of records always involves all the nodes where the record is
stored. No matter the node that receive the update operation. If we update record
#13:22 that is stored on cluster 13 , namely client_china in the example above, then the
update is sent to nodes: "china", "usa", "europe".
Read records
If the local node has the requested record, the record is read directly from the storage. If
it's not present on local server, a forward is executed to any of the nodes that have the
requested record. This means a network call to between nodes.
In case of queries, OrientDB checks where the query target are located and send the
query to all the involved servers. This operation is equivalent to a Map-Reduce. If the
query target is 100% managed on local node, the query is simply executed on local node
without paying the cost of network call.
All the query works by aggregating the result sets from all the involved nodes.
Since local node (USA) already owns client_usa and client_china , 2/3 of data are local.
The missing 1/3 of data is in client_europe that is managed only by node "Europe". So
the query will be executed on local node "usa" and "Europe" providing the aggregated
result back to the client.
1282
select from cluster:client_china
In this case the local node (USA) is used, because client_china is hosted on local node.
1283
Map-Reduce
OrientDB supports Map/Reduce by using the OrientDB SQL. The Map/Reduce operation
is totally transparent to the developer. When a query involve multiple shards (clusters),
OrientDB executes the query against all the involved server nodes (Map operation) and
then merge the results (Reduce operation). Example:
In this case the query is executed across all the 3 nodes and then filtered again on
starting node.
1284
1285
Define the target cluster/shard
The application can decide where to insert a new Client by passing the cluster number
or name. Example:
If the node that executes this command is not the master of cluster client_usa , an
exception is thrown.
OrientVertex v = graph.addVertex("class:Client,cluster:client_usa");
v.setProperty("name", "Jay");
Limitation
1286
Indexes
All the indexes are managed locally to a server. This means that if a class is spanned
across 3 clusters on 3 different servers, each server will have own local indexes. By
executing a distributed query (Map/Reduce like) each server will use own indexes.
1287
Hot management of distributed
configuration
With Community Edition the distributed configuration cannot be changed at run-time but
you have to stop and restart all the nodes. Enterprise Edition allows to create and drop
new shards without stopping the distributed cluster.
By using Enterprise Edition and the Workbench, you can deploy the database to the new
server and defining the cluster to assign to it. In this example a new server "usa2" is
created where only the cluster client_usa will be copied. After the deployment, cluster
client_usa will be replicated against nodes "usa" and "usa2".
1288
Distributed Cache
OrientDB has own more Cache levels. When OrientDB runs in Distributed-Architecture,
each server has own cache. All the caches in each server are independent.
You can also have a shared cache among servers, by enabling the Hazelcast's 2nd level
cache. To enable it set the cache.level2.impl property in orientdb-dserver-config.xml file
with value com.orientechnologies.orient.server.hazelcast.OHazelcastCache:
Note that this will slow down massive insertion but will improve query and lookup
operations.
...
<properties>
<!-- Uses the Hazelcast distributed cache as 2nd level cache -->
<entry name="cache.level2.impl" value="com.orientechnologies.orient.server.hazelcast.OHazelcastCache"
</properties>
1289
Backup & Restore
OrientDB supports backup and restore operations like any RDBMS.
Backup executes a complete backup against the currently opened database. The
backup file is compressed using the ZIP algorithm. To restore the database use the
Restore Database command. Backup is much faster than Export Database. Look also to
Export Database and Import Database commands. Backup can be done automatically
by enabling the Automatic-Backup Server plugin.
1290
When to use backup and when export?
Backup does a consistent copy of database, all further write operations are locked
waiting to finish it. The database is in read-only mode during backup operation. If you
need an read/write database during backup setup a distributed cluster of nodes.
Export, instead, doesn't lock the database and allow concurrent writes during the export
process. This means the exported database could have changes executed during the
export.
1291
Backup database
Starting from v1.7.8, OrientDB comes with the script "backup.sh" under the "bin"
directory. This script executes the backup by using the console. Syntax:
Where:
Non-Blocking Backup
Same example like before, but against a remote database hosted on localhost:
For more information about LVM) and Copy On Write (COS) look at:
1292
Using the console
You can also use the console to execute a backup. Below the same backup like before,
but using the console.
1293
Restore database
Use the console to restore a database. Example:
1294
See also
Backup Database
Restore Database
Export Database
Import Database
Console-Commands
1295
Export & Import
OrientDB supports export and import operations like any RDBMS.
The Export command exports the current opened database to a file. The exported file is
in JSON format using the Export-Format. By default the file is compressed using the
GZIP algorithm. The Export/Import commands allow to migrate the database between
different releases of OrientDB without loosing data. If you receive an error about the
database version, export the database using the same version of OrientDB that has
generated the database.
Export doesn't lock your database, but browses it. This means that concurrent operation
can be executed during the export, but the exported database couldn't be the exact
replica when you issued the command because concurrent updates could occurs. If you
need a snapshot of database at a point in a time, please use Backup.
Once exported, use the Import to restore it. The database will be imported and will be
ready to be used. Look also to Backup Database and Restore Database commands.
1296
When to use backup and when export?
Backup does a consistent copy of database, all further write operations are locked
waiting to finish it. The database is in read-only mode during backup operation. If you
need an read/write database during backup setup a distributed cluster of nodes.
Export, instead, doesn't lock the database and allow concurrent writes during the export
process. This means the exported database could have changes executed during the
export.
1297
Export Example
1298
Import Example
1299
See also
Export-Format
Restore Database
Export Database
Import Database
Console-Commands
1300
Export format
This page contains the format used by Export Database and Import Database tools. The
file is 100% JSON compliant.
1301
See also
Export Database
Import Database
1302
Sections
Info Section
First section resuming the database information and all the version used to check
compatibility on import.
{
"info":{
"name": <database-name>,
"default-cluster-id": <default-cluster-id>,
"exporter-version": <exporter-format>,
"engine-version": <engine-version>,
"storage-config-version": <storage-version>,
"schema-version": <schema-version>,
"mvrbtree-version": <mvrbtree-version>
}
Example
{
"info":{
"name": "demo",
"default-cluster-id": 2,
"exporter-version": 2,
"engine-version": "1.7-SNAPSHOT",
"storage-config-version": 2,
"schema-version": 4,
"mvrbtree-version": 0
}
1303
Clusters Section
"clusters": [
{"name": <cluster-name>, "id": <cluster-id>, "type": <cluster-type>}
]
cluster-
name Name of cluster String
Example
"clusters": [
{"name": "internal", "id": 0, "type": "PHYSICAL"},
{"name": "index", "id": 1, "type": "PHYSICAL"},
{"name": "default", "id": 2, "type": "PHYSICAL"}
]
Schema Section
"schema":{
"version": <schema-version>,
"classes": [
{ "name": <class-name>,
"default-cluster-id": <default-cluster-id>,
"cluster-ids": [<cluster-ids>],
"properties": [
{ "name": <property-name>,
"type": <property-type>,
"mandatory": <property-is-mandatory>,
"not-null": <property-not-null> }
]
}
]
}
1304
Parameter Description JSON
Type
cluster-ids Array of cluster ids where the class records can be Array of
stored. The first is always the <default-cluster-id> Integer
property-
is- Is this property mandatory? true or false Boolean
mandatory
property-
not-null The property can't accept null? true or false Boolean
Example
"schema":{
"version": 210,
"classes": [
{"name": "Account", "default-cluster-id": 9, "cluster-ids": [9],
"properties": [
{"name": "binary", "type": "BINARY", "mandatory": false, "not-null": false},
{"name": "birthDate", "type": "DATE", "mandatory": false, "not-null": false},
{"name": "id", "type": "INTEGER", "mandatory": false, "not-null": false}
]
}
]
}
Records Section
"records": [
{
"@type": <record-type>,
"@rid": <record-id>,
1305
"@version": 0,
"@class": <record-class>,
<field-name>: <field-value>,
["@fieldTypes": "<field-name>=<field-type>"]
}
]
Example
"records": [
{
"@type": "d", "@rid": "#12:476", "@version": 0, "@class": "Whiz",
"id": 476,
"date": "2011-12-09 00:00:00:000",
"text": "Los a went chip, of was returning cover, In the",
"@fieldTypes": "date=t"
},{
"@type": "d", "@rid": "#12:477", "@version": 0, "@class": "Whiz",
"id": 477,
"date": "2011-12-09 00:00:00:000",
"text": "He in office return He inside electronics for $500,000 Jay",
"@fieldTypes": "date=t"
}
]
1306
Full Example
{
"info":{
"name": "demo",
"default-cluster-id": 2,
"exporter-version": 2,
"engine-version": "1.0rc8-SNAPSHOT",
"storage-config-version": 2,
"schema-version": 4,
"mvrbtree-version": 0
},
"clusters": [
{"name": "internal", "id": 0, "type": "PHYSICAL"},
{"name": "index", "id": 1, "type": "PHYSICAL"},
{"name": "default", "id": 2, "type": "PHYSICAL"},
{"name": "orole", "id": 3, "type": "PHYSICAL"},
{"name": "ouser", "id": 4, "type": "PHYSICAL"},
{"name": "orids", "id": 5, "type": "PHYSICAL"},
{"name": "csv", "id": 6, "type": "PHYSICAL"},
{"name": "flat", "id": 7, "type": "PHYSICAL"},
{"name": "binary", "id": 8, "type": "PHYSICAL"},
{"name": "account", "id": 9, "type": "PHYSICAL"},
{"name": "company", "id": 10, "type": "PHYSICAL"},
{"name": "profile", "id": 11, "type": "PHYSICAL"},
{"name": "whiz", "id": 12, "type": "PHYSICAL"},
{"name": "address", "id": 13, "type": "PHYSICAL"},
{"name": "city", "id": 14, "type": "PHYSICAL"},
{"name": "country", "id": 15, "type": "PHYSICAL"},
{"name": "dummy", "id": 16, "type": "PHYSICAL"},
{"name": "ographvertex", "id": 26, "type": "PHYSICAL"},
{"name": "ographedge", "id": 27, "type": "PHYSICAL"},
{"name": "graphvehicle", "id": 28, "type": "PHYSICAL"},
{"name": "graphcar", "id": 29, "type": "PHYSICAL"},
{"name": "graphmotocycle", "id": 30, "type": "PHYSICAL"},
{"name": "newv", "id": 31, "type": "PHYSICAL"},
{"name": "mappoint", "id": 33, "type": "PHYSICAL"},
{"name": "person", "id": 35, "type": "PHYSICAL"},
{"name": "order", "id": 36, "type": "PHYSICAL"},
{"name": "post", "id": 37, "type": "PHYSICAL"},
{"name": "comment", "id": 38, "type": "PHYSICAL"}
],
"schema":{
"version": 210,
"classes": [
{"name": "Account", "default-cluster-id": 9, "cluster-ids": [9],
"properties": [
{"name": "binary", "type": "BINARY", "mandatory": false, "not-null": false},
{"name": "birthDate", "type": "DATE", "mandatory": false, "not-null": false},
{"name": "id", "type": "INTEGER", "mandatory": false, "not-null": false}
]
},
{"name": "Address", "default-cluster-id": 13, "cluster-ids": [13]
},
{"name": "Animal", "default-cluster-id": 17, "cluster-ids": [17]
},
1307
{"name": "AnimalRace", "default-cluster-id": 18, "cluster-ids": [18]
},
{"name": "COMMENT", "default-cluster-id": 38, "cluster-ids": [38]
},
{"name": "City", "default-cluster-id": 14, "cluster-ids": [14]
},
{"name": "Company", "default-cluster-id": 10, "cluster-ids": [10], "super-class": "Account"
"properties": [
]
},
{"name": "Country", "default-cluster-id": 15, "cluster-ids": [15]
},
{"name": "Dummy", "default-cluster-id": 16, "cluster-ids": [16]
},
{"name": "GraphCar", "default-cluster-id": 29, "cluster-ids": [29], "super-class": "GraphVehicle"
"properties": [
]
},
{"name": "GraphMotocycle", "default-cluster-id": 30, "cluster-ids": [30], "super-class":
"properties": [
]
},
{"name": "GraphVehicle", "default-cluster-id": 28, "cluster-ids": [28], "super-class":
"properties": [
]
},
{"name": "MapPoint", "default-cluster-id": 33, "cluster-ids": [33],
"properties": [
{"name": "x", "type": "DOUBLE", "mandatory": false, "not-null": false},
{"name": "y", "type": "DOUBLE", "mandatory": false, "not-null": false}
]
},
{"name": "OGraphEdge", "default-cluster-id": 27, "cluster-ids": [27], "short-name": "E"
"properties": [
{"name": "in", "type": "LINK", "mandatory": false, "not-null": false, "linked-class
{"name": "out", "type": "LINK", "mandatory": false, "not-null": false, "linked-class
]
},
{"name": "OGraphVertex", "default-cluster-id": 26, "cluster-ids": [26], "short-name": "V"
"properties": [
{"name": "in", "type": "LINKSET", "mandatory": false, "not-null": false, "linked-class
{"name": "out", "type": "LINKSET", "mandatory": false, "not-null": false, "linked-class
]
},
{"name": "ORIDs", "default-cluster-id": 5, "cluster-ids": [5]
},
{"name": "ORole", "default-cluster-id": 3, "cluster-ids": [3],
"properties": [
{"name": "mode", "type": "BYTE", "mandatory": false, "not-null": false},
{"name": "name", "type": "STRING", "mandatory": true, "not-null": true},
{"name": "rules", "type": "EMBEDDEDMAP", "mandatory": false, "not-null": false, "linked-type
]
},
{"name": "OUser", "default-cluster-id": 4, "cluster-ids": [4],
"properties": [
{"name": "name", "type": "STRING", "mandatory": true, "not-null": true},
{"name": "password", "type": "STRING", "mandatory": true, "not-null": true},
{"name": "roles", "type": "LINKSET", "mandatory": false, "not-null": false, "linked-class
]
1308
},
{"name": "Order", "default-cluster-id": 36, "cluster-ids": [36]
},
{"name": "POST", "default-cluster-id": 37, "cluster-ids": [37],
"properties": [
{"name": "comments", "type": "LINKSET", "mandatory": false, "not-null": false, "linked-class
]
},
{"name": "Person", "default-cluster-id": 35, "cluster-ids": [35]
},
{"name": "Person2", "default-cluster-id": 22, "cluster-ids": [22],
"properties": [
{"name": "age", "type": "INTEGER", "mandatory": false, "not-null": false},
{"name": "firstName", "type": "STRING", "mandatory": false, "not-null": false},
{"name": "lastName", "type": "STRING", "mandatory": false, "not-null": false}
]
},
{"name": "Profile", "default-cluster-id": 11, "cluster-ids": [11],
"properties": [
{"name": "hash", "type": "LONG", "mandatory": false, "not-null": false},
{"name": "lastAccessOn", "type": "DATETIME", "mandatory": false, "not-null": false, "
{"name": "name", "type": "STRING", "mandatory": false, "not-null": false, "min": "3"
{"name": "nick", "type": "STRING", "mandatory": false, "not-null": false, "min": "3"
{"name": "photo", "type": "TRANSIENT", "mandatory": false, "not-null": false},
{"name": "registeredOn", "type": "DATETIME", "mandatory": false, "not-null": false, "
{"name": "surname", "type": "STRING", "mandatory": false, "not-null": false, "min":
]
},
{"name": "PropertyIndexTestClass", "default-cluster-id": 21, "cluster-ids": [21],
"properties": [
{"name": "prop1", "type": "STRING", "mandatory": false, "not-null": false},
{"name": "prop2", "type": "INTEGER", "mandatory": false, "not-null": false},
{"name": "prop3", "type": "BOOLEAN", "mandatory": false, "not-null": false},
{"name": "prop4", "type": "INTEGER", "mandatory": false, "not-null": false},
{"name": "prop5", "type": "STRING", "mandatory": false, "not-null": false}
]
},
{"name": "SQLDropIndexTestClass", "default-cluster-id": 23, "cluster-ids": [23],
"properties": [
{"name": "prop1", "type": "DOUBLE", "mandatory": false, "not-null": false},
{"name": "prop2", "type": "INTEGER", "mandatory": false, "not-null": false}
]
},
{"name": "SQLSelectCompositeIndexDirectSearchTestClass", "default-cluster-id": 24, "cluster-ids
"properties": [
{"name": "prop1", "type": "INTEGER", "mandatory": false, "not-null": false},
{"name": "prop2", "type": "INTEGER", "mandatory": false, "not-null": false}
]
},
{"name": "TestClass", "default-cluster-id": 19, "cluster-ids": [19],
"properties": [
{"name": "name", "type": "STRING", "mandatory": false, "not-null": false},
{"name": "testLink", "type": "LINK", "mandatory": false, "not-null": false, "linked-class
]
},
{"name": "TestLinkClass", "default-cluster-id": 20, "cluster-ids": [20],
"properties": [
{"name": "testBoolean", "type": "BOOLEAN", "mandatory": false, "not-null": false},
{"name": "testString", "type": "STRING", "mandatory": false, "not-null": false}
1309
]
},
{"name": "Whiz", "default-cluster-id": 12, "cluster-ids": [12],
"properties": [
{"name": "account", "type": "LINK", "mandatory": false, "not-null": false, "linked-class
{"name": "date", "type": "DATE", "mandatory": false, "not-null": false, "min": "2010-01-01"
{"name": "id", "type": "INTEGER", "mandatory": false, "not-null": false},
{"name": "replyTo", "type": "LINK", "mandatory": false, "not-null": false, "linked-class
{"name": "text", "type": "STRING", "mandatory": true, "not-null": false, "min": "1"
]
},
{"name": "classclassIndexManagerTestClassTwo", "default-cluster-id": 25, "cluster-ids":
},
{"name": "newV", "default-cluster-id": 31, "cluster-ids": [31], "super-class": "OGraphVertex"
"properties": [
{"name": "f_int", "type": "INTEGER", "mandatory": false, "not-null": false}
]
},
{"name": "vertexA", "default-cluster-id": 32, "cluster-ids": [32], "super-class": "OGraphVertex"
"properties": [
{"name": "name", "type": "STRING", "mandatory": false, "not-null": false}
]
},
{"name": "vertexB", "default-cluster-id": 34, "cluster-ids": [34], "super-class": "OGraphVertex"
"properties": [
{"name": "map", "type": "EMBEDDEDMAP", "mandatory": false, "not-null": false},
{"name": "name", "type": "STRING", "mandatory": false, "not-null": false}
]
}
]
},
"records": [{
"@type": "d", "@rid": "#12:476", "@version": 0, "@class": "Whiz",
"id": 476,
"date": "2011-12-09 00:00:00:000",
"text": "Los a went chip, of was returning cover, In the",
"@fieldTypes": "date=t"
},{
"@type": "d", "@rid": "#12:477", "@version": 0, "@class": "Whiz",
"id": 477,
"date": "2011-12-09 00:00:00:000",
"text": "He in office return He inside electronics for $500,000 Jay",
"@fieldTypes": "date=t"
}
]
}
1310
Import from RDBMS
NOTE: Starting from OrientDB 2.0 you can use the OrientDB-ETL module to import data
from RDBMS. You can use ETL also with 1.7.x by installing it as separate module.
POST
COMMENT
TABLE POST:
+----+----------------+
| id | title |
+----+----------------+
| 10 | NoSQL movement |
| 20 | New OrientDB |
+----+----------------+
TABLE COMMENT:
+----+--------+--------------+
| id | postId | text |
+----+--------+--------------+
| 0 | 10 | First |
| 1 | 10 | Second |
| 21 | 10 | Another |
| 41 | 20 | First again |
| 82 | 20 | Second Again |
+----+--------+--------------+
1311
Import from RDBMS to Document Model
This guide is to import an exported relational database into OrientDB using the
Document Model. If you're using the Graph Model, look at Import into Graph Model.
For the sake of simplicity consider your Relational database having just these two tables:
POST
COMMENT
TABLE POST:
+----+----------------+
| id | title |
+----+----------------+
| 10 | NoSQL movement |
| 20 | New OrientDB |
+----+----------------+
TABLE COMMENT:
+----+--------+--------------+
| id | postId | text |
+----+--------+--------------+
| 0 | 10 | First |
| 1 | 10 | Second |
| 21 | 10 | Another |
| 41 | 20 | First again |
| 82 | 20 | Second Again |
+----+--------+--------------+
Since the Relational Model hasn't Object Oriented concepts you can create a class per
table in OrientDB. Furthermore in the RDBMS references One-2-Many are inverted from
the target table to the source one. In OrientDB the Object Oriented model is respected
and you've a collection of links from POST to COMMENT instances. In a RDBMS you
have:
1312
In OrientDB the Document model uses Links to manage relationships:
1313
Export your Relational Database
Most of Relational DBMSs provide a way to export a database in SQL format. What you
need is a text file containing the SQL INSERT commands to recreate the database from
scratch. Take a look to the documentation of your RDBMS provider. Below the link to the
export utilities for the most common RDBMSs:
MySQL:
http://www.abbeyworkshop.com/howto/lamp/MySQL_Export_Backup/index.html
Oracle: http://www.orafaq.com/wiki/Import_Export_FAQ
MS SqlServer: http://msdn.microsoft.com/en-us/library/ms140052.aspx
At this point you should have a .sql file containing the Relational database exported in
SQL format like this:
1314
Modify the SQL script
What we're going to do is to change the generated SQL file to be imported into a
OrientDB database. Don't execute the following commands but include them into the
SQL file to be executed in batch mode by the OrientDB Console.
1315
What database to use?
Before to import the database you need an open connection to a OrientDB database.
You can create a brand new database or use an existent one. You can use a volatile in-
memory only database or a persistent disk-based one.
For persistent databases you can choose to create it in a remote server or locally using
the "plocal" mode avoiding the server at all. This is suggested to have better
performance on massive insertion.
Or start a OrientDB server and create a database using the "remote" protocol in the
connection URL. Example:
NOTE: When you create a remote database you need the server's credentials to do it.
Use the user "root" and the password stored in config/orientdb-server-config.xml file.
1316
Use the remote mode
1317
Declare the 'massive insert' intent
In order to obtain the maximum of performance you can tell to OrientDB what you're
going to do. These are called "Intents". The "Massive Insert" intent will auto tune the
OrientDB engine for fast insertion.
1318
Create the classes, one for tables
Since the Relational Model hasn't Object Oriented concepts you can create a class per
table. Change the CREATE TABLE ... statements with CREATE CLASS :
This is the case when your Relational database was created using a OR-Mapping tool
like Hibernate or Data Nucleus (JDO).
In this case you have to re-build the original Object Oriented structure directly in
OrientDB using the Object Oriented capabilities of OrientDB.
1319
Remove not supported statements
Leave only the INSERT INTO statements. OrientDB supports not only INSERT statement
but for this purpose is out of scope.
1320
Create links
At this point you need to create links as relationships in OrientDB. The Create Link
command creates links between two or more records of type Document. In facts in the
Relational world relationships are resolved as foreign keys.
Using OrientDB, instead, you have direct relationship as in your object model. So the
navigation is from Post to Comment and not viceversa as for Relational model. For this
reason you need to create a link as INVERSE.
Execute:
1321
Remove old constraints
This is an optional step. Now you've direct links the field 'postId' has no more sense, so
remove it:
1322
Expected output
After these steps the expected output should be similar to that below:
1323
Import the records
Now you have modified the SQL script execute it by invoking the console tool in batch
mode (text file just created as first argument). Example of importing the file called
"database.sql":
$ console.sh database.sql
1324
Enjoy
That's all. Now you've a OrientDB database where relationships are direct without
JOINS.
Now enjoy with your new document-graph database and the following queries:
Select all the posts where comments contain the word 'flame' in the text property (before
as column):
orientdb> select * from post where comments contains ( text like '%flame%' )
Select all the posts commented today. In this case we're assuming a property "date" is
present in Comment class:
orientdb> select * from post where comments contains ( date > '2011-04-14 00:00:00' )
This is a command of the Orient console. To know all the commands go to Console-
Commands.
1325
Import from RDBMS to Graph Model
To import from RDBMS to OrientDB using the Graph Model the ETL tool is the
suggested way to do it. Take a look at: Import from CSV to a Graph.
1326
Import from Neo4j
This guide explains how to export a graph from Neo4j* and import it into OrientDB in 3
easy steps. If you want to know more about the differences between OrientDB and
Neo4j, take a look at OrientDB vs Neo4j.
1327
1) Download Neo4j Shell Tools plugin
In order to export the database in GraphML format, you need the additional neo4j-shell-
tools plugin:
1328
2) Export the Neo4j database to a file
Now launch the Neo4j-Shell tool located in the bin directory and execute the following
command:
export-graphml -t -o /tmp/out.graphml
Example:
$ bin/neo4j-shell
Welcome to the Neo4j Shell! Enter 'help' for a list of commands
NOTE: Remote Neo4j graph database service 'shell' at port 1337
1329
3) Import the database into OrientDB
The third and last step can be done in 2 ways, based on the OrientDB version you are
using.
If you have OrientDB 2.0, this is the suggested method because it's easier and is able to
import Neo4j labels as OrientDB classes automatically.
$ cd $ORIENTDB_HOME/bin
$ ./console.sh
orientdb> create database plocal:/tmp/db/test
creating database [plocal:/tmp/db/test] using the storage type [plocal]...
Database created successfully.
This method uses the standard Gremlin importer, but doesn't take in consideration any
label declared in Neo4j, so everything is imported as V (base Vertex class) and E (base
Edge class). After importing you could need to refactor your graph element to fit in a
more structured schema.
To import the GraphML file into OrientDB complete the following steps:
Example:
$ cd $ORIENTDB_HOME/bin
$ ./gremlin.sh
1330
\,,,/
(o o)
-----oOOo-(_)-oOOo-----
gremlin> g = new OrientGraph("plocal:/tmp/db/test");
==>orientgraph[plocal:/db/test]
gremlin> g.loadGraphML('/tmp/out.graphml');
==>null
gremlin> quit
1331
Logging
OrientDB uses the Java Logging framework bundled with the Java Virtual Machine.
1332
Configuration file
The logging strategies and policies can be configured using a file following the Java
syntax: Java Logging configuration.
To tell to the JVM where the properties file is placed you need to set the
"java.util.logging.config.file" system property to it. Example:
1333
Set the logging level
To change the logging level without modify the logging configuration just set the
"log.console.level" and "log.file.level" system variables to the requested levels.
Open the file orientdb-server-config.xml and add or update these lines at the end of
the file inside the <properties> section:
At startup
Set the system property "log.console.level" and "log.file.level" to the levels you want
using the -D parameter of java.
Example:
At run-time
The system variable can be setted at startup using the System.setProperty() API.
Example:
1334
Install Log formatter
OrientDB Server uses own LogFormatter. To use the same by your application call:
OLogManager.installCustomFormatter();
1335
Enterprise Edition
This is the main guide on using OrientDB Enterprise Edition. For more information
look at OrientDB Enterprise Edition.
Enterprise Agent
Enterprise Workbench
1336
OrientDB Enterprise Agent
The Agent contains the license generated by Orient Technologies. If you're a client you
already own Agent jar files to install. If you don't have them or you want to try Enterprise
Edition write to: [email protected].
Installation
In order to enable Enterprise feature, copy the provided agent-*.jar file under the
OrientDB Server "plugins" directory of each server. The plugin will be hot loaded by the
server after few seconds (look at the server's output). In case the plugin is not loaded
restart the OrientDB Server.
Once installed, the Agent Plugin displays the license information. Example:
************************************************
* ORIENTDB - ENTERPRISE EDITION *
* *
* Copyrights (c) 2013 Orient Technologies LTD *
************************************************
* Version...: 1.6.2 *
* License...: 2P2tA1EO8oOoS/WkR2/023kdks922JDw *
* Expires in: -25 days *
************************************************
NOTE: OrientDB Enterprise Plugin and OrientDB Server must be of the same main
version. Workbench 1.7.x works against all Agents 2.7.x. If you don't have the right
version please write to the Orient Technologies: [email protected].
1337
OrientDB Enterprise Workbench
Download
Download the right OrientDB Workbench distribution, using the same Agent version:
1338
Install
Uncompress the Workbench distribution to a local directory. For Windows user it's a ZIP
file, for all the others is a TAR.GZ archive.
1339
Start and Use Workbench
To start the Workbench go into the "bin" directory and double click on:
************************************************
* ORIENTDB WORKBENCH - ENTERPRISE EDITION *
* *
* Copyrights (c) 2013 Orient Technologies LTD *
************************************************
* Version...: 1.6.2 *
************************************************
To open the Web Console open your browser to the URL: http://localhost:2491 and use 'admin' as user and p
Now point your browser to the local server's IP address, port 2491, example:
http://localhost:2491. This is the login page. Use the default credentials as user
"admin" and password "admin" (you can change it once logged in).
1340
Troubleshooting
This page aims to link all the guides to Problems and Troubleshooting.
1341
Sub sections
Troubleshooting Java API
1342
Topics
The reason of this issue is massive usage of sun.misc.Unsafe which may have different
contract than it is implemented for Linux and Windows JDKs. To avoid this error please
use following settings during server start:
Don't be scared about it: your OrientDB installation will work perfectly, just it could be
slower with database larger than memory.
This lock is needed in case of you work on OS which uses aggressive swapping like
Linux. If there is the case when amount of available RAM is not enough to cache all
MMAP content OS can swap out rarely used parts of Java heap to the disk and when
GC is started to collect garbage we will have performance degradation, to prevent such
situation Java heap is locked into memory and prohibited to be flushed on the disk.
1343
com.orientechnologies.orient.core.exception.OStorageEx
ception: Error on reading record from file 'default.0.oda',
position 2333, size 122,14Mb: the record size is bigger
then the file itself (233,99Kb)
This usually happens because the database has been corrupted by a hw/sw crash or a
hard kill of the process during the writing to disk. If this happens on index clusters just
rebuild indexes, otherwise re-import a previously exported database.
This means that probably default timeouts are too low and server side operation need
more time to complete. Follow these MemoryLocker.lockMemoryPerformance-
Tuning#remote_connections.suggestions]].
1344
Brand new records are created with version major than 0
When OrientDB starts to serialize records goes recursively from the root A. When A is
encountered again to avoid loops it saves the record as empty just to get the RecordID
to store into the record C. When the serialization stack ends the record A (that was the
first of the stack) is updated because has been created as first but empty.
OGlobalConfiguration.MVRBTREE_LAZY_UPDATES.setValue(-1);
or via configuration:
Error:
com.orientechnologies.orient.core.db.record.ORecordLaz
ySet cannot be cast to
com.orientechnologies.orient.core.db.record.OIdentifiable
This happens if you've migrated a database created with an old version of OrientDB
where indexes were managed in different way. Just drop and recreate the indexes.
com.orientechnologies.common.concur.lock.OLockExcep
tion: File '/tmp/databases/demo/default.0.oda' is locked by
another process, maybe the database is in use by another
process. Use the remote mode with a OrientDB server to
allow multiple access to the same database
This is because the database is locked by another process is using it. To fix:
1345
check there's no a process is using OrientDB. Most of the times a OrientDB Server
is running. Just shutdown it and retry
set the storage.keepOpen setting to false
You're using different version of libraries. For example the client is using 1.3 and the
server 1.4. Align the libraries to the same version (last is suggested). Or probably you've
different versions of the same jars in the classpath.
1346
Troubleshooting using Java API
OConcurrentModificationException: Cannot
update record #X:Y in storage 'Z' because
the version is not the latest. Probably you
are updating an old record or it has been
modified by another user (db=vA your=vB)
This exception happens because you're running in a Multi Version Control Check
(MVCC) system and another thread/user has updated the record you're saving. To fix
this problem you can:
if you're running in a multi-thread application and your JVM is the only client is
writing to the database then disabling the Level1 cache could be enough.
If you're using the GraphDB API look at: concurrency
If you want to leave the MVCC and write code concurrency proof:
document.save();
break;
} catch(ONeedRetryException e) {
// RELOAD IT TO GET LAST VERSION
document.reload();
}
}
1347
Collection<ODocument> items = invoice.field(items);
items.add(invoiceItem);
invoice.save();
db.commit();
break;
} catch (OTransactionException e) {
// RELOAD IT TO GET LAST VERSION
invoice.reload();
}
}
1348
Run in OSGi context
(by Raman Gupta) OrientDB uses ServiceRegistry to load OIndexFactory and some
OSGi container couldn't be happy with it.
One solution is to set the TCCL so that the ServiceRegistry lookup works inside of osgi:
ODatabaseObjectTx db = null;
ClassLoader origClassLoader = Thread.currentThread().getContextClassLoader();
try {
ClassLoader orientClassLoader = OIndexes.class.getClassLoader();
Thread.currentThread().setContextClassLoader(orientClassLoader);
db = objectConnectionPool.acquire(dbUrl, username, password);
} finally {
Thread.currentThread().setContextClassLoader(origClassLoader);
}
Because the ServiceLoader uses the thread context classloader, you can configure it to
use the classloader of the OrientDB bundle so that it finds the entries in META-
INF/services.
Another way is to embed the dependencies in configuration in the Maven pom.xml file
under plugin(maven-bundle-plugin)/configuration/instructions:
<Embed-Dependency>
orientdb-client,
orient-commons,
orientdb-core,
orientdb-enterprise,
orientdb-object,
javassist
</Embed-Dependency>
Including only the jars you need. Look at Which library do I use?
1349
Database instance has been released to the
pool. Get another database instance from
the pool with the right username and
password
This is a generic error telling that the database has been found closed while using it.
1350
OLazyObjectIterator
This is the case when you're working with Object Database API and a field contains a
collection or a map loaded in lazy. On iteration it needs an open database to fetch linked
records.
Solutions:
1351
Stack Overflow on saving objects
This could be due to the high deep of the graph, usually when you create many records.
To fix it save the records more often.
1352
Plugins
If you're looking for drivers or JDBC connector go to Programming-Language-Bindings.
With proper mark-up/logic separation, a POJO data model, and a refreshing lack of
XML, Apache Wicket makes developing web-apps simple and enjoyable again. Swap
the boilerplate, complex debugging and brittle code for powerful, reusable components
written with plain Java and HTML.
1353
Auto mapping entities in package to db scheme or using classpath scanning to map
annotated entities
Auto db creation
Hooks for schema migration and data initialization extensions
All three database types may be used in single unit of work (but each type will use
its own transaction)
Vert.x is a lightweight, high performance application platform for the JVM that's designed
for modern mobile, web, and enterprise applications. Vert.x Persistor Module for
Tinkerpop-compatible Graph Databases like OrientDB.
Gephi Visual tool usage with OrientDB and the Blueprints importer
1354
OrientDB session store for Connect
Puppet module
JCA connectors
OPS4J Orient provides a JCA resource adapter for integrating OrientDB with Java
EE 6 servers
OrientDB JCA connector to access to OrientDB database via JCA API + XA
Transactions
Pacer plugin by Paul Dlug. Pacer is a JRuby graph traversal framework built on the
Tinkerpop stack. This plugin enables full OrientDB graph support in Pacer.
EventStore for Axonframework, which uses fully transactional (full ACID support) NoSQL
database OrientDB. Axon Framework helps build scalable, extensible and maintainable
applications by supporting developers apply the Command Query Responsibility
Segregation (CQRS) architectural pattern
1355
Accessing OrientDB using Slick
1356
Rexster
Rexster provides a RESTful shell to any Blueprints-complaint graph database. This
HTTP web service provides: a set of standard low-level GET, POST, and DELETE
methods, a flexible extension model which allows plug-in like development for external
services (such as ad-hoc graph queries through Gremlin), and a browser-based
interface called The Dog House.
A graph database hosted in the OrientDB can be configured in Rexster and then
accessed using the standard RESTful interface powered by the Rexster web server.
1357
Installation
You can get the latest stable release of Rexster from it's Download Page. The latest
stable release when this page was last updated was 2.5.0.
Or you can build a snapshot by executing the following Git and Maven commands:
Rexster is distributed as a zip file (also the building process creates a zip file) hence the
installation consist of unzipping the archive in a directory of your choice. In the following
sections, this directory is referred to as $REXSTER_HOME.
After unzipping the archive, you should copy orient-client.jar and orient-enterprise.jar in
$REXSTER_HOME/ext. Make sure you use the same version of OrientDB as those
used by Rexster. For example Rexster 2.5.0 uses OrientDB 1.7.6.
You can find more details about Rexster installation at the Getting Started page.
1358
Configuration
Refer to Rexster's Configuration page and OrientDB specific configuration page for the
latest details.
Synopsis
The Rexster configuration file rexster.xml is used to configure parameters such as: TCP
ports used by Rexster server modules to listen for incoming connections; character set
supported by the Rexster REST requests and responses; connection parameters of
graph instances.
In order to configure Rexster to connect to your OrientDB graph, locate the rexster.xml in
the Rexster directory and add the following snippet of code:
<rexster>
...
<graphs>
...
<graph>
<graph-enabled>true</graph-enabled>
<graph-name>my-orient-graph</graph-name>
<graph-type>orientgraph</graph-type>
<graph-file>url-to-your-db</graph-file>
<properties>
<username>user</username>
<password>pwd</password>
</properties>
</graph>
...
</graphs>
</rexster>
In the configuration file, there could be a sample graph element for an OrientDB
instance ( <graph-name>orientdbsample<graph-name> ): you might edit it according to your
needs.
The <graph-name> element must be unique within the list of configured graphs and
reports the name used to identify your graph. The <graph-enabled> element states
whether the graph should be loaded and managed by Rexster. Setting its contents to
false will prevent that graph from loading to Rexster; setting explicitly to true the graph
will be loaded. The <graph-type> element reports the type of graph by using an identifier
( orientgraph for an OrientDB Graph instance) or the full name of the class that
implements the GraphConfiguration interface
1359
(com.tinkerpop.rexster.OrientGraphConfiguration for an OrientDB Graph).
The <graph-file> element reports the URL to the OrientDB database Rexster is
expected to connect to:
plocal:*path-to-db* , if the graph can be accessed over the file system (e.g.
plocal:/tmp/graph/db )
remote:*url-to-db* , if the graph can be accessed over the network and/or if you want
to enable multiple accesses to the graph (e.g. remote:localhost/mydb )
memory:*db-name* , if the graph resides in memory only. Updates to this kind of graph
are never persistent and when the OrientDB server ends the graph is lost
The <username> and <password> elements reports the credentials to access the graph
(e.g. admin admin ).
1360
Run
Note: only Rexster 0.5-SNAPSHOT and further releases work with OrientDB
GraphEd
In this section we present a step-by-step guide to Rexster-ify an OrientDB graph.
We assume that:
you created a Blueprints enabled graph called orientGraph using the class
com.tinkerpop.blueprints.pgm.impls.orientdb.OrientGraph
you inserted in the Rexster configuration file a <graph> element with the <graph-
name> element set to my-orient-graph and the graph-file element set to
remote:orienthost/orientGraph (if you do not remember how to do this, go back to the
Configuration section).
Be sure that the OrientDB server is running and you have properly configured the
<graph-file> location and the access credentials of your graph.
Execute the startup script ($REXSTER_HOME/bin/rexster.bat or
$REXSTER_HOME/bin/rexster.sh)
The shell console appears and you should see the following log message (line 10
states that the OrientDB graph instance has been loaded):
Now you can use Rexster REST API and The Dog House web application to
retrieve and modify the data stored in the OrientDB graph.
1361
Gephi Visual Tool
1362
Introduction
Gephi is a visual tool to manipulate and analyze graphs. Gephi is an Open Source
project. Take a look at the amazing features.
Gephi can be used to analyze graphs extracted from OrientDB. There are 2 level of
integration:
the Streaming plugin that calls OrientDB server via HTTP. OrientDB exposes the
new "/gephi" command in HTTP GET method that executes a query and returns the
result set in "gephi" format.
Gephi importer for Blueprints
In this mini guide we will take a look at the first one: the streaming plugin.
1363
Getting started
Before to start assure you've OrientDB 1.1.0-SNAPSHOT or major.
1364
Download and install
1. To download Gephi goto: http://gephi.org/users/download/
2. Install it, depends on your OS
3. Run Gephi
4. Click on the menu Tools -> Plugins
5. Click on the tab Available Plugins
6. Select the plugin Graph Streaming, click on the Install button and wait the plugin is
installed
1365
Import a graph in Gephi
Before to import a graph assure a OrientDB server instance is running somewhere. For
more information watch this video.
1366
Executing a query
The OrientDB's "/gephi" HTTP command allow to execute any query. The format is:
http://<host>:<port>/gephi/<database>/<language>/<query>[/<limit>]
Where:
host is the host name or the ip address where the OrientDB server is running. If
you're executing OrientDB on the same machine where Gephi is running use
"localhost"
port is the port number where the OrientDB server is running. By default is 2480.
database is the database name
language
query , the query text following the URL encoding rules. For example to use the
spaces use %20 , so the query select from v becomes select%20from%20v
limit , optional, set the limit of the result set. If not defined 20 is taken by default.
-1 means no limits
1367
SQL Graph language
To use the OrientDB's SQL language use sql as language. For more information look
at the SQL-Syntax.
For example, to return the first 1,000 vertices (class V) with outgoing connections the
query would be:
http://localhost:2480/gephi/demo/sql/select%20from%20V%20where%20out.size()%20%3E%200/1000
1368
GREMLIN language
To use the powerful GREMLIN language to retrieve the graph or a portion of it use
gremlin as language. For more information look at the GREMLIN syntax.
g.V[0..99]
http://localhost:2480/gephi/demo/gremlin/g.V%5B0..99%5D/-1
For more information about using Gephi look at Learn how to use Gephi
1369
Upgrade
OrientDB uses the Semantic Versioning System (http://semver.org) where given a
version number MAJOR.MINOR.PATCH, increment the:
So between PATCH versions the compatibility is assured (example 1.7.0 -> 1.7.8).
Between MINOR and MAJOR versions you could export and re-import the database.
See below in the column "Database":
1370
Compatibility Matrix
Migration-
1.7.x 2.0.x from- Final Automatic 25 10
1.7.x-to- v2.6.0
2.0.x
Migration-
1.6.x 1.7.x from- Final Automatic 20, 21 10
1.6.x-to- v2.5.0
1.7.x
Migration-
1.5.x 1.6.x from- Changed Automatic 18, 19 10
1.5.x-to- v2.5.x
1.6.x
Migration-
1.4.x 1.5.x from- Changed Automatic 16, 17 10
1.4.x-to- v2.4.x
1.5.x
Migration-
1.3.x 1.4.x from- Changed Automatic 14, 15 n.a.
1.3.x-to- v2.3.x
1.4.x
References:
1371
Migrate from LOCAL storage engine to
PLOCAL
Starting from version 1.5.x OrientDB comes with a brand new storage engine: PLOCAL
(Paginated LOCAL). It's persistent like the LOCAL, but stores information in different
way. Below the main differences with LOCAL:
records are stored in cluster files, while with LOCAL was split between cluster and
data-segments
more durable than LOCAL because the append-on-write mode
minor contention locks on writes: this means more concurrency
it doesn't use Memory Mapping techniques (MMap) so the behavior is more
"predictable"
To migrate your LOCAL storage to the new PLOCAL you've to export and reimport the
database using PLOCAL as storage engine. Follow the steps below:
2) export the database using the console. Example by exporting the database under
/temp/db:
3) now always in the console create a new database using the "plocal" engine:
a) on a local filesystem:
4) now always in the console import the old database in the new one:
1372
orientdb> import database /temp/db.json.gzip -preserveClusterIDs=true
orientdb> quit
5) If you access to the database in the same JVM remember to change the URL from
"local:" to "plocal:"
1373
Migrate graph to RidBag
Since OrientDB 1.7 RidBag is default collection that manage adjacency relations in
graphs. While the older database managed by MVRB-Tree are fully compatible, you can
update your database to more recent format.
You can upgrade your graph via console or using the ORidBagMigration class
Using console
1374
OrientDB supports binary compatibility between previous releases and latest release.
Binary compatibility is supported at least between last 2 minor versions.
For example, lets suppose that we have following releases 1.5, 1.5.1, 1.6.1, 1.6.2, 1.7,
1.7.1 then binary compatibility at least between 1.6.1, 1.6.2, 1.7, 1.7.1 releases will be
supported.
If we have releases 1.5, 1.5.1, 1.6.1, 1.6.2, 1.7, 1.7.1, 2.0 then binary compatibility will
be supported at least between releases 1.7, 1.7.1, 2.0.
1. When storage is opened, version of binary format which is used when storage is
created is read from storage configuration.
2. Factory of objects are used to present disk based data structures for current binary
format is created.
Only features and database components which were exist at the moment when current
binary format was latest one will be used. It means that you can not use all database
features available in latest release if you use storage which was created using old binary
format version. It also means that bugs which are fixed in new versions may be (but may
be not) reproducible on storage created using old binary format.
To update binary format storage to latest one you should export database in JSON
format and import it back. Using either console commands export database and import
database or Java API look at com.orientechnologies.orient.core.db.tool.ODatabaseImport ,
com.orientechnologies.orient.core.db.tool.ODatabaseExport classes and
com.orientechnologies.orient.test.database.auto.DbImportExportTest test.
Version proporty.
ION .
Please note that binary compatibility is supported since 1.7-rc2 version for plocal
storage (as exception you can read database created in 1.5.1 version by 1.7-rc2
version).
1375
Return to Upgrade.
1376
Migration from 1.7.x to 2.0.x
Databases created with release 1.7.x are compatible with 2.0, so you don't have to
export/import the database like in the previous releases. Check your database directory:
if you have a file *.wal, delete it before migration.
1377
Use the new binary serialization
To use the new binary protocol you have to export and reimport the database into a new
one. This will boost up your database performance of about +20% against old database.
2) Export the database using the console. Move into the directory where you've installed
OrientDB 2.0 and execute the following commands:
> cd bin
> ./console.sh (or bin/console.bat under Windows)
orientdb> connect plocal:/temp/mydb admin admin
orientdb> export database /temp/mydb.json.gz
orientdb> disconnect
orientdb> create database plocal:/temp/newdb
orientdb> import database /temp/mydb.json.gz
1378
API changes
We have hidden some methods considered internal to avoid users call them. However, if
your usage of OrientDB is quite advanced and you still need them, you can access from
Internal helper classes. Please still consider them as internals and could change in the
future. Below the main ones:
ODatabaseRecord.getStorage()
ODatabaseDocumentPool
We replaced ODatabaseDocumentPool Java class (now deprecated) with the new, more
efficient com.orientechnologies.orient.core.db.OPartitionedDatabasePool.
Caches
We completely removed Level2 cache. Now only Level1 and Storage DiskCache are
used. This change should be transparent with code that run on previous versions, unless
you enable/disable Level2 cache in your code.
Furthermore it's not possible anymore to disable Cache, so method setEnable() has
been removed.
Changes
Context 1.7.x
1379
Configuration OGlobalConfiguration.CACHE_LEVEL1_ENABLED OGlobalConfiguration.C
We completely drop the long deprecated LOCAL Storage. If your database was created
using "LOCAL:" then you have to export it with the version you was using, then import it
in a fresh new database created with OrientDB 2.0.
1380
Server
At first run, OrientDB asks for the root's password. Leave it blank to auto generate it (like
with 1.7.x). This is the message:
+----------------------------------------------------+
| WARNING: FIRST RUN CONFIGURATION |
+----------------------------------------------------+
| This is the first time the server is running. |
| Please type a password of your choice for the |
| 'root' user or leave it blank to auto-generate it. |
+----------------------------------------------------+
If you set the system setting or environment variable ORIENTDB_ROOT_PASSWORD , then its
value will be taken as root password. If it's defined, but empty, a password will be
automatically generated.
1381
Distributed
At first run as distributed, OrientDB asks for the node name. Leave it blank to auto
generate it (like with 1.7.x). This is the message:
+----------------------------------------------------+
| WARNING: FIRST DISTRIBUTED RUN CONFIGURATION |
+----------------------------------------------------+
| This is the first time that the server is running |
| as distributed. Please type the name you want |
| to assign to the current server node. |
+----------------------------------------------------+
If you set the system setting or environment variable ORIENTDB_NODE_NAME , then its value
will be taken as node name. If it's defined, but empty, a name will be automatically
generated.
Multi-Master replication
With OrientDB 2.0 each record cluster selects assigns the first server node in the
servers list node as master for insertion only. In 99% of the cases you insert per class,
not per cluster. When you work per class, OrientDB auto-select the cluster where the
local node is the master. In this way we completely avoid conflicts (like in 1.7.x).
If you execute this command against a node1, OrientDB will assign the cluster-id where
node1 is master, i.e. #13:232. With node2 would be different: it couldn't never be #13.
Asynchronous replication
1382
OrientDB 2.0 supports configurable execution mode through the new variable
executionMode . It can be:
{
"autoDeploy": true,
"hotAlignment": false,
"executionMode": "undefined",
"readQuorum": 1,
"writeQuorum": 2,
"failureAvailableNodesLessQuorum": false,
"readYourWrites": true,
"clusters": {
"internal": {
},
"index": {
},
"*": {
"servers" : [ "<NEW_NODE>" ]
}
}
}
1383
Graph API
Multi-threading
Edge collections
OrientDB 2.0 disabled the auto scale of edge. In 1.7.x, if a vertex had 1 edge only, a
LINK was used. As soon as a new edge is added the LINK is auto scaled to a LINKSET
to host 2 edges. If you want this setting back you have to call these two methods on
graph instance (or OrientGraphFactory before to get a Graph instance):
graph.setAutoScaleEdgeType(true);
graph.setEdgeContainerEmbedded2TreeThreshold(40);
1384
Migration from 1.6.x to 1.7.x
Databases created with release 1.6.x are compatible with 1.7, so you don't have to
export/import the database like in the previous releases.
1385
Engine
OrientDB 1.7 comes with the PLOCAL engine as default one. For compatibility purpose
we still support "local" database, but this will be removed soon. So get the chance to
migrate your old "local" database to the new "plocal" follow the steps in: Migrate from
local storage engine to plocal.
1386
Migration from 1.5.x to 1.6.x
Databases created with release 1.5.x need to be exported and reimported in OrientDB
1.6.x.
1387
Engine
OrientDB 1.6.x comes with the new PLOCAL engine. To migrate a database create with
the old "local" to such engine follow the steps in: Migrate from local storage engine to
plocal.
1388
Migration from 1.4.x to 1.5.x
OrientDB 1.5.x automatic upgrades any databases created with version 1.4.x, so export
and import is not needed.
1389
Engine
OrientDB 1.5.x comes with the new PLOCAL engine. To migrate to such engine follow
the steps in: Migrate from local storage engine to plocal.
1390
Migration from 1.3.x to 1.4.x
GraphDB
OrientDB 1.4.x uses a new optimized structure to manage graphs. You can use the new
OrientDB 1.4.x API against graph databases created with OrientDB 1.3.x setting few
properties at database level. In this way you can continue to work with your database but
remember that this doesn't use the new structure so it's strongly suggested to export and
import the database.
The new Engine uses some novel techniques based on the idea of a dynamic Graph
that change shape at run-time based on the settings and content. The new Engine is
much faster than before and needs less space in memory and disk. Below the main
improvements:
1391
of edges to find the right one
Blueprints changes
If you was using Blueprints look also to the Blueprints changes 1.x and 2.x.
Before 1.4.x the base classes for Vertices was "OGraphVertex" with alias "V" and for
Edges was "OGraphEdge" with alias "E". Starting from v1.4 the base class for Vertices is
"V" and "E" for Edges. So if in your code you referred "V" and "E" for inheritance nothing
is changed (because "V" and "E" was the aliases of OGraphVertex and "OGraphEdge"),
but if you used directly "OGraphVertex" and "OGraphEdge" you need to replace them
into "V" and "E".
If you don't export and import the database you can rename the classes by hand typing
these commands:
If you're exporting the database using the version 1.4.x you've to set few configurations
at database level. See above Working with database created with 1.3.x.
1392
$ cd $ORIENTDB_HOME/bin
$ ./gremlin.sh
\,,,/
(o o)
-----oOOo-(_)-oOOo-----
gremlin> g = new OrientGraph("local:/temp/db");
==>orientgraph[local:/temp/db]
gremlin> g.saveGraphML("/temp/export.xml")
==>null
1393
General Migration
If you want to migrate from release 1.3.x to 1.4.x you've to export the database using the
1.3.x and re-import it using 1.4.x. Example:
$ cd $ORIENTDB_HOME/bin
$ ./console.sh
OrientDB console v.1.3.0 - www.orientechnologies.com
Type 'help' to display all the commands supported.
1394
OK (1 indexes)
Exporting manual indexes content...
- Exporting index dictionary ...OK (entries=0)
OK (1 manual indexes)
$ cd $ORIENTDB_HOME/bin
$ ./console.sh
OrientDB console v.1.3.0 - www.orientechnologies.com
Type 'help' to display all the commands supported.
1395
- Imported records into cluster 'internal' (id=0): 1 records
- Imported records into cluster 'v' (id=9): 809 records
- Imported records into cluster 'followed_by' (id=11): 7047 records
- Imported records into cluster 'sung_by' (id=12): 2 records
- Imported records into cluster 'written_by' (id=13): 1 records
- Imported records into cluster 'testmodel' (id=14): 2 records
- Imported records into cluster 'vertexwithmandatoryfields' (id=15): 1 records
- Imported records into cluster 'person' (id=21): 2 records
1396
Internals
This section contains internal technical information. Users usually are not interested to
such technical details, but if you want to hack OrientDB or become a contributor this
information could be useful.
1397
Storages
Any OrientDB database relies on a Storage. OrientDB supports 4 storage types:
plocal, persistent disk-based, where the access is made in the same JVM process
remote, by using the network to access a remote storage
memory, all data remains in memory
local, deprecated, it's the first version of disk based storage, but has been replaced
by plocal
1398
Storages
Any OrientDB database relies on a Storage. OrientDB supports 4 storage types:
plocal, persistent disk-based, where the access is made in the same JVM process
remote, by using the network to access a remote storage
memory, all data remains in memory
local, deprecated, it's the first version of disk based storage, but has been replaced
by plocal
1399
PLocal Storage
The Paginated Local Storage, "plocal" from now, is a disk based storage which works
with data using page model.
plocal storage consists of several components each of those components use disk data
through disk cache.
Below is list of plocal storage components and short description of each of them:
1400
File System
Since PLOCAL is bases on disk, all the pages are flushed to physical files. You can
specify any mounted partitions on your machine, backed by Disks, SSD, Flash Disks or
DRAM.
1401
Cluster
Cluster is logical piece of disk space where storage stores records data. Each cluster is
split in pages. Page is a single atomic unit, which is used by cluster.
Each page contains system information and records data. System information includes
"magic number" and crc32 check sum of page content. This information is used to check
storage integrity after DB crash. To start integrity check run command "check database"
from console.
File System
To speed up the access to the most requested clusters it's recommended to use the
cluster files to a SSD or any faster support than disk. To do that, move the files to the
mounted partitions and create symbolic links to them on original path. OrientDB will
follow symbolic links and will open cluster files everywhere are reachable.
Cluster pointers
The mapping between data file and physical position is managed with a list, where each
entry of this list is a fixed size element which is the pointer to the physical position of
record in data file.
Because data file is paginated, this pointer consist of 2 items: page index (long value)
and position of record inside page (int value), so each record pointer consumes 12
bytes.
When a new record is inserted, a new pointer is added to the list so index of this pointer
becomes cluster position. The list is append only data structure so if you add a new
record its cluster position will be unique and will not be reused.
1402
When you delete a record, the page index and record position are set to -1. So record
pointer is transformed in record tombstone. You can think about record id like a uuid. It
is unique and never reused.
Usually when you delete records you lose very small amount of disk space. This could
be mitigated with a periodic "offline compaction" by performing database export/import.
In such case records cluster positions will be changed (tombstones will be ignored
during export) and the lost space will be revoked. So during the import process, the
cluster positions can change.
Migration of RID
OrientDB import tool uses a manual hash index (by default the name is
'___exportImportRIDMap') to map the old record ids and new record ids.
1403
Write Ahead (operation) Log (WAL)
Write Ahead Log, WAL from now, is used to restore storage data after a non-soft
shutdown:
All the operations on plocal components are logged in WAL before they are performed
on these components. WAL is append only data structure, you can think about it like a
list of records which contains information about operations performed on storage
components.
WAL flush
As result if OrientDB crashes, all data changes done during <=1 second interval before
crash will be lost. This is the trade off between performance and durability.
It's strongly recommended to store WAL records on separate disk than the disk used to
store the DB content. In this way data I/O operations will not be interrupted by WAL I/O
operations. This can be done by setting the storage.wal.path property to the folder
where storage WAL files will be placed.
1404
In ROLLBACK_ONLY mode only data are needed to rollback transactions are stored.
WAL records can not be used to restore index content after crash, in such case
automatic indexes are rebuild. In FULL mode indexes can be restored after DB crash
without rebuild. You can change index durability mode by setting the property
index.txMode.
1405
File types
PLocal storage writes the database on file system using different files. Below all the
extensions:
.cpm, contains the mapping between real physical positions and cluster positions. If
you delete record, the tombstone is placed here. Each tombstone consumes about
12 bytes
.pcl, data file
.sbt, is index file
.wal and .wmr, are Journal Write Ahead (operation) Log files
.cm, is the mapping between file id and real file name (is used internally)
.irs, is the RID set file for not unique index
1406
How it works (Internal)
Basically paginated storage is nothing more than 2-level disk cache which works
together with write ahead log.
Every file is spitted on pages, and each file operation is atomic at page level. 2-level disk
cache allows:
Typical set of operations are needed to work with any file looks like following:
1407
8. Push record back to the disk cache, in other words indicate cache that you do not
use this page any more so it can be safely evicted from the memory to make room
to other pages OReadWriteDiskCache#release.
When we load page at first Read Cache looks it in one of LRU lists. There are two of
them for data which are accessed several times and then not accessed for very long
period of item (it consumes 25% of memory) and data which are accessed frequently for
long period of time (it consumes 75% of memory).
If page is absent in LRU queues, then Read Cache asks to the Write Cache to load data
from the disk.
If we are lucky and pages which are queued to flush are still in Write Queue of Write
Cache it will be retrieved from there or otherwise Write Cache will load data from file on
the disk.
When data will be read from file by Write Cache, it will be put in LRU queue which
contains short living pages. Eventually, if this pages will be accessed frequently during
long time interval, loaded page will be moved to the LRU of long living pages.
When we release page and this page is marked as dirty this page is put into the Write
Cache which adds it to the Write Queue. Write Queue can be considered as ring buffer
where all the pages are sorted by its position on the disk. This trick allows to minimize
disk head movements during pages flush. What is more interesting that pages are
always flushed in background in background flush thread. This approach allows to
mitigate I/O bottleneck if we have enough RAM to work in memory only and flush data in
background.
So it was about how disk cache works. But how we achieve durability of changes on
page level and what is more interesting on the level when we work with complex data
structures like Trees or Hash Maps (these data structures are used in indexes).
If we look back on set of operations which we perform to manipulate file data you see
that step 5 does not contains any references to OrientDB API. That is because there are
two ways to work with off heap page durable and not durable.
So simple (not durable way) is to work with methods of direct memory pointer
com.orientechnologies.common.directmemory.ODirectMemoryPointer(setLong/getLong,
1408
setInt/getInt and so on). If you would like to make all changes in your data structures
durable you should not work with direct memory pointer but should create component
which will present part of your data structure and extend it from
com.orientechnologies.orient.core.storage.impl.local.paginated.ODurablePage class.
This class has similar methods for manipulation of data in off heap page but also it
tracks all changes are done to the page and we can always return diff between old/new
states of page using
com.orientechnologies.orient.core.storage.impl.local.paginated.ODurablePage#getPage
Changes method. Also this class allows to apply given diff to the old/new snapshot of
given pages to repeat/revert (restoreChanges()/revertChanges()) changes are done for
this page.
1409
PLocal Engine
Paginated Local storage engine, also called as "plocal", is intended to be used as
durable replacement of the previous local storage.
plocal storage is based on principle that using disk cache which contains disk data that
are split by fixed size portions (pages) and write ahead logging approach (when changes
in page are logged first in so called durable storage) we can achieve following
characteristics:
Using write ahead log and page based cache we can achieve durability/performance
trade off. We do not need to flush every page to the disk so we will avoid costly random
I/O operations as much as possible and still can achieve durability using much cheaper
append only I/O operations.
From all given above we can conclude one more advantage of plocal against local - it
has much faster transactions implementation. In order achieve durability on local storage
we should set tx.commit.synch property to true (perform synchronization of disk cache
on each transaction commit) which of course makes create/update/delete operations
inside transaction pretty slow.
Local storage uses MMAP implementation and it means that caching of read and write
operations can not be controlled, plocal from other side uses two types of caches read
cache and write cache (the last is under implementation yet and not included in current
implementation).
The decision to split responsibilities between 2 caches is based on the fact that
characters of distribution of "read" and "write" data are different and they should be
processed separately.
We replaced MMAP by our own cache solution because we needed low level integration
with cache life cycle to provide fast and durable integration between WAL and disk
cache. Also we expect that when cache implementation will be finished issues like
https://github.com/orientechnologies/orientdb/issues/1202 and
https://github.com/orientechnologies/orientdb/issues/1339 will be fixed automatically.
1410
Despite of the fact that write cache is still not finished it does not mean that plocal
storage is not fully functional. You can use plocal storage and can notice that after
server crash it will restore itself.
But it has some limitations right now, mostly related to WAL implementation. When
storage is crashed it finds last data check point and restores data from this checkpoint
by reading operations log from WAL.
There are two kind of check points full check point and fuzzy check point. The full check
point is simple disk cache flush it is performed when cluster is added to storage or
cluster attributes are changed, also this check point is performed during storage close.
Fuzzy checkpoint is completely different (it is under implementation yet). During this
checkpoint we do not flush disk cache we just store the position of last operation in write
ahead log which is for sure flushed to the disk. When we restore data after crash we find
this position in WAL and restore all operations from it. Fuzzy check points are much
faster and will be performed each hour.
To achieve this trick we should have special write cache which will guarantee that we will
not restore data from the begging of database creation during restore from fuzzy
checkpoint and will not have performance degradation during write operations. This
cache is under implementation.
So right now when we restore data we need to restore data since last DB open
operation. It is quite long procedure and require quite space for WAL.
When fuzzy check points will be implemented we will cut unneeded part of WAL during
fuzzy check point which will allow us to keep WAL quite small.
But whether we use fuzzy checkpoints or not we can not append to the WAL forever.
WAL is split by segments, when WAL size is exceed maximum allowed size the oldest
WAL segment will be deleted and new empty one will be created.
Maximum amount of size which is consumed by disk cache currently is set using two
parameters: storage.diskCache.bufferSize - Maximum amount of memory consumed by
disk cache in megabytes. storage.diskCache.writeQueueLength - Currently pages are
1411
nor flushed on the disk at the same time when disk cache size exceeds, they placed to
write queue and when write queue will be full it is flushed. This approach minimize disk
head movements but it is temporary solution and will be removed at final version of
plocal storage. This parameter is measured in megabytes.
During update the previous record deleted and content of new record is placed instead
of old record at the same place. If content of new record does not fit in place occupied by
old record, record is split on two parts first is written on old record's place and the
second is placed on new or existing page. Placing of part of the record on new page
requires to log in WAL not only new but previous data are hold in both pages which
requires much more space. To prevent such situation cluster in plocal storage has
following attributes:
1. USE_WAL if you prefer that some clusters will be faster but not durable you can set
this parameter to false.
1412
PLocal Disk-Cache
OrientDB Disk cache consists of two separate cache components that work together:
1413
Read Cache
It contains the following queues:
a1, as FIFO queue for pages which were not in the read cache and accessed for the
first time
am, as FIFO queue for the hot pages (pages which are accessed frequently during
db lifetime). The most used pages stored in a1 becomes "hot pages" and are moved
into the am queue.
a1 Queue
Loading a page
When a page is read for the first time, it's loaded from the disk and put in the a1in
queue. If there isn't enough space in RAM, the page is moved to a1out queue.
Queue sizes
1414
When OrientDB starts, both caches are empty, so all the accessed pages are put in a1in
queue, and the size of this queue is 100% of the size of the Read Cache.
But then, when there is no more room for new pages in a1in, the old pages are moved
from a1in to a1out. Eventually when a1out contains requested pages we need room for
am queue pages, so once again we move pages from a1in queue to a1out queue, a1in
queue is truncated till it is reached 25% size of read cache.
To make more clear how RAM and pages are distributed through queues lets look at
example. Lets suppose we have cache which should cache in RAM 4 pages, and we
have 8 pages stored on disk (which have indexes from 0 till 7 accordingly).
am - []
a1in - []
a1out - []
am - []
a1in - [3, 2, 1, 0]
a1out - []
Then we read 5-th page from the disk and then 6-th , because only 4 pages can be fit
into RAM we remove the last pages with indexes 0 and 1, free memory which is
consumed by those pages and put them in a1out. So we have:
am - []
a1in - [5, 4, 3, 2]
a1out - [1, 0]
lets read pages with indexes from 6 till 7 (last 2 pages) but a1out can contain only 2
pages (50% of cache size) so the first pages will be removed from o1out. We have here:
am - []
a1in - [7, 6, 5, 4]
a1out - [3, 2]
Then if we will read pages 2, 3 then we mark them (obviously) as hot pages and we put
them in am queue but we do not have enough memory for these pages, so we remove
pages 5 and 4 from a1in queue and free memory which they consumed. Here we have:
1415
am - [3, 2]
a1in - [7, 6]
a1out - [5, 4]
Then we read page 4 because we read it several times during long time interval it is hot
page and we put it in am queue. So we have:
am - [4, 3, 5]
a1in - [7]
a1out - [6, 5]
We reached state when queues can not grow any more so we reached stable, from point
of view of memory distribution, state.
On accessing a page X
begin:
if X is in Am then
move X to the head of Am
else if (X is in A1out) then
removeColdestPageIfNeeded
add X to the head of Am
else if (X is in A1in)
// do nothing
else
removeColdestPageIfNeeded
add X to the head of A1in
end if
end
removeColdestPageIfNeeded
begin
if there is enough RAM do nothing
else if( A1in.size > A1inMaxSize)
free page out the tail of A1in, call it Y
add identifier of Y to the head of A1out
if(A1out.size > A1OutMaxSize)
remove page from the tail of Alout
end if
else
remove page out the tail of Am
// do not put it on A1out; it hasnt been
// accessed for a while
end if
end
1416
Write cache
The main target of the write cache is to eliminate disk I/O overhead, by using the
following approaches:
1. All the pages are grouped by 4 adjacent pages (group 0 contains pages from 0 to 3,
group 1 contains pages from 4 to 7, etc. ). Groups are sorted by position on the
disk. Groups are flushed in sorted order, in such way we reduce the random I/O disk
head seek overhead. Group's container is implemented as SortedMap: when we
reach the end of the map we start again from the beginning. You can think about
this data structure as a "ring buffer"
2. All the groups have "recency bit", this bit is set when group is changed. It is needed
to avoid to flush pages that are updated too often, it will be wasting of I/O time
3. Groups are continuously flushed by background thread, so until there is enough free
memory, all data operations do not suffer of I/O overhead because all operations
are performed in memory
begin
try to find page in page group.
if such page exist
replace page in page group
set group's "recency bit" to true
end if
else
add page group
set group's "recency bit" to true
end if
end
begin
calculate amount of groups to flush
start from group next to flushed in previous flush iteration
set "force sync" flag to false
1417
flush pages in group
remove group from ring buffer
end if
end for
if we need to flush more than one group and not all of them are flushed repeat "flush loop" with "force
end
1. if amount of RAM consumed by pages is less than 80%, then 1 group is flushed.
2. if amount of RAM consumed by pages is more than 80%, then 20% of groups is
flushed.
3. if amount of RAM consumed by pages is more than 90%, then 40% of groups is
flushed.
1418
Interaction between Read and Write Caches
By default the maximum size of Read Cache is 70% of cache RAM and 30% for Write
Cache.
When a page is requested, the Read Cache looks into the cached pages. If it's not
present, the Read Cache requests page from the Write Cache. Write Cache looks for the
page inside the Ring Buffer: if it is absent, it reads the page from the disk and returns it
directly to the Read Cache without caching it inside of Write Cache Ring Buffer.
Implementation details
Page which is used by storage data structure (such as cluster or index) can not be
evicted (removed from memory) so each page pointer also has "usage counter" when
page is requested by cache user, "usage counter" is incremented and decremented
when page is released. So removeColdestPageIfNeeded() method does not remove tail
page, but removes page closest to tail which usage counter is 0, if such pages do not
exit either exception is thrown or cache size is automatically increased and warning
message is added to server log (default) (it is controlled by properties
server.cache.2q.increaseOnDemand and server.cache.2q.increaseStep, the last one
is amount of percent of RAM from original size on which cache size will be increased).
When a page is changed, the cache page pointer (data structure which is called
OCacheEntry) is marked as dirty by cache user before release. If cache page is dirty it is
put in write cache by read cache during call of OReadWriteDiskCache#release()
method. Strictly speaking memory content of page is not copied, it will be too slow, but
pointer to the page is passed. This pointer (OCachePointer) tracks amount of referents if
no one references this pointer, it frees referenced page.
1419
PLocal WAL (Journal)
Write Ahead Log, WAL form now, is operation log which is used to store data about
operations which were performed on disk cache page. WAL is enabled by default.
You could disable the journal (WAL) for some operations where reliability is not
necessary:
-storage.useWAL=false
By default, the WAL files are written in the database folder. Since these files can growth
very fast, it's a best practice to store in a dedicated partition. WAL are written in append-
only mode, so there is not much difference on using a SSD or a normal HDD. If you
have a SSD we suggest to use for database files only, not WAL.
To setup a different location than database folder, set the WAL_LOCATION variable.
OGlobalConfiguration.WAL_LOCATION.setValue("/temp/wal")
or at JVM level:
This log is not an high level log, which is used to log operations on record level. During
each page change following values are stored:
As you can see WAL contains not logical but raw (in form of chunk of bytes) presentation
of data which was/is contained inside of page. Such format of record of write ahead log
allows to apply the same changes to the page several times and as result allows do not
flush cache content after each TX operation but do such flush on demand and flush only
chosen pages instead of whole cache. The second advantage is following if storage is
crashed during data restore operation it can be restored again , again and again.
1420
Lets say we have page where following changes are done.
Storage is crashed during the middle of page flush, which does not mean that first 10
bytes are written, so lets suppose that the last 10 changed byte were written, but first 10
bytes were not.
During data restore we apply all operations stored in WAL one by one, which means that
we set first 10 bytes of changed page and then last 10 bytes of this page. So the
changed page will have correct state does not matter whether it's state was flushed to
the disk or not.
WAL file is split on pages and segments, each page contains in header CRC32 code of
page content and "magic number". When operation records are logged to WAL they are
serialized and binary content appended to the current page, if it is not enough space left
in page to accommodate binary presentation of whole record, the part of binary content
(which does not fit inside of current page) will be put inside of next record. It is important
to avoid gaps (free space) inside of pages. As any other files WAL can be corrupted
because of power failure and detection of gaps inside WAL pages is one of the
approaches how database separates broken and "healthy" WAL pages. More about this
later.
Any operation may include not single but several pages, to avoid data inconsistency all
operations on several records inside of one logical operation are considered as single
atomic operation. To achieve this functionality following types of WAL records were
introduced:
1421
iii. rollback flag - indicates whether given atomic operation should be rolled back.
3. Record which contains page changes contains following fields:
i. LSN (log sequence number) - physical position of log record inside WAL.
ii. page index and file id of changed page.
iii. Page changes itself.
iv. LSN of change which was applied to the current page before given one -
prevLSN.
The last record's type (page changes container) contains field (d. item) which deserves
additional explanation. Each cache page contains following "system" fields:
Every time we perform changes on the page before we release it back to the cache we
log page changes to the WAL, assign LSN of WAL record as the "page LSN" and only
after that release page back to the cache.
When WAL flushes it's pages it does not do it at once when current page is filled it is put
in cache and is flushed in background along with other cached pages. Flush is
performed every second in background thread (it is trade off between performance and
durability). But there are two exceptions when flush is performed in thread which put
record in WAL:
begin
go trough all WAL records one by one
gather together all atomic operation records in one batch
when "atomic operation end" record was found
if commit should be performed
go through all atomic operation records from first to last, apply all page changes, set page LSN to t
else
go through all atomic operation records from last to first, set old page's content, set page LSN to t
1422
endif
end
As it is written before WAL files are usual files and they can be flushed only partially if
power is switched off during WAL cache flush. There are two cases how WAL pages can
be broken:
1. When we open WAL during DB start we verify that size of WAL multiplies of WAL
page size if it is not WAL size is truncated to page size.
2. When we read pages one by one we verify CR32 and magic number of each page.
If page is broken we stop data restore procedure here.
Second case a bit more tricky. Because WAL is append only log, there is two possible
sub-cases, lets suppose we have 3 pages after 2-nd (broken) flush. First and first half of
second page were flushed during first flush and second half of second page and third
page were flushed during second flush. Because second flush was interrupted by power
failure we can have two possible states:
1. Second half of page was flushed but third was not. It is easy to detect by checking
CRC and magic number values.
2. Second half of page is not flushed but third page is flushed. In such case CRC and
magic number values will be correct and we can not use them instead of this when
we read WAL page we check if this page has free space if it has then we check if
this is last page if it is not we mark this WAL page as broken.
1423
Local Storage (Not more available since
2.0)
Local storage is the first version of disk-based storage engine, but has been replaced by
plocal. Don't create new databases using local, but rather plocal. Local storage has
been kept only for compatibility purpose.
1424
Local Physical Cluster
The cluster is mapped 1-by-2 to files in the underlying File System. The local physical
cluster uses two or more files: One or more files with extension "ocl" (OrientDB Cluster)
and only one file with the extension "och" (OrientDB Cluster Holes).
For example, if you create the "Person" cluster, the following files will be created in the
folder that contains your database:
person.0.ocl
person.och
The first file contains the pointers to the record content in ODA (OrientDB Data
Segment). The '0' in the name indicates that more successive data files can be created
for this cluster. You can split a physical cluster into multiple real files. This behavior
depends on your configuration. When a cluster file is full, a new file will be used.
The second file is the "Hole" file that stores the holes in the cluster caused by deleted
data.
NOTE (again, but very important): You can move real files in your file system only
by using the OrientDB APIs.
1425
Data Segment
OrientDB uses data segments to store the record content. The data segment behaves
similar to the physical cluster files: it uses two or more files. One or multiple files with the
extension "oda" (OrientDB Data) and only one file with the extension "odh" (OrientDB
Data Holes).
By default OrientDB creates the first data segment named "default". In the folder that
contains your database you will find the following files:
default.0.oda
default.odh
The first file is the one that contains the real data. The '0' in the name indicates that
more successive data files can be created for this cluster. You can split a data segment
into multiple real files. This behavior depends on your configuration. When a data
segment file is full, a new file will be used.
NOTE (again, but it can't be said too many times): You can move real files in your
file system only by using the OrientDB APIs.
1426
1427
Clusters
OrientDB uses clusters to store links to the data. A cluster is a generic way to group
records. It is a concept that does not exist in the Relational world, so it is something that
readers from the relational world should pay particular attention to.
You can use a cluster to group all the records of a certain type, or by a specific value.
Here are some examples of how clusters may be used:
Use the cluster "Person" to group all the records of type "Person". This may at first
look very similar to the RDBMS tables, but be aware that the concept is quite
different.
Use the cluster "Cache" to group all the records most accessed.
Use the cluster "Today" to group all the records created today.
Use the cluster "CityCar" to group all the city cars.
If you have a background from the RDBMS world, you may benefit to think of a cluster
as a table (at least in the beginning). OrientDB uses a cluster per "class" by default, so
the similarities may be striking at first. However, as you get more advanced, we strongly
recommend that you spend some time understanding clustering and how it differs from
RDBMS tables.
Note: If you used an earlier version of OrientDB. The concept of "Logical Clusters"
are not supported after the introduction of version 1.0.
1428
Persistent Cluster
Also called Physical cluster, it stores data on disk.
1429
In-Memory cluster
The information stored in "In-Member clusters" is volatile (that is, it is never stored to
disk). Use this cluster only to work with temporary data. If you need an In-Memory
database, create it as an In-memory Database. In-memory databases have only In-
memory clusters.
1430
Limits
Below are the limitations of the OrientDB engine:
Indexes can be up to 2 Billion per database. There are no limitations regarding the
number of indexes per class
Queries can return a maximum of 2 Billion rows, no matter the number of the
properties per record
1431
Limitations running distributed
OrientDB v 2.0.x has some limitations you should notice when you work in Distributed
Mode:
1432
RidBag
RidBag is a data structure that manages multiple RIDs. It is a collection without an order
that could contain duplication. Actually the bag (or multi-set) is similar to set, but could
hold several instances of the same object.
1433
Why it doesn't implement java
java.util.Collection
The first goal of RidBag is to be able efficiently manage billions of entries. In the same
time it should be possible to use such collection in the remote. The main restriction of
such case is amount of data that should be sent over the network.
1434
How it works
RidBag has 2 modes:
Embedded - has list-like representation and serialize its content right in document
Tree-based - uses external tree-based data structure to manages its content. Has
some overhead over embedded one, but much more efficient for many records.
By default newly created RidBags are embedded and they are automatically converted
to tree-based after reaching a threshold. The automatic conversion in opposite direction
is disabled by default due to an issues in remote mode. However you can use it if you
are using OrientDB embedded and don't use remote connections.
The conversion is always done on server and never on client. Firstly it allows to avoid a
lot of issues related to simultaneous conversions. Secondly it allows to simplify the
clients.
1435
Configuration
RidBag could be configured with OGlobalConfiguration.
RID_BAG_EMBEDDED_TO_SBTREEBONSAI_THRESHOLD ( ridBag.embeddedToSbtreeBonsaiThreshold ) -
The threshold of LINKBAG conversion to sbtree-based implementation. Default
value: 80.
RID_BAG_SBTREEBONSAI_TO_EMBEDDED_THRESHOLD ( ridBag.sbtreeBonsaiToEmbeddedToThreshold ) -
The threshold of LINKBAG conversion to embedded implementation. Disabled by
default.
1436
Interaction with remote clients
NOTE: This topic is rather for contributors or driver developers. OrientDB users
don't have to care about bag internals.
As been said rid bag could be represented in two ways: embedded and tree-based. The
first implementation serializes its entries right into stream of its owner. The second one
serializes only a special pointer to an external data structure.
In the same time the server could automatically convert the bag from embedded to tree-
based during save/commit. So client should be aware of such conversion because it can
hold an instance of rid bag.
To "listen" for such changes client should assign a temporary collection id to bag.
Client Server
| |
V |
/---------\ Record content [that contain bag with uuid] |
| |------------------------------------------------------->|
| Send | | Convert to tree
| command | | and save to disk
| to server | Response with changes (A new collection pointer) |
| |<-------------------------------------------------------/
\---------/ the target of new identity assignment
| identified by temporary id
|
V
/-----------------------------\
| Update a collection pointer |
| to be able perform actions |
| with remote tree |
\-----------------------------/
1437
Serialization.
NOTE: This topic is rather for contributors or driver developers. OrietnDB users
don't have to care about bag serialization
Save and load operations are performed during save/load of owner of RidBag. Other
operations are performed separately and have its own commands in binary protocol.
To get definitive syntax of each network command see Network Binary Protocol
1438
Serialization during save and load
The bag is serialized in a binary format. If it is serialized into document by CSV serializer
it's encoded with base64.
(config:byte)[(temp_id:uuid:optional)](content.md)
The first byte is reserved for configuration. The bits of config byte define the further
structure of binary stream:
(size:int)(link:rid)*
If bag is tree based it doesn't serialize the content it serialize just a collection pointer
that points where the tree structure is saved:
(collectionPointer)(size:int)(changes)
The cached size value is also saved to stream. It don't have to be recalculated in most
cases.
The changes part is used by client to send changes to server. In all other cases size of
cahnges is 0
1439
Size of rid bag
Calculation of size for embedded rid bag is straight forward. But what about tree-based
bag.
The issue there that we probably have some changes on client that have not been send
to the server. On the other hand we probably have billions of records in bag on server.
So we can't just calculate size on server because we don't know how to apply changes
readjust that size regarding to changes on client. And in the same time calculation of
size on client is inefficient because we had to iterate over big amount of records over the
network.
Client ask server for RidBag size and provide client changes
Server apply changes in memory to calculate size, but doesn't save them to bag.
New entries (documents that have never been saved) are not sent to server for
recalculation, and the size is adjusted on client. New entries doesn't have an identity
yet, but rid bag works only with identities. So to prevent miscalculation it is easier to
add the count of not saved entries to calculated bag size on client.
Request:
(treePointer:collectionPointer)(changes)
Response:
(size:int)
1440
Iteration over tree-based RidBag
Iteration over tree-based RidBag could be implemented with
REQUEST_SBTREE_BONSAI_GET_ENTRIES_MAJOR and
REQUEST_SBTREE_BONSAI_FIRST_KEY.
Server doesn't know anything about client changes. So iterator implementation should
apply changes to the result before returning result to the user.
1441
Serialization of rid bag changes
(changesSize:int)[(link:rid)(changeType:byte)(value:int)]*
Diff - value defines how the number of entries is changed for specific link.
Absolute - sets the number of entries of specified link. The number defined by
value field.
1442
Serialization of collection pointer
(fileId:long)(pageIndex:long)(pageOffset:int)
1443
SQL parser syntax
BNF token specification
DOCUMENT START
TOKENS
<DEFAULT> SKIP : {
" "
| "\t"
| "\n"
| "\r"
}
1444
| <RPAREN: ")">
| <LBRACE: "{">
| <RBRACE: "}">
| <LBRACKET: "[">
| <RBRACKET: "]("0"-"7"].md))*)">
| <SEMICOLON: ";">
| <COMMA: ",">
| <DOT: ".">
| <AT: "@">
}
1445
| <TRAVERSE: ("T" | "t") ("R" | "r") ("A" | "a") ("V" | "v") ("E" | "e") ("R" | "r") ("S" | "s"
}
<DEFAULT> TOKEN : {
<IDENTIFIER: <LETTER> (<PART_LETTER>)**>
| <#LETTER: [| <#PART_LETTER: ["0"-"9","A"-"Z","_","a"-"z"]("A"-"Z","_","a"-"z"]>.md)>
}
NON-TERMINALS
Rid := "#" <INTEGER_LITERAL> <COLON> <INTEGER_LITERAL>
| <INTEGER_LITERAL> <COLON> <INTEGER_LITERAL>
/** Root production. **/ OrientGrammar := Statement <EOF>
Statement := ( SelectStatement | DeleteStatement | InsertStatement | UpdateStatement )
SelectStatement := <SELECT> ( Projection )? <FROM> FromClause ( <WHERE> WhereClause )? ( OrderB
DeleteStatement := <DELETE> <FROM> <IDENTIFIER> ( <WHERE> WhereClause )?
UpdateStatement := <UPDATE> ( <IDENTIFIER> | Cluster | IndexIdentifier ) ( ( <SET> UpdateItem (
UpdateItem := <IDENTIFIER> <EQ> ( <NULL> | <STRING_LITERAL> | Rid | <INTEGER_LITERAL> | <FLOATI
UpdateAddItem := <IDENTIFIER> <EQ> ( <STRING_LITERAL> | Rid | <INTEGER_LITERAL> | <FLOATING_POI
InsertStatement := <INSERT> <INTO> ( <IDENTIFIER> | Cluster ) <LPAREN> <IDENTIFIER> (
InsertExpression := <NULL>
| <STRING_LITERAL>
| <INTEGER_LITERAL>
| <FLOATING_POINT_LITERAL>
| Rid
| <CHARACTER_LITERAL>
| <LBRACKET> Rid ( "," Rid )** <RBRACKET>
InputParameter := "?"
Projection := ProjectionItem ( "," ProjectionItem )**
ProjectionItem := "**"
| ( ( <NULL> | <INTEGER_LITERAL> | <STRING_LITERAL> | <FLOATING_POINT_LITERAL> | <CHARACTER_LI
FilterItem := <NULL>
| Any
| All
| <INTEGER_LITERAL>
| <STRING_LITERAL>
| <FLOATING_POINT_LITERAL>
| <CHARACTER_LITERAL>
| FunctionCall
| DottedIdentifier
| RecordAttribute
| ThisOperation
| InputParameter
Alias := <IDENTIFIER>
Any := "any()"
All := "all()"
RecordAttribute := <RECORD_ATTRIBUTE>
ThisOperation := <THIS> ( FieldOperator )**
FunctionCall := <IDENTIFIER> <LPAREN> ( "**" | ( FilterItem ( "," FilterItem )** ) ) <RPAREN> (
FieldOperator := ( <DOT> <IDENTIFIER> <LPAREN> ( FilterItem ( "," FilterItem )** )? <RPAREN> )
| ( "[<STRING_LITERAL> "](".md)" )
DottedIdentifier := <IDENTIFIER> ( "[WhereClause "](".md)" )+
| <IDENTIFIER> ( FieldOperator )+
| <IDENTIFIER> ( <DOT> DottedIdentifier )?
FromClause := FromItem
FromItem := Rid
| <LBRACKET> Rid ( "," Rid )** <RBRACKET>
| Cluster
| IndexIdentifier
| <IDENTIFIER>
1446
Cluster := "cluster:" <IDENTIFIER>
IndexIdentifier := "index:" <IDENTIFIER>
WhereClause := OrBlock
OrBlock := AndBlock ( <OR> AndBlock )**
AndBlock := ( NotBlock ) ( <AND> ( NotBlock ) )**
NotBlock := ( <NOT> )? ( ConditionBlock | ParenthesisBlock )
ParenthesisBlock := <LPAREN> OrBlock <RPAREN>
ConditionBlock := TraverseCondition
| IsNotNullCondition
| IsNullCondition
| BinaryCondition
| BetweenCondition
| ContainsCondition
| ContainsTextCondition
| MatchesCondition
CompareOperator := EqualsCompareOperator
| LtOperator
| GtOperator
| NeOperator
| NeqOperator
| GeOperator
| LeOperator
| InOperator
| NotInOperator
| LikeOperator
| ContainsKeyOperator
| ContainsValueOperator
LtOperator := <LT>
GtOperator := <GT>
NeOperator := <NE>
NeqOperator := <NEQ>
GeOperator := <GE>
LeOperator := <LE>
InOperator := <IN>
NotInOperator := <NOT> <IN>
LikeOperator := <LIKE>
ContainsKeyOperator := <CONTAINSKEY>
ContainsValueOperator := <CONTAINSVALUE>
EqualsCompareOperator := <EQ>
BinaryCondition := FilterItem CompareOperator ( Rid | FilterItem )
BetweenCondition := FilterItem <BETWEEN> FilterItem <AND> FilterItem
IsNullCondition := FilterItem <IS> <NULL>
IsNotNullCondition := FilterItem <IS> <NOT> <NULL>
ContainsCondition := FilterItem <CONTAINS> <LPAREN> OrBlock <RPAREN>
ContainsAllCondition := FilterItem <CONTAINSALL> <LPAREN> OrBlock <RPAREN>
ContainsTextCondition := FilterItem <CONTAINSTEXT> ( <STRING_LITERAL> | DottedIdentifier )
MatchesCondition := FilterItem <MATCHES> <STRING_LITERAL>
TraverseCondition := <TRAVERSE> ( <LPAREN> <INTEGER_LITERAL> ( "," <INTEGER_LITERAL> (
TraverseFields := <STRING_LITERAL>
OrderBy := <ORDER> <BY> <IDENTIFIER> ( "," <IDENTIFIER> )** ( <DESC> | <ASC> )?
Limit := <LIMIT> <INTEGER_LITERAL>
Range := <RANGE> Rid ( "," Rid )?
DOCUMENT END
1447
Custom Index Engine
(Since OrientDB v 1.7)
1448
Entry Points
The entry points for creating a new Index Engine are two:
OIndexFactory
OIndexEngine
1449
Implementing OIndexFactory
Create your own facory that implements OIndexFactory.
package com.orientechnologies.lucene;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import com.orientechnologies.lucene.index.OLuceneFullTextIndex;
import com.orientechnologies.lucene.index.OLuceneSpatialIndex;
import com.orientechnologies.lucene.manager.*;
import com.orientechnologies.lucene.shape.OShapeFactoryImpl;
import com.orientechnologies.orient.core.db.record.ODatabaseRecord;
import com.orientechnologies.orient.core.db.record.OIdentifiable;
import com.orientechnologies.orient.core.exception.OConfigurationException;
import com.orientechnologies.orient.core.index.OIndexFactory;
import com.orientechnologies.orient.core.index.OIndexInternal;
import com.orientechnologies.orient.core.metadata.schema.OClass;
import com.orientechnologies.orient.core.record.impl.ODocument;
/**
* Created by enricorisa on 21/03/14.
*/
public class OLuceneIndexFactory implements OIndexFactory {
static {
final Set<String> types = new HashSet<String>();
types.add(OClass.INDEX_TYPE.UNIQUE.toString());
types.add(OClass.INDEX_TYPE.NOTUNIQUE.toString());
types.add(OClass.INDEX_TYPE.FULLTEXT.toString());
types.add(OClass.INDEX_TYPE.DICTIONARY.toString());
types.add(OClass.INDEX_TYPE.SPATIAL.toString());
TYPES = Collections.unmodifiableSet(types);
}
static {
final Set<String> algorithms = new HashSet<String>();
1450
algorithms.add(LUCENE_ALGORITHM);
ALGORITHMS = Collections.unmodifiableSet(algorithms);
}
public OLuceneIndexFactory() {
}
@Override
public Set<String> getTypes() {
return TYPES;
}
@Override
public Set<String> getAlgorithms() {
return ALGORITHMS;
}
@Override
public OIndexInternal<?> createIndex(ODatabaseRecord oDatabaseRecord, String indexType, String algorith
String valueContainerAlgorithm, ODocument metadata) throws OConfigurationException {
return createLuceneIndex(oDatabaseRecord, indexType, valueContainerAlgorithm, metadata);
}
To plug your factory create in your project under META-INF/services a text file called
com.orientechnologies.orient.core.index.OIndexFactory and write inside your factory
Example
com.orientechnologies.lucene.OLuceneIndexFactory
1451
Implementing OIndexEngine
To write a new Index Engine implements the OIndexEngine interface.
get
put
1452
Create Index from Sql
You can create an index with your Index Engine with sql with this syntax
1453
Contribute to OrientDB
In order to contribute issues and pull requests, please sign OrientDB's Contributor
License Agreement. The purpose of this agreement is to protect users of this codebase
by ensuring that all code is free to use under the stipulations of the Apache2 license.
1454
Pushing into main repository
If you'd like to contribute to OrientDB with a patch follow the following steps:
if all the tests pass then do a Pull Request (PR) against "develop" branch on
GitHub and write a comment about the change. Don't sent PR to "master" because
we use that only for releasing
1455
Code formatting
You can find eclipse java formatter config file here: _base/ide/eclipse-formatter.xml
If you use IntelliJ IDEA you can install this plugin and use formatter profile mentioned
above.
1456
Issue priorities
As soon as github issues does not provide way to manage issue prioritization, priorities
of issues are defined as tags.
Priority Definition
Medium The Issue hasnt impact on the OrientDB operation and can be
bypassed with a round trip.
1457
The Team
If you want to contribute to the project, follow the Contributor rules.
1458
Committers
Committers have reached the Joda Level OrientDB certification. They coordinates
updates, patches, new tasks and answer actively to the Google Group. They talk in a
private Mailing List to take decision all together. All the committers refer to the
Committer's guide.
1459
Luca Garulli
Description Luca is the original author of OrientDB product
and the main committer. In order to handle indexes in
efficient way Luca has created the new MVRB-Tree
algorithm (it was called RB+Tree but another different
algorithm already exists with this name) as mix of Red-Black
Tree and B+Tree. MVRB stands for Multi Value Red Black
because stores multiple values in each tree node instead of
just one as RB-Tree does. MVRB-Tree consumes less than half memory of the RB-Tree
implementation mantaining the original speed while it balances the tree on
insertion/update. Furthermore the MVRB-Tree allows fast retrieving and storing of nodes
in persistent way. He is member of the Sun Microsystems JDO 1.0 Expert Group
(JSR#12) and JDO 2.0 Expert Group (JSR#243) for the writing of JDO standard.
Company Orient Technologies Ltd
Links Twitter - Google+ - VisualizeMe - LinkedIn - Blog - Ohloh
Since 2009
1460
Artem Orobets
Description Committer since 2012 and contributor since
2011. He started diving into indexes, composite indexes and
many other was introduced.
He have deep knowledge about the MVRB-Tree algorithm,
the optimization of the indexes on queries, Transactions and
Binary storage.
Company Orient Technologies Ltd
Links Twitter LinkedIn
Since 2012
1461
Andrey Lomakin
Description Committer since 2012 and contributor since
2011. He started diving into indexes, composite indexes and
many other was introduced.
He is:
1462
Luca Molino
Description Contributor since 2010 and committer since
2012 Luca is author of various Http commands and the
network protocol multipart management; author of the v1.0
ObjectDatabase implementation; author of the centralized
Fetching strategy; author of the FIND REFERENCES SQL
command; author of the ttl bash orient console; worked on
SQL commands, Storage creation\deleting and more.
Company Asset Data
Links Twitter GitHub
Since 2012
1463
Contributors
Contributors are all the people that contribute in any way to the OrientDB development
as code, tests, documentation or other. They talk in a private Mailing List with all the
other committers and contributors and are updated on changes in internal stuff like
binary protocol. One time patch doesn't make you a contributor, but if you're developing
a driver or you sent more patches then you are a candidate to figure in this list.
1464
Anton Terekhov
Description Web developer since 2001, PHP developer
since 2002. Developer and maintainer of OrientDB-PHP
driver for binary protocol
(https://github.com/AntonTerekhov/OrientDB-PHP), bug
hunter, binary protocol tester :-) . Speaker on two Russian
IT-conferences. Founder, CEO and Lead Developer of own
company. Now specialized at high load, distributed web
systems.
Company NetMonsters
Links Facebook
Since 2011
1465
Artyom Loginov
Description Artem took part in MMAP file improvement
Since 2011
1466
Dino Ciuffetti
Description Dino is responsable of the Cloud infrastructure of NuvolaBase, providing
OrientDB databases as service. He develop in PHP but his main skill is System
Administrator and hacking on Linux platforms.
Since 2012
1467
Federico Fissore
Description Federico references to himself in the third
person and develops the node.js driver, which powers its
baby creature, http://presentz.org
Links GitHub Twitter LinkedIn Google+
Since
1468
Gabriel Petrovay
Description Gabriel has been started the node.js OrientDB
driver that implements the binary protocol. This helped
discovering some problems in the binary protocol. Also
helped a little with the corresponding documentation pages.
Links Twitter LinkedIn
Since 2012
1469
Johann Sorel
Description Java Developer specialized in Geographic Information Systems (GIS). Core
developer on Geotoolkit project (http://www.geotoolkit.org) and related projects :
GeoAPI, Mapfaces, Constellation, MDWeb, Puzzle-GIS. Member at the Open
Geospatial Consortium (OGC) for elaboration of geographic specifications. Contributions
on OrientDB are related to modularisation and performances.
Company Geomatys
Links Web Site Ohloh
Since 2013, contributors since 2012
1470
Rus V. Brushkoff
Description Contributed C++ binding
(https://github.com/Sfinx/orientpp)
Company SfinxSoft
Links LinkedIn
Since 2012
1471
Tomas Bosak
Description Tomas is developing and maintaining C# binary protocol driver for
OrientDB.
Company ONXPO
Links Home Page GitHub Twitter LinkedIn
Since 2012
1472
Hackaton
Hackatons are the appointement where OrientDB old and new committers and
contributors work together in few hours, on the same spot, or connected online.
1473
The draft rules are (please contribute to
improve it):
1. Committers will support contributors and new users on Hackaton
2. A new Google Hangout will be created, so if you want to attendee please send me
your gmail/gtalk account
3. We'll use the hangout to report to the committer issues to close, or any questions
about issues
4. We'll start from current release (1.7) and then go further (2.0, 2.1, no-release-tag)
5. If the issue is pretty old (>4 months), comment it about trying the last 1.7-rc2. We
could have some chance the issue has already been fixed
6. If the problem is with a SQL query, you could try to reproduce against the
GratefulDeadConcerts database or even an empty database. If you succeed on
reproduce it, please comment with additional information about the issue
1474
Contribution from Java Developers
1. If you're a Java developer and you can debug inside OrientDB code (that's would be
great) you could include more useful information about the issue or even fix it
2. If you think the issue has been fixed with your patch, please run all the test cases
with:
ant clean test
mvn clean test
3. If all tests pass, send us a Pull Request (see below)
1475
Contribution to the Documentation
1. We're aware to have not the best documentation of the planet, so if you can improve
on this would be awesome
2. JavaDoc, open a Java class, and:
i. add the JavaDoc at the top of the class. This is the most important
documentation in code we can have. if it's pertinent
ii. add the JavaDoc for the public methods. It't better having a description about
the method than the detail of all the parameters, exceptions, etc
1476
Send a Pull Request!
We use GitHub and it's fantastic to work in a team. In order to make our life easier, the
best way to contribute is with a Pull Request:
1. Goto your GitHub account. if you don't have it, create it in 2 minutes:
www.github.com
2. Fork this project: https://github.com/orientechnologies/orientdb, or any other projects
you want to contribute
3. Commit locally against the "develop" branch
4. Push your changes to your forked repository on GitHub
5. Send us a Pull Request and wait for the merging
1477
Report an Issue
Very often when a new issue is open it lacks some fundamental information. This slows
down the entire process because the first question from the OrientDB team is always
"What release of OrientDB are you using?" and every time a Ferret dies in the world.
1. OrientDB release? (If you're using a SNAPSHOT please attach also the build
number found in "build.number" file)
2. What steps will reproduce the problem? 1. 2. 3.
3. Settings. If you're using custom settings please provide them below (to dump all the
settings run the application using the JVM argument -
Denvironment.dumpCfgAtStartup=true)
4. What is the expected behavior or output? What do you get or see instead?
5. If you're describing a performance or memory problem the profiler dump can be
very useful (to dump it run the application using the JVM arguments -
Dprofiler.autoDump.reset=true -Dprofiler.autoDump.interval=10 -
Dprofiler.enabled=true)
1478
Get in touch
We want to make it super-easy for OrientDB users and contributors to talk to us and
connect with each other, to share ideas, solve problems and help make OrientDB
awesome. Here are the main channels we're running currently, we'd love to hear from
you on one of them:
1479
Google Group
OrientDB Google Group
The OrientDB Google Group (aka Community Group) is a good first stop for a general
inquiry about OrientDB or a specific support issue (e.g. trouble setting OrientDB up). It's
also a good forum for discussions about the roadmap or potential new functionality.
1480
Gitter.io
The best Web Chat, where we have an open channel. Use this is you have a question
about OrientDB.
1481
IRC
#orientdb
We're big fans of IRC here at OrientDB. We have a #orientdb channel on Freenode -
stop by and say hi, you can even use Freenode's webchat service so don't need to
install anything to access it.
1482
Twitter
@orientechno
1483
GitHub
OrientDB issues
If you spot a bug, then please raise an issue in our main GitHub project
orientechnologies/orientdb. Likewise if you have developed a cool new feature or
improvement in your OrientDB fork, then send us a pull request against the "develop"
branch!
If you want to brainstorm a potential new feature, then the OrientDB Google Group (see
above) is probably a better place to start.
1484
Email
[email protected]
If you want more information about Commercial Support, Consultancy or Training, email
us.
1485
Table of Contents
Introduction 1
Getting Started 5
Multi-Model Database 7
Installation 12
Run the server 15
Run the console 17
Classes 19
Clusters 22
Record ID 22
SQL 29
Relationships 32
Working with Graphs 38
Using Schema with Graphs 43
Setup a Distributed Database 47
Working with Distributed Graphs 52
Java API 55
More on Tutorials 58
Presentations 61
Basic Concepts 67
Supported Types 76
Inheritance 79
Schema 83
Cluster Selection 91
Fetching Strategies 94
Indexes 101
SB-Tree 101
Hash 101
Full Text 120
Lucene Full Text 122
Lucene Spatial 124
Security 129
SSL 146
Caching 152
Functions 157
Transaction 175
Hook - Triggers 175
Dynamic Hooks 187
Java (Native) Hooks 190
API 196
1486
Graph or Document API? 200
SQL 203
Filtering 212
Functions 223
Methods 248
Batch 272
Pagination 279
Sequences and auto increment 279
Commands 285
Java API 429
Graph API 434
Document API 494
Object API 538
Traverse 598
Multi-Threading 604
Transactions 612
Binary Data 614
Web Apps 622
Server Management 627
JDBC Driver 632
JPA 637
Gremlin API 642
Javascript 665
Javascript API 672
Scala API 690
HTTP API 697
Binary Protocol 735
CSV Serialization 801
Schemaless Serialization 806
Commands 816
Use Cases 819
Time Series 821
Key Value 825
Server 836
Embed the Server 848
Plugins 854
Automatic Backup 866
Mail 869
JMX 875
Studio 877
Query 882
Edit Document 882
1487
Edit Vertex 882
Schema 887
Class 890
Graph Editor 893
Functions 893
Security 902
Database Management 906
Server Management 909
Console 912
Backup 921
Begin 926
Browse Class 930
Browse Cluster 933
Classes 936
Clusters 939
Commit 943
Config 947
Config Get 951
Config Set 955
Connect 959
Create Cluster 963
Create Database 967
Create Index 973
Create Link 976
Create Property 979
Declare Intent 983
Delete 983
Dictionary Get 987
Dictionary Keys 990
Dictionary Put 993
Dictionary Remove 996
Disconnect 999
Display Record 1002
Drop Cluster 1005
Drop Database 1008
Export 1012
Export Record 1018
Freeze DB 1021
Get 1025
Grant 1029
Import 1032
Info 1038
1488
Info Class 1041
Insert 1044
Load Record 1047
Profiler 1050
Properties 1053
Release DB 1057
Reload Record 1061
Restore 1064
Revoke 1069
Rollback 1072
Set 1076
Operations 1080
Installation 1084
Install with Docker 1087
Install as Service on Unix/Linux 1095
Install as Service on Windows 1097
Performance Tuning 1105
Setting Configuration 1118
Graph API 1135
Document API 1147
Object API 1149
Profiler 1151
ETL 1185
Configuration 1190
Blocks 1197
Sources 1201
Extractors 1205
Transformers 1207
Loaders 1220
Import from CSV to a Graph 1223
Import from JSON 1230
Import from RDBMS 1234
Import from DB-Pedia 1238
Import from Parse (Facebook) 1240
Distributed Architecture 1243
Lifecycle 1249
Configuration 1257
Server Manager 1269
Replication 1271
Sharding 1277
Cache 1288
Backup and Restore 1289
1489
Export and Import 1295
Export format 1300
Import From RDBMS 1300
Import From Neo4j 1326
Logging 1331
Enterprise Edition 1335
Troubleshooting 1340
Java 1346
Available Plugins 1352
Rexster 1356
Gephi Graph Render 1361
Upgrade 1369
Backward compatibility 1374
From 1.7.x to 2.0.x 1376
From 1.6.x to 1.7.x 1384
From 1.5.x to 1.6.x 1386
From 1.4.x to 1.5.x 1388
From 1.3.x to 1.4.x 1390
Internals 1390
Storages 1390
Memory storage 1390
PLocal storage 1399
Local storage (deprecated) 1423
Clusters 1427
Limits 1430
RidBag 1432
SQL Syntax 1443
Custom Index Engine 1447
Contribute to OrientDB 1453
The Team 1457
Hackaton 1472
Report an issue 1472
Get in touch 1478
1490