Quickstart

Basic Python examples for how to use Bulbs with Neo4j Server.

Before you begin, make sure you download and install Bulbs and Neo4j Server.

Neo4j Server

Bulbs’ Neo4j Server client is a Python interface to the Neo4j Server REST API.

To use Bulbs with Neo4j Server, you need to make sure Neo4j Server is up and running.

Start Neo4j Server

Change to the directory where you installed Neo4j Server, and start it with its default configuration:

$ cd /path/to/neo4j-<version>
$ bin/neo4j start

Browse Neo4j Server

Now check to see that you can browse the Neo4j Web admin using this URL:

If you can, then success! Neo4j Server is up and running.

The Neo4j Web Admin is a browser-based interface to Neo4j Server that allows you to view elements in the graph and simulate a Gremlin-console session. See the Neo4j Tools documentation for details.

Graph

Ok, now the fun part. This will show you how to use Bulbs to connect to Neo4j Server from Python and interact with the graph database.

Create the Graph Object

Here’s how you create the Graph object, your primary interface to Neo4j Server:

>>> from bulbs.neo4jserver import Graph
>>> g = Graph()

If you don’t pass a Config object to Graph(), Graph will use the default URI and Config.

You you can pass in a custom config, with a uri, username, and password (a username and password is not required by default):

>>> from bulbs.neo4jserver import Graph, Config, NEO4J_URI
>>> config = Config(NEO4J_URI, "james", "secret")
>>> g = Graph(config)

We used the default Neo4j URI:

>>> print NEO4J_URI

http://localhost:7474/db/data/

If you ever change the URI in the server config, you should use your URI instead:

>>> config = Config('http://example.dev:7777/db/data/')
>>> g = Graph(config)

Create Vertices and Edges

Here is a basic example that creates two Vertex objects and an Edge object that links them together:

>>> james = g.vertices.create(name="James")
>>> julie = g.vertices.create(name="Julie")
>>> g.edges.create(james, "knows", julie)

Return a Property

>>> james.name

Update an Existing Property

>>> james.name = "James Thornton"
>>> james.save()

Add New Properties

>>> james.city = "Dallas"
>>> james.age = 34
>>> james.save()

Return the Property Data Map

>>> james.data()

Get Vertex by ID

>>> james.eid
1
>>> james2 = g.vertices.get(1)
>>> assert james == james2

Update Vertex by ID

>>> data = dict(age=34, city="Dallas")
>>> g.vertices.update(1, data)

Display Vertices

Display all the vertices in the graph:

>>> g.V

This returns a list all the Vertex objects in the graph.

This method is primarily used for testing because you won’t normally want to do this for a large database containing millions (or billions) of vertices.

You can see how many vertices were returned by checking the length of the list:

>>> vertices = g.V
>>> len(vertices)

Display Edges

Display all the edges in the graph:

>>> g.E

Like g.V, this method is primarily used for testing because you won’t normally want to do this for a large database.

Look Up Indexed Vertices

The default Bulbs Config class has autoindex set to True, with “vertex” as the name of the default Vertex index. When autoindex is True, it will automatically index vertices when you create or update them.

Everytime you create a new vertex, it’s automatically added to vertex index, and you can look it up by its properties.

This will return all the vertices that have a “name” property with a value of “James”:

>>> g.vertices.index.lookup(name="James")

As you can see, the return value is a Python generator.

A generator is iterable like a list, but it’s more memory friendly because it’s not copying the entire list around – it lazy loads items as needed:

>>> vertices = g.vertices.index.lookup(name="James")
>>> for vertex in vertices: print vertex

Get the next Vertex in the generator:

>>> vertices = g.vertices.index.lookup(name="James")
>>> james = vertices.next()

To convert a generator into a list, do this:

>>> vertices = g.vertices.index.lookup(name="James")
>>> list(vertices)

Get Adjacent Edges

Get all outgoing edges:

>>> james.outE()

Get outgoing edges labeled “knows”:

>>> james.outE("knows")

Get incoming edges (there shouldn’t be any):

>>> james.inE()

Get all the incoming and outgoing edges:

>>> james.bothE()

Get Adjacent Vertices

An adjacent vertex is a vertex connected to another vertex by an edge.

Get all the outgoing vertices:

>>> james.outV()

Get outgoing vertices connected by edges labeled “knows”:

>>> james.outV("knows")

Get incoming vertices (there shouldn’t be any):

>>> james.inV()

Get all the incoming and outgoing vertices:

>>> james.bothV()

Enable Debugging

Bulbs uses the Python logging facility, and by default it sets the logger to use StreamHandler with log level set to ERROR

To display DEBUG info, set the log level to DEBUG:

>>> from bulbs.config import DEBUG
>>> g.config.set_logger(DEBUG)

Disable Debugging

To disable DEBUG info, set the log level back to ERROR:

>>> from bulbs.config import ERROR
>>> g.config.set_logger(ERROR)

Models

Model Declaration

You can also use Bulbs to create type-checked, domain-specific models:

# people.py

from bulbs.model import Node, Relationship
from bulbs.property import String, Integer, DateTime
from bulbs.utils import current_datetime

class Person(Node):

    element_type = "person"

    name = String(nullable=False)
    age = Integer()


class Knows(Relationship):

    label = "knows"

    created = DateTime(default=current_datetime, nullable=False)

Example Usage

Models provide type checking and validation to ensure that your database properties are stored properly.

Here’s how you would use the models to create and connect Person objects:

>>> from people import Person, Knows
>>> from bulbs.neo4jserver import Graph
>>> g = Graph()

Add proxy interfaces to the Graph object for each custom Model:

>>> g.add_proxy("people", Person)
>>> g.add_proxy("knows", Knows)

Create two Person nodes, which are automatically saved in the DB:

>>> james = g.people.create(name="James")
>>> julie = g.people.create(name="Julie")

Lookup people using the Person model’s primary index:

>>> nodes = g.people.index.lookup(name="James")

Connect James and Julie by creating a “knows” relationship between them:

>>> relationship = g.knows.create(james, julie)

Get the people James knows (the outgoing vertices labeled “knows”):

>>> friends = james.outV('knows')

Get the people that know Julie (the incoming vertices labeled “knows”):

>>> friends = julie.inV('knows')

Return the relationship element’s ID:

>>> relationship.eid

Return the created property:

>>> relationship.created

Return all the property data:

>>> relationship.data()

Return the label:

>>> relationship.label()

Return the outgoing vertex:

>>> relationship.outV()

Return the incoming vertex:

>>> relationship.inV()

Return the outgoing vertex ID:

>>> relationship._outV

Return the incoming vertex ID:

>>> relationship._inV

Gremlin

Using the Neo4j Web console is sometimes convienent, but most of the time I use the external Gremlin REPL to experiment with queries.

Create a neo4j.groovy file with the path to your neo4j/data/graph.db directory:

// neo4j.groovy
import org.neo4j.kernel.EmbeddedReadOnlyGraphDatabase
db = new EmbeddedReadOnlyGraphDatabase('/path/to/neo4j/data/graph.db')
g = new Neo4jGraph(db)

And then load neo4j.groovy when you start a Gremlin REPL:

$ cd /path/to/gremlin
$ ./gremlin.sh

         \,,,/
         (o o)
-----oOOo-(_)-oOOo-----
gremlin> load neo4j.groovy
gremlin> g.V.range(0,9)  // try viewing the first 10 vertices in the graph