Welcome to AjguDB Documentation
Kesako?!
AjguDB is graph database written in Python with several backends. It's meant to be an easy to use, just works persistent graph for people that want to experiment with graph databases. SQLite for graphs, if I may.
Getting started
Create a Graph
You need to choose a storage class and create a graph. There is three storages right now:
ajgu.storage.BSDDB3
the default storage which use Oracle Berkeley Database 5.x or 6.x.ajgu.storage.NoTxnBSDDB3
a bsddb3 backend that is not ACID but fast...ajgu.storage.FileStorage
a file based backend.
You can start graphology as easily as:
from ajgu import Database
from ajgu import BSDDB3
graph = Database(BSDDB3('/path/to/my/super-dupper/database/files'))
If the directory doesn't exists it will be created.
Remember to close the database, when you are finished:
graph.close()
The Mighty Transaction
Every operation must happen in a transaction. For that matter there is a context manager Graph.transaction()
that returns a storage specific transaction class. It must be used as follow:
with graph.transaction() as txn:
txn.vertex.create('my-vertex')
...
...
The transaction will be commited if there is no error.
For advanced use, you can use Graph.txn()
method to create a transaction and manage it yourself. It looks
like the following:
try:
txn = graph.txn()
txn.create_vertex('my-vertex')
...
...
except Exception as exc:
txn.rollback()
else:
txn.commit()
commit
and rollback
are the only public methods of transaction class.
Both Graph.transaction
and Graph.txn
take keyword arguments to configure the transaction. It depends
of the backend. Read the code to know more about the options.
Create a vertex
The transaction object works as a shadow copy of the graph. Otherwise said, its methods reflects the graph structure. You always perform graph operations against it. Once the transaction is commited, changes are persisted and saved.
To create a vertex use Transaction.vertex.create(label)
:
with graph.transaction() as txn:
amirouche = txn.vertex.create('amirouche')
amirouche.properties['age'] = 30
As you can see in the above snippet it's possible to add properties to a vertex
through the properties
attribute just like you do with a normal dictionary.
Values can be anything that can be serialized by msgpack: int
, float
, str
,
list
, dict
and any combination of them.
Vertex
are indexed by their Vertex.label()
. Several vertices can have the same label.
Create an edge
To create an edge you can use Transaction.edge.create(start, label, end)
:
with graph.transaction() as txn:
amirouche = txn.vertex.create("amirouche")
python = txn.vertex.create("python")
txn.edge.create(amirouche 'know', python)
Edge
have also an index on their label, also available as Edge.label()
. Labels don't have be unique
either. start
and end
must be vertices created or retrieve in the current transaction. You can
also edit edge's properties via Edge.properties
attribute.
Transaction.*.get
You can retrieve edge with Transaction.edge.get(identifier)
and vertices with Transaction.vertex.get(identifier
.
Vertices outgoing and incoming edges
Vertex has Vertex.outgoings(label=None)
and Vertex.incomings(label=None)
. They allow to retrieve
edges. The label argument allows to filter based on the edge.label()
of the edge. They return
a generator. They will be explained further below.
Quering
Even querying happens against the transaction. Querying happens through what is called managers, available
at transaction.vertex
and transaction.edge
. Here the lists of their methods:
transaction.element.all()
Return a generator over all elements of a given type.
transaction.element.count()
Return the count of objects for a given type.
transaction.element.slice(start, end)
Return a slice of of elements between start
and end
(excluded) indices.
transaction.element.label(label)
Return a generator over all elements of the given type filtered by label
. You can chain an operator over
the given generator using the following syntax transaction.element.slice.operator
where operator can
be slice
, count
or first
.
transaction.element.filter(key=value)
Return a generator over all the element of the given type filtered by property name key
and value
. You can
chain an operator over the given generator using the following syntax transaction.element.slice.operator
where operator can be slice
, count
or first
.
Only properties that are indexed can be filtered
To create an index over key
use Graph.index(key)
. This will index every elements (edge and vertex) with
the a property.
transaction.element.get(**kwargs)
Return a generator over all elements of the given type filtered by kwargs
you can chain an operator over
the given generator using the following syntax transaction.element.slice.operator
where operator can
be slice
, count
or first
.
Mind the fact that right now only one pair of key/value is supported kwargs
providing more pairs
won't refine the query.
transaction.element.get(identifier)
That one we've already seen allow to retrieve an object by identifier.
transaction.element.create(...)
This one too was presented previously allow to create an element of given type. The signature is different depending on the actual type.