JanusGraph

JanusGraph is an open-source distributed graph database that runs on top of an existing wide-column store (Apache Cassandra, ScyllaDB, HBase, or BerkeleyDB) for storage and an external indexing system (Elasticsearch, Solr, or Lucene) for full-text and geo queries. JanusGraph is the spiritual successor to Titan, forked by IBM, Google, Hortonworks, and others in 2017. It uses Apache TinkerPop’s Gremlin as its query language and is the standard choice when Neo4j’s single-node scale is insufficient.

1. Key Features:

2. JanusGraph vs. Neo4j:

3. Use Cases:

4. Architecture

JanusGraph is a layer over pluggable backends Gremlin clients Java, Python, JS, .NET JanusGraph Server Gremlin Server + TinkerPop Storage backend Cassandra, ScyllaDB, HBase, Bigtable, BerkeleyDB Index backend Elasticsearch, OpenSearch, Solr, Lucene

JanusGraph is an open-source distributed graph database under the Linux Foundation, forked from Titan in 2017. It does not implement its own disk storage. Instead it maps the property-graph model onto a wide-column or key-value store, and delegates full-text, geo and range queries to an external search engine. Queries are written in Gremlin, the traversal language of Apache TinkerPop, and are executed either embedded in a JVM application or through JanusGraph Server, which is a configured Gremlin Server.

This design means JanusGraph scales storage horizontally to the extent the backend does (Cassandra and ScyllaDB scale to very large clusters), and it inherits that backend's consistency and operational characteristics. You operate two or three distributed systems rather than one.

5. Data model: adjacency lists in wide rows

How a vertex is stored in the backend Row key = vertex id partitioned across the cluster Property cells name, age ... Edge cells label, direction, adjacent id Edge properties since, weight

Each vertex becomes one row keyed by its ID. The row's columns hold the vertex properties and every incident edge, sorted by edge label and direction, with the adjacent vertex ID and edge properties encoded in the cell. Fetching a vertex's neighbours is therefore a single row read, and a traversal step is a sequence of row lookups. Vertex-centric indexes sort a vertex's edges by a property so that "the 10 most recent follows" does not have to scan all edges of a high-degree vertex. Composite indexes (exact match, stored in the storage backend) and mixed indexes (in Elasticsearch or Solr) support finding starting vertices by property.

6. Worked example: schema and Gremlin traversals

// Gremlin console (Groovy syntax)
graph = JanusGraphFactory.open('conf/janusgraph-cql-es.properties')
mgmt = graph.openManagement()
name   = mgmt.makePropertyKey('name').dataType(String.class).make()
person = mgmt.makeVertexLabel('person').make()
knows  = mgmt.makeEdgeLabel('knows').multiplicity(MULTI).make()
mgmt.buildIndex('byName', Vertex.class).addKey(name).buildCompositeIndex()
mgmt.commit()

g = graph.traversal()
a = g.addV('person').property('name', 'ana').next()
b = g.addV('person').property('name', 'bo').next()
c = g.addV('person').property('name', 'cy').next()
g.addE('knows').from(a).to(b).iterate()
g.addE('knows').from(b).to(c).iterate()
graph.tx().commit()

// friends of friends of ana, excluding ana
g.V().has('person', 'name', 'ana').out('knows').out('knows')
     .where(neq(a)).dedup().values('name')          // ==> cy

// shortest path between two people (up to 4 hops)
g.V().has('name', 'ana').repeat(out('knows').simplePath())
     .until(has('name', 'cy')).limit(1).path().by('name')

Defining the schema explicitly and creating the composite index before loading data matters: without an index, has('name', 'ana') becomes a full graph scan, and JanusGraph logs a warning (or rejects the query if force-index is enabled).

7. When to use JanusGraph versus alternatives

SystemModelChoose when
JanusGraphProperty graph over Cassandra/HBase/ScyllaDBVery large graphs, you already run those backends, open source required
Neo4j (comparison)Native graph storage, CypherFast deep traversals, strong tooling, single-cluster scale
Amazon NeptuneManaged, Gremlin/openCypher/SPARQLAWS shop wanting no operations
DgraphNative distributed graph, GraphQL/DQLGraphQL-first applications

Because every hop is a backend read over the network, JanusGraph's per-hop latency is higher than a native graph engine that follows in-memory pointers. It favours wide, shallow traversals on huge graphs and bulk analytics through Spark (SparkGraphComputer) over sub-millisecond deep traversals.

8. Pitfalls