CGWire
Published in

CGWire

Photo by William Bout on Unsplash

CG Pipeline: The Best Graph Database for Your CG Production Data

Example use case

To explore these databases, we propose to implement the data graph of the props animation described in our previous article named CG production as a Graph. The approach will be to store the steps required to build the props and include it in a given shot.

Main databases

The main databases we will study are the following:

Cayley

Cayley is a graph database distributed by Google written in Go. It looks promising on many aspects (configurable backend, community driven) but currently the documentation is close to inexistant. The best source of information is a forum dedicated to it. Whatever, let’s see what we can do with.

./cayley init -db bolt -dbpath /tmp/testdb
./cayley http --dbpath=/tmp/testdb --host 0.0.0.0 --port 64210
pip install pyley
def create_quad(quad):
path = “http://localhost:64210/api/v1/write"
return requests.post(path, json=[quad])
quads = [
{
“subject”: “props1-concept”,
“predicate”: “dependencyof”,
“object”: “props1-texture”
},
{
“subject”: “props1-concept”,
“predicate”: “dependencyof”,
“object”: “props1-mesh”
},
{
“subject”: “props1-texture”,
“predicate”: “dependencyof”,
“object”: “props1-model”
},
{
“subject”: “props1-mesh”,
“predicate”: “dependencyof”,
“object”: “props1-model”
},
{
“subject”: “props1-mesh”,
“predicate”: “dependencyof”,
“object”: “props1-rig”
},
{
“subject”: “props1-mesh”,
“predicate”: “dependencyof”,
“object”: “props1-keys”
}
{
“subject”: “props1-rig”,
“predicate”: “dependencyof”,
“object”: “props1-keys”
},
{
“subject”: “props1-model”,
“predicate”: “dependencyof”,
“object”: “shot1-image-sequence”
},
{
“subject”: “props1-keys”,
“predicate”: “dependencyof”,
“object”: “shot1-image-sequence”
}
]
for quad in quads:
create_quad(quad)
from pyley import CayleyClient, GraphObject
client = CayleyClient("http://localhost:64210", "v1")
graph = GraphObject()
query = graph.V(“props1-mesh”)
.Out()
.All()

Neo4j

Neo4j is the most mature solution of all. The enterprise behind it offers compelling entreprise solution for support and extra features (monitoring, backup, improved querying…). That’s a big advantage if you need to feel very safe due to hard contracts with your clients. But to start with it, we reommend using the community edition. This is this version that we’ll cover in this article.

docker run \
--publish=7474:7474 --publish=7687:7687 \
--volume=$HOME/neo4j/data:/data \
neo4j
pip install neo4j-driver
from neo4j.v1 import GraphDatabase, basic_authdriver = GraphDatabase.driver(
"bolt://localhost:7687",
auth=basic_auth("neo4j", "tests")
)
session = driver.session()
# session.run("CALL dbms.changePassword('tests')")
def create_asset(name):
session.run(
"MERGE (a:Asset { name: $name })",
name=name
)
def create_shot(name):
session.run(
"MERGE (a:Shot { name: $name })",
name=name
)
def create_relation(asset1, asset2):
session.run(
"MATCH (a:Asset { name: $asset1 }), (b:Asset { name: $asset2 })"
"MERGE (a)-[r:ELEMENT_OF]->(b)",
asset1=asset1, asset2=asset2
)
def create_casting(asset, shot):
session.run(
"MATCH (a:Asset { name: $asset }), (b:Shot { name: $shot })"
"MERGE (a)-[r:CASTED_IN]->(b)",
asset=asset, shot=shot
)
create_asset("Props 1 concept")
create_asset("Props 1 mesh")
create_asset("Props 1 texture")
create_asset("Props 1 rig")
create_asset("Props 1 model")
create_asset("Props 1 keys")
create_shot("Shot 1")
create_relation("Props 1 concept", "Props 1 texture")
create_relation("Props 1 concept", "Props 1 mesh")
create_relation("Props 1 mesh", "Props 1 model")
create_relation("Props 1 texture", "Props 1 model")
create_relation("Props 1 mesh", "Props 1 rig")
create_relation("Props 1 mesh", "Props 1 keys")
create_relation("Props 1 rig", "Props 1 keys")
create_casting("Props 1 model", "Shot 1")
create_casting("Props 1 keys", "Shot 1")
result = session.run(
"MATCH (:Asset { name: 'Props 1 mesh' })-[*]->(out)"
"RETURN out.name as name"
)
for record in result:
print("%s" % record["name"])
session.close()
Displaying of the graph in the neo4j UI

With ArangoDB

ArangoDB is a versatile database that allows document storage and graph storage all along. Recently, it have gained in popularity, it’s the reason why we included it to the test. It comes with handful features like easy deployment on a cloud infrastructure and helpers to build REST API. But for this article we’ll focus on the graph storage and its query system.

docker run -p 8529:8529 -e ARANGO_ROOT_PASSWORD=openSesame arangodb/arangodb:3.2.1
pip install python-arango
from arango.client import ArangoClientclient = ArangoClient(username='root', password='openSesame')
db = client.create_database('cgproduction')
dependencies = db.create_graph('dependencies')shots = dependencies.create_vertex_collection('shots')
assets = dependencies.create_vertex_collection('assets')
casting = dependencies.create_edge_definition(
name='casting',
from_collections=['assets'],
to_collections=['shots']
)
elements = dependencies.create_edge_definition(
name='element',
from_collections=['assets'],
to_collections=['assets']
)
# Insert vertices
assets.insert(
{'_key': 'props1-concept', 'name': 'Props 1 Concept'})
assets.insert(
{'_key': 'props1-texture', 'name': 'Props 1 Texture'})
assets.insert(
{'_key': 'props1-mesh', 'name': 'Props 1 Mesh'})
assets.insert({'_key': 'props1-rig', 'name': 'Props 1 Rig'})
assets.insert({'_key': 'props1-model', 'name': 'Props 1 Model'})
assets.insert({'_key': 'props1-keys', 'name': 'Props 1 Keys'})
shots.insert(
{'_key': 'shot1-image-sequence',
'name': 'Shot 1 Image sequence'})
# Insert edges
elements.insert(
{'_from': 'assets/props1-concept',
'_to': 'assets/props1-texture'})
elements.insert(
{'_from': 'assets/props1-concept',
'_to': 'assets/props1-mesh'})
elements.insert(
{'_from': 'assets/props1-texture',
'_to': 'assets/props1-model'})
elements.insert(
{'_from': 'assets/props1-mesh',
'_to': 'assets/props1-rig'})
elements.insert(
{'_from': 'assets/props1-mesh',
'_to': 'assets/props1-model'})
elements.insert(
{'_from': 'assets/props1-mesh',
'_to': 'assets/props1-keys'})
elements.insert(
{'_from': 'assets/props1-rig',
'_to': 'assets/props1-keys'})
casting.insert(
{'_from': 'assets/props1-model',
'_to': 'shots/shot1-image-sequence'})
casting.insert(
{'_from': 'assets/props1-keys',
'_to': 'shots/shot1-image-sequence'})
traversal_results = dependencies.traverse(
start_vertex=’assets/props1-mesh’,
direction=’outbound’
)
for result in traversal_results[“vertices”]:
print(result[“name”])
The overall web UI is slicker than neo4j UI but the graph representation is less explicit

OrientDB

OrientDB is here for a while now (since 2010). But because of the very bad feedback about it (see comments too), we decided to not cover this database in this article. It’s too risky to use it in a CG production environment.

Alternatives

There are still alternatives. By playing with traditional database, you can have similar features as with graph database. One option is to use Postgres with its recursive joins. It will allow you to cover simple use cases of graph traversal.

Visualisation

Having graph data is great but you may want to build tools that shows your data at some point (and outside of the built-in UIs).

  • ZodiacGraph: a powerful C++ library which is fast and flexible.
  • Nodz: a Python library easy to use.
  • SigmaJS: fast and well documented library
  • Cytoscape: versatile and robust.
  • d3.js: harder to use but limitless.

To conclude

From our study, it looks like ArangoDB is the most user friendly database and its document storage aspect will make your production data management easier. But it’s still a young DB. If you need speed or if there is a lot of money at stake and if you are looking for a safer choice go for Neo4j, which does the job well and looks more robust. Finally Cayley looks good on many aspects has a great design and could be the best choice to complement an already existing relational database, but is still too undocumented and young to be used in production. So, to sum up: try ArangoDB first!

--

--

Posts about Animation Pipeline and Production Management

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store