Skip to content

This is the multi-page printable view of this section. .

Return to the regular view of this page.

Graph Query Languages

HugeGraph supports two mainstream graph query languages: Gremlin (imperative traversal language) and Cypher (declarative pattern matching language).

  • Gremlin: The core graph traversal language of Apache TinkerPop, offering rich traversal primitives and fine control over complex topological paths.
  • Cypher: The declarative query language standardized by openCypher, featuring intuitive SQL-like patterns (MATCH ... WHERE ... RETURN) for Neo4j parity.

Language Guides & References

  • HugeGraph-Gremlin

    Gremlin traversal fundamentals, CRUD query examples, and TinkerPop feature support.

  • HugeGraph Cypher

    Declarative Cypher language support, read/write statement examples, execution mechanics, and constraints.

  • Cypher Compatibility

    Coverage matrix for Cypher clauses and functions, known behavior differences, and workarounds for unsupported features.

  • Migrate from Neo4j

    Core differences between Neo4j and HugeGraph in graph modeling, ID strategies, multiple labels, and query translation.

  • Sample Graph Data

    The classic TitanDB “Graph of the Gods” sample graph dataset (12 vertices) used across query examples.

Related Tools & Entry Points

Ways to interact with and execute graph queries across HugeGraph components:

1 - HugeGraph Gremlin

Overview

HugeGraph supports Gremlin, a graph traversal query language of Apache TinkerPop3. While SQL is a query language for relational databases, Gremlin is a general-purpose query language for graph databases, enabling entity creation, property modification, deletion, and traversal queries.

For developers seeking declarative pattern matching (similar to SQL or Neo4j style), HugeGraph also supports Cypher.

Note

HugeGraph is powered by the TinkerPop 3.8.1 engine (running on Java 17 and Groovy 4.0.25). Upgrading from an older version? Review the Gremlin & TinkerPop Migration Guide for removed legacy syntax and behavioral changes.

TinkerPop Features

HugeGraph implements the TinkerPop framework, but not all TinkerPop features are implemented.

The table below lists the support status of various TinkerPop features in HugeGraph:

Graph Features

NameDescriptionSupport
ComputerDetermines if the {@code Graph} implementation supports {@link GraphComputer} based processingfalse
TransactionsDetermines if the {@code Graph} implementations supports transactions.true
PersistenceDetermines if the {@code Graph} implementation supports persisting it’s contents natively to disk.This feature does not refer to every graph’s ability to write to disk via the Gremlin IO packages(.e.g. GraphML), unless the graph natively persists to disk via those options somehow. For example,TinkerGraph does not support this feature as it is a pure in-sideEffects graph.Backend-dependent
ThreadedTransactionsDetermines if the {@code Graph} implementation supports threaded transactions which allow a transaction be executed across multiple threads via {@link Transaction#createThreadedTx()}.false
ConcurrentAccessDetermines if the {@code Graph} implementation supports more than one connection to the same instance at the same time. For example, Neo4j embedded does not support this feature because concurrent access to the same database files by multiple instances is not possible. However, Neo4j HA could support this feature as each new {@code Graph} instance coordinates with the Neo4j cluster allowing multiple instances to operate on the same database.false

Vertex Features

NameDescriptionSupport
UserSuppliedIdsDetermines if an {@link Element} can have a user defined identifier. Implementation that do not support this feature will be expected to auto-generate unique identifiers. In other words, if the {@link Graph} allows {@code graph.addVertex(id,x)} to work and thus set the identifier of the newly added {@link Vertex} to the value of {@code x} then this feature should return true. In this case, {@code x} is assumed to be an identifier data type that the {@link Graph} will accept.true
NumericIdsDetermines if an {@link Element} has numeric identifiers as their internal representation. In other words,if the value returned from {@link Element#id()} is a numeric value then this method should be return {@code true}. Note that this feature is most generally used for determining the appropriate tests to execute in the Gremlin Test Suite.false
StringIdsDetermines if an {@link Element} has string identifiers as their internal representation. In other words, if the value returned from {@link Element#id()} is a string value then this method should be return {@code true}. Note that this feature is most generally used for determining the appropriate tests to execute in the Gremlin Test Suite.true
UuidIdsDetermines if an {@link Element} has UUID identifiers as their internal representation. In other words,if the value returned from {@link Element#id()} is a {@link UUID} value then this method should be return {@code true}.Note that this feature is most generally used for determining the appropriate tests to execute in the Gremlin Test Suite.false
CustomIdsDetermines if an {@link Element} has a specific custom object as their internal representation.In other words, if the value returned from {@link Element#id()} is a type defined by the graph implementations, such as OrientDB’s {@code Rid}, then this method should be return {@code true}.Note that this feature is most generally used for determining the appropriate tests to execute in the Gremlin Test Suite.true
AnyIdsDetermines if an {@link Element} any Java object is a suitable identifier. TinkerGraph is a good example of a {@link Graph} that can support this feature, as it can use any {@link Object} as a value for the identifier. Note that this feature is most generally used for determining the appropriate tests to execute in the Gremlin Test Suite. This setting should only return {@code true} if {@link #supportsUserSuppliedIds()} is {@code true}.false
AddPropertyDetermines if an {@link Element} allows properties to be added. This feature is set independently from supporting “data types” and refers to support of calls to {@link Element#property(String, Object)}.true
RemovePropertyDetermines if an {@link Element} allows properties to be removed.true
AddVerticesDetermines if a {@link Vertex} can be added to the {@code Graph}.true
MultiPropertiesDetermines if a {@link Vertex} can support multiple properties with the same key.true
DuplicateMultiPropertiesDetermines if a {@link Vertex} can support non-unique values on the same key. For this value to be {@code true}, then {@link #supportsMetaProperties()} must also return true. By default this method, just returns what {@link #supportsMultiProperties()} returns.true
MetaPropertiesDetermines if a {@link Vertex} can support properties on vertex properties. It is assumed that a graph will support all the same data types for meta-properties that are supported for regular properties.false
RemoveVerticesDetermines if a {@link Vertex} can be removed from the {@code Graph}.true

Edge Features

NameDescriptionSupport
UserSuppliedIdsDetermines if an {@link Element} can have a user defined identifier. Implementation that do not support this feature will be expected to auto-generate unique identifiers. In other words, if the {@link Graph} allows {@code graph.addVertex(id,x)} to work and thus set the identifier of the newly added {@link Vertex} to the value of {@code x} then this feature should return true. In this case, {@code x} is assumed to be an identifier data type that the {@link Graph} will accept.false
NumericIdsDetermines if an {@link Element} has numeric identifiers as their internal representation. In other words,if the value returned from {@link Element#id()} is a numeric value then this method should be return {@code true}. Note that this feature is most generally used for determining the appropriate tests to execute in the Gremlin Test Suite.false
StringIdsDetermines if an {@link Element} has string identifiers as their internal representation. In other words, if the value returned from {@link Element#id()} is a string value then this method should be return {@code true}. Note that this feature is most generally used for determining the appropriate tests to execute in the Gremlin Test Suite.true
UuidIdsDetermines if an {@link Element} has UUID identifiers as their internal representation. In other words,if the value returned from {@link Element#id()} is a {@link UUID} value then this method should be return {@code true}.Note that this feature is most generally used for determining the appropriate tests to execute in the Gremlin Test Suite.false
CustomIdsDetermines if an {@link Element} has a specific custom object as their internal representation.In other words, if the value returned from {@link Element#id()} is a type defined by the graph implementations, such as OrientDB’s {@code Rid}, then this method should be return {@code true}.Note that this feature is most generally used for determining the appropriate tests to execute in the Gremlin Test Suite.true
AnyIdsDetermines if an {@link Element} any Java object is a suitable identifier. TinkerGraph is a good example of a {@link Graph} that can support this feature, as it can use any {@link Object} as a value for the identifier. Note that this feature is most generally used for determining the appropriate tests to execute in the Gremlin Test Suite. This setting should only return {@code true} if {@link #supportsUserSuppliedIds()} is {@code true}.false
AddPropertyDetermines if an {@link Element} allows properties to be added. This feature is set independently from supporting “data types” and refers to support of calls to {@link Element#property(String, Object)}.true
RemovePropertyDetermines if an {@link Element} allows properties to be removed.true
AddEdgesDetermines if an {@link Edge} can be added to a {@code Vertex}.true
RemoveEdgesDetermines if an {@link Edge} can be removed from a {@code Vertex}.true

Data Type Features

NameDescriptionSupport
BooleanValuestrue
ByteValuestrue
DoubleValuestrue
FloatValuestrue
IntegerValuestrue
LongValuestrue
MapValuesSupports setting of a {@code Map} value. The assumption is that the {@code Map} can contain arbitrary serializable values that may or may not be defined as a feature itselffalse
MixedListValuesSupports setting of a {@code List} value. The assumption is that the {@code List} can contain arbitrary serializable values that may or may not be defined as a feature itself. As this{@code List} is “mixed” it does not need to contain objects of the same type.false
BooleanArrayValuesfalse
ByteArrayValuestrue
DoubleArrayValuesfalse
FloatArrayValuesfalse
IntegerArrayValuesfalse
LongArrayValuesfalse
SerializableValuesfalse
StringArrayValuesfalse
StringValuestrue
UniformListValuesSupports setting of a {@code List} value. The assumption is that the {@code List} can contain arbitrary serializable values that may or may not be defined as a feature itself. As this{@code List} is “uniform” it must contain objects of the same type.false (supported via Schema valueList())

Gremlin Steps

HugeGraph supports all steps of Gremlin. For complete reference information about Gremlin, please refer to the Apache TinkerPop 3.8.1 official documentation.

StepDescriptionDocumentation
addEAdd an edge between two vertices.addE step
addVAdd vertices to graph.addV step
andMake sure all traversals return values.and step
asStep modulator for assigning variables to the step’s output.as step
byStep modulators used in conjunction with group and order.by step
coalesceReturns the first traversal that returns a result.coalesce step
constantReturns a constant value. Used in conjunction with coalesce.constant step
countReturns a count from the traversal.count step
datetimeCreates a datetime object or retrieves current server time (returns OffsetDateTime).datetime function
dedupReturns values with duplicates removed.dedup step
discardDiscards all current traversers (replaces parameterless none()).discard step
dropDiscards a value (vertex/edge).drop step
foldActs as a barrier for computing aggregated values from results.fold step
groupGroups values based on specified labels.group step
hasUsed to filter properties, vertices, and edges. Supports hasLabel, hasId, hasNot, and has variants.has step
injectInjects values into the stream.inject step
isUsed to filter by a Boolean expression.is step
limitUsed to limit the number of items in a traversal.limit step
localLocally wraps a part of a traversal, similar to a subquery.local step
notUsed to generate the negation result of a filter.not step
optionalReturns the result of a specified traversal if it generates any results, otherwise returns the calling element.optional step
orEnsures that at least one traversal returns a value.or step
orderReturns results in the specified order.order step
pathReturns the full path of the traversal.path step
projectProjects properties as a map.project step
propertiesReturns properties with specified labels.properties step
rangeFilters based on a specified range of values.range step
repeatRepeats a step a specified number of times. Used for looping.repeat step
sampleUsed to sample results returned by the traversal.sample step
selectUsed to project the results returned by the traversal.select step
mergeVMatches vertices by property; updates if present, creates if absent (standard upsert).mergeV step
mergeEMatches edges by property and endpoints; updates if present, creates if absent (standard upsert).mergeE step
treeAggregate the paths in vertices into a tree.tree step
unfoldUnfolds an iterator as a step.unfold step
unionCombines the results of multiple traversals.union step
VTraversal steps between vertices and edges: V, E, out, in, both, outE, inE, bothE, outV, inV, bothV, and otherVvertex steps
whereFilters traversal results. Supports eq, neq, lt, lte, gt, gte, and between operators.where step

2 - HugeGraph Cypher

Overview

HugeGraph supports Cypher, the declarative graph query language originally created by Neo4j and standardized as openCypher. While Gremlin is an imperative traversal language, Cypher lets you describe the graph pattern you want (MATCH, WHERE, RETURN) and lets the engine decide how to execute it.

HugeGraph supports the openCypher 9 syntax subset, parsing declarative pattern queries directly and bridging them seamlessly to the underlying TinkerPop graph traversal engine. For complete coverage and boundaries, see Cypher Compatibility.

When to use Cypher vs Gremlin

Use Cypher whenUse Gremlin when
You are migrating from Neo4j or already know CypherYou need the full HugeGraph feature surface
You want declarative pattern matching (MATCH (a)-[:KNOWS]->(b))You need fine-grained traversal control, custom steps, or lambdas
Your queries are read-mostly patterns and projectionsYou need graph algorithms, OLAP, or features Cypher does not expose

For anything Cypher cannot express, the equivalent Gremlin query always works — examples below show both.

Calling the Cypher API

Cypher statements are submitted to the HugeGraph Server through the REST endpoint:

1GET  /graphspaces/{graphspace}/graphs/{graph}/cypher?cypher={statement}
2POST /graphspaces/{graphspace}/graphs/{graph}/cypher

When authentication is enabled, Cypher requests require an Authorization header, supporting Basic (standard RFC 4648 Base64, e.g. curl -u) or Bearer <token> (requests without credentials return 401). When authentication is disabled, no Authorization header is required. See the Cypher REST API reference for the full request and response format.

Example:

1curl -H "Authorization: Bearer $TOKEN" \
2  "http://localhost:8080/graphspaces/DEFAULT/graphs/hugegraph/cypher?cypher=MATCH%20(n:person)%20RETURN%20n.name%20LIMIT%2010"

From the Java client, use CypherManager (see hugegraph-client):

1ResultSet resultSet = hugeClient.cypher().execute("MATCH (n:person) RETURN n.name LIMIT 10");

Basic examples

The examples below assume a graph with person vertices (name, age, city properties) and knows edges. Before running them, note:

  • Property predicates in WHERE (such as WHERE n.age > 30) require covering indexes (e.g. a RANGE index on person.age).
  • On schemas with non-nullable properties or PRIMARY_KEY strategy, create statements must provide required attributes and primary keys; create vertices with complete properties separately before creating connecting edges.

Read — MATCH / WHERE / RETURN

1// All persons named "marko"
2MATCH (n:person) WHERE n.name = 'marko' RETURN n
1// Projection with ordering and limit
2MATCH (n:person)
3WHERE n.age > 30
4RETURN n.name AS name, n.age AS age
5ORDER BY age DESC
6LIMIT 10
1// Relationship pattern
2MATCH (a:person)-[:knows]->(b:person)
3WHERE a.name = 'marko'
4RETURN b.name AS friend

Create — CREATE

1// Create a vertex
2CREATE (n:person {name: 'alice', age: 32, city: 'beijing'})
1// Create two vertices, then an edge between them (send each statement as its own request)
2CREATE (:person {name: 'bob'})
3CREATE (:person {name: 'carol'})
4MATCH (a:person), (b:person)
5WHERE a.name = 'bob' AND b.name = 'carol'
6CREATE (a)-[:knows]->(b)

Update — SET / REMOVE

1MATCH (n:person) WHERE n.name = 'alice'
2SET n.age = 33
3REMOVE n.city

Delete — DELETE / DETACH DELETE

1// Delete an edge
2MATCH (a:person)-[r:knows]->(b:person)
3WHERE a.name = 'bob' AND b.name = 'carol'
4DELETE r
1// Delete a vertex and all its edges
2MATCH (n:person) WHERE n.name = 'alice'
3DETACH DELETE n

Aggregation

1// Total count
2MATCH (n:person) RETURN count(n) AS total
1// Grouped count
2MATCH (n:person) RETURN n.city AS city, count(*) AS cnt ORDER BY cnt DESC

Gremlin equivalents

Every Cypher statement is translated to Gremlin internally. When a Cypher feature is unsupported, write the traversal directly:

CypherGremlin equivalent
MATCH (n:person) WHERE n.name='marko' RETURN ng.V().hasLabel('person').has('name','marko')
MATCH (a)-[:knows]->(b) RETURN bg.V().out('knows')
CREATE (n:person {name:'x'})g.addV('person').property('name','x')
MATCH (n) DETACH DELETE ng.V().drop()
MATCH (n:person) RETURN count(n)g.V().hasLabel('person').count()

Tip: You can inspect generated underlying Gremlin traversals via EXPLAIN MATCH (n:person) RETURN n (in the translation field of the response) to draft equivalent traversals. PROFILE is not supported.

Limitations

  • Parameterized query rules: Parameter bindings are supported via JSON request bodies ({"cypher": "...", "parameters": {...}}, up to 16 top-level parameters; group additional properties into a nested Map and reference fields explicitly). Referencing an undeclared $param results in an execution error; explicit null is supported.
  • Partial clause coverage: Certain advanced openCypher constructs (such as map projections and complex functions) are currently unsupported and fail during parsing and validation.
  • No CALL procedures: Graph algorithms (shortest path, k-out, personalrank, etc.) are available via the traverser REST APIs or Gremlin instead of Cypher CALL procedures.
  • Single statement per request: Multi-statement scripts are not supported; submit one statement per call.

When a statement fails validation or execution, the server returns structured error details under status.attributes.errors with code, message, and hint. The Gremlin equivalent is the recommended fallback.

Further reading

3 - Cypher Compatibility

Scope and Overview

HugeGraph supports declarative openCypher 9 queries on top of the TinkerPop engine. This page summarizes supported request forms, parameter binding rules, syntax coverage, and behavioral boundaries.

The endpoint is /graphspaces/{graphspace}/graphs/{graph}/cypher. For query examples and Gremlin equivalents, see the HugeGraph Cypher Guide.

Request Forms and Parameter Bindings

Request FormContent-TypeDescription
POST (Recommended)application/jsonJSON body {"cypher": "...", "parameters": {...}}, supports parameter bindings
POSTapplication/jsonRaw Cypher text string body (for unparameterized raw statements)
GET—Query parameter ?cypher=<URL-encoded statement>, suitable for simple read queries

Example JSON parameterized request:

1{
2  "cypher": "MATCH (n:person) WHERE n.name = $name RETURN n.name",
3  "parameters": {"name": "marko"}
4}

Parameter Binding Rules

  • Parameter Format: The cypher field must be a non-empty string; parameters, if provided, must be a JSON object (omitted means an empty map).
  • Parameter Count: The top-level parameters object accepts at most 16 keys. For more properties, group them into a nested Map and reference fields explicitly in the statement (e.g. $props.name).
  • Unbound Variables: Referencing an undeclared $param raises an execution error and is rejected (explicit null is supported).
  • Reserved Marker: The exact string " cypher.null" (two leading spaces) is reserved by the engine as an internal sentinel and is rejected in parameter values.
  • Error Response: A malformed request body returns HTTP 400 with the standard error body. Translation and execution errors return HTTP 200 with status.code 400 (and null result), with structured details (code, message, hint) in status.attributes.errors.

Syntax and Feature Support Matrix

CategorySupported FeaturesNotes
Reads & PatternsLabel scans, equality and range predicates, boolean logic (AND/OR/NOT), directed 1-hop and multi-hop patterns, regex matching (=~ full match)Range comparisons require corresponding indexes
Results & ProjectionNode and scalar projections, aliases (AS), property access, nested structures, relationship IDs, path expressions, null handlingResults are mapped to standard JSON structures
Aggregation & Orderingcount, sum, min, max, avg, DISTINCT, ORDER BY, SKIP, LIMITMapped to underlying graph traversal steps
Data WritesVertex and edge CREATE, property SET / REMOVE, edge and vertex DELETE / DETACH DELETECreate vertices with required properties before creating connecting edges

Write Constraints and Considerations

On schemas with non-nullable properties or PRIMARY_KEY strategy, the shorthand CREATE (a)-[:knows]->(b) fails due to non-null property validation (checkNonnullProperty) or missing primary keys. Execute vertex and edge creations separately, ensuring required vertex attributes are fully specified.

Unsupported Features

The following advanced features are currently unsupported; use Gremlin or the respective REST APIs:

  • Complex Clauses: MERGE, UNION, variable-length paths (*1..3);
  • Procedures: CALL dbms.* / CALL algo.* (use the Traverser REST API);
  • Schema Management: Cypher Schema DDL (use the Schema REST API);
  • Protocols & Drivers: Bolt protocol and drivers (use the HTTP REST API or HugeGraph Client).

4 - Migrating from Neo4j

Overview

For developers migrating from Neo4j or evaluating HugeGraph. HugeGraph supports openCypher declarative query syntax, but differences exist in the graph model, schema rules, parameter bindings, and indexing. For language usage and compatibility references, see HugeGraph Cypher and Cypher Compatibility.

What carries over directly

Neo4j conceptHugeGraph equivalent
Property graph model (nodes / relationships / properties)Same — vertex labels / edge labels / properties
Core Cypher: MATCH/WHERE/RETURN/CREATE/SET/DELETEWorks as-is (REST /cypher endpoint or Java client CypherManager), subject to the schema and index rules below
Simple aggregations (count/sum/min/max/avg)Works as-is
Traversal-heavy queriesGremlin traversals or the traverser REST APIs (k-out, shortest path, personalrank, …)

Habits you need to change

In Neo4jIn HugeGraph
CREATE INDEX / CREATE CONSTRAINTCreate property indexes through the IndexLabel REST API; uniqueness constraints map to UNIQUE IndexLabels; node keys map to non-nullable keys plus a composite UNIQUE index; property existence constraints map to non-nullable keys on VertexLabels or EdgeLabels. Note that primary_keys defines vertex identity, not a uniqueness constraint — a duplicate CREATE overwrites the existing vertex instead of failing
Implicit schema (add properties freely)Strong schema: define VertexLabel / EdgeLabel / PropertyKey before writing data
Property predicates in WHERE need no indexThe starting vertex lookup in WHERE needs a covering index unless it is an equality on every primary key of the label. Use RANGE for > / < comparisons. Without a covering index the request returns HTTP 200 with status.code 400 and a “not indexed” error
Parameterized queries $paramParameterized requests are supported via JSON body (up to 16 top-level parameters; group additional values into a nested Map); missing parameters result in execution errors
CALL dbms.* / CALL algo.* proceduresEquivalent capabilities are in the traverser, task, and other REST APIs
Driver: Neo4j Bolt driverhugegraph-client (CypherManager) or any HTTP client
Transaction boundaries inside a Cypher statementOne statement per request; graph-to-graph migration uses Apache SeaTunnel 3.0.0 (preferred, see below), file-based bulk loads use the HugeGraph Loader

On PRIMARY_KEY labels, a UNIQUE index cannot include all primary-key fields (the server rejects it). To keep duplicate-rejection behavior, use a CUSTOMIZE_STRING label keyed on the Neo4j node id and add a UNIQUE index on the business key.

Suggested migration path

  1. Inventory your queries: Review your application’s Cypher queries against the Cypher Compatibility Notes and Limitations to classify them into “works as-is”, “rewrite as Gremlin”, or “switch to a REST API”.

  2. Create the schema first: define VertexLabel / EdgeLabel / PropertyKey and indexes through the schema API — HugeGraph requires the schema to exist before data is written.

  3. Import data: the preferred path is Apache SeaTunnel 3.0.0 (released 2026-09-29) running Neo4j Source → HugeGraph Sink directly — no intermediate file export. REST remains fine for small datasets; the HugeGraph Loader stays an alternative for file-based imports. HugeGraph-side setup (environment, mappings, vertex/edge import examples) is covered in the Import Graph Data with SeaTunnel Sink guide.

    The SeaTunnel 3.0.0 connector docs document what to rely on:

    • Neo4j Source reads Cypher query results with explicit field schemas; 3.0.0 adds multi-table reads via tables_configs.
    • HugeGraph Sink is refactored in 3.0.0 with multi-mapping support — use the recommended mappings configuration for vertices/edges and follow its schema-creation behavior. By default, the Sink fails fast on errors (batch_failure_fallback=false and max_insert_errors=0). Record skipping is opt-in via batch_failure_fallback=true; if enabled, capture and reconcile skipped records and compare row counts before cutover.
    • HugeGraph Source is new in 3.0.0 (schema auto-discovery, multi-label/parallel reads), enabling HugeGraph export and migration workflows.

    Map Neo4j properties to HugeGraph PropertyKeys and pick the vertex ID strategy before importing. The Sink requires idFields for every vertex strategy other than AUTOMATIC, and edge mappings need separate sourceConfig.idFields and targetConfig.idFields, so the Neo4j query must return the field that carries the ID:

    • idStrategy = "PRIMARY_KEY": put a Neo4j business key in idFields and express edge endpoints through those same key fields.
    • idStrategy = "CUSTOMIZE_STRING": this alone does not keep the Neo4j node id. Make the Neo4j query return the id you want to keep as its own column (aliased, for example AS node_id), declare that field in the Source schema.fields (it must match the fields the query returns), set the vertex idFields to it, and map the matching edge endpoint fields in sourceConfig.idFields and targetConfig.idFields.

    Labels you pre-created in step 2 must use that same strategy — automatic creation does not convert an existing PRIMARY_KEY label into CUSTOMIZE_STRING. The Sink mappings configuration can create the missing PropertyKey, VertexLabel and EdgeLabel definitions, so those three parts of step 2 are optional when you use it; it does not create IndexLabels, so create any index your queries rely on (see the habits table above) separately. When SeaTunnel auto-creates EdgeLabels, omitting frequency defaults to SINGLE, which collapses parallel Neo4j relationships between the same endpoints into a single edge. To preserve parallel relationships, explicitly specify frequency = "MULTIPLE" and provide stable relationship discriminator fields as sortKeys in the edge mapping (HugeGraph uses sort keys to distinguish parallel edges). Load vertices before edges. We recommend thoroughly testing the import pipeline with a representative data sample before cutover.

  4. Switch incrementally: keep queries Cypher supports, and rewrite unsupported constructs as Gremlin — the equivalents table shows the mapping.

Limitations at a glance

  • Statements and parameters: Multi-statement scripts and CALL procedures are not supported; parameter binding supports up to 16 top-level parameters (pass a nested Map for additional properties).
  • Unverified syntax: Advanced openCypher constructs not covered in the compatibility matrix are unverified and may fail during query validation; established limitations are listed above.
  • Fallback path: Unsupported query constructs can typically be rewritten as Gremlin traversals — see the equivalents table; schema DDL and procedures map to REST APIs instead.

5 - HugeGraph Examples

1 Overview

This example uses the TitanDB Getting Started guide as a template to demonstrate how to use HugeGraph. By comparing HugeGraph and TitanDB, you can understand the differences between them.

1.1 Similarities and Differences between HugeGraph and TitanDB

Both HugeGraph and TitanDB are graph databases based on the Apache TinkerPop3 framework. They both support the Gremlin graph query language and share many similarities in terms of usage and interfaces. However, HugeGraph is a completely new design and development, characterized by its clear code structure, richer features, and more user-friendly interfaces.

Compared to TitanDB, HugeGraph’s main features are as follows:

  • HugeGraph currently offers a comprehensive suite of tools, including HugeGraph-API, HugeGraph-Client, HugeGraph-Loader, HugeGraph-Studio, and HugeGraph-Spark. These components facilitate system integration, data loading, visual graph querying, Spark connectivity, and other functionalities.
  • HugeGraph incorporates the concepts of Server and Client, allowing third-party systems to connect via multiple methods such as JAR references, clients, and APIs. In contrast, TitanDB only supports connections via JAR references.
  • HugeGraph requires explicit schema definition, and all insertions and queries must pass strict schema validation. Implicit schema creation is not supported at the moment.
  • HugeGraph makes full use of the characteristics of the underlying storage system to achieve efficient data access, whereas TitanDB ignores the differences of the backend with a unified Kv structure.
  • HugeGraph’s update operations can be performed on-demand (e.g., updating a specific attribute), offering better performance. TitanDB uses a read-and-update approach for updates.
  • Both VertexId and EdgeId in HugeGraph support concatenation, allowing for automatic deduplication and better query performance. In TitanDB, all IDs are auto-generated and require indexing for queries.

1.2 Character Relationship Graph

This example uses the Property Graph Model to describe the relationships between characters in Greek mythology, also known as the character relationship graph. The specific relationships are shown in the diagram below.

image

In the diagram, circular nodes represent entities (Vertices), arrows represent relationships (Edges), and the content in the boxes represents attributes.

There are two types of vertices in this graph: characters and locations, as shown in the table below:

NameTypeAttributes
charactervertexname,age,type
locationvertexname

There are six types of relationships: father, mother, brother, battled, lives, and pet. The details of these relationships are as follows:

NameTypeSource Vertex LabelTarget Vertex LabelAttributes
fatheredgecharactercharacter-
motheredgecharactercharacter-
brotheredgecharactercharacter-
battlededgecharactercharactertime
petedgecharactercharacter-
livesedgecharacterlocationreason

An edge label can be linked to more than one pair of source and target vertex labels: call link(sourceLabel, targetLabel) once per pair when creating it. The deprecated sourceLabel() and targetLabel() builder methods accept only a single pair.

In this example, the original TitanDB’s monster, god, human, and demigod are all represented using the same vertex label: character in HugeGraph, with an additional type attribute to indicate the type of character. The edge labels remain consistent with the original TitanDB.

2 Graph Schema and Data Ingest Examples

HugeGraph requires explicit schema creation, which involves creating PropertyKeys, VertexLabels, and EdgeLabels in sequence. If indexing is needed, IndexLabels must also be created.

2.1 Graph Schema

The snippets assume a local Groovy script has opened HugeGraph as graph and set g = graph.traversal(). Start with the Gremlin Console local-mode example, whose scripts/example.groovy creates both variables. In a remote Console, g is a Server-side traversal-source alias and there is no local graph object; use the Schema REST API for remote schema creation.

 1import org.apache.tinkerpop.gremlin.structure.T
 2import org.apache.tinkerpop.gremlin.structure.Vertex
 3
 4schema = graph.schema()
 5g = graph.traversal()
 6
 7schema.propertyKey("name").asText().ifNotExist().create()
 8schema.propertyKey("age").asInt().ifNotExist().create()
 9schema.propertyKey("time").asInt().ifNotExist().create()
10schema.propertyKey("reason").asText().ifNotExist().create()
11schema.propertyKey("type").asText().ifNotExist().create()
12
13schema.vertexLabel("character").properties("name", "age", "type").primaryKeys("name").nullableKeys("age").ifNotExist().create()
14schema.vertexLabel("location").properties("name").primaryKeys("name").ifNotExist().create()
15
16schema.edgeLabel("father").link("character", "character").ifNotExist().create()
17schema.edgeLabel("mother").link("character", "character").ifNotExist().create()
18schema.edgeLabel("battled").link("character", "character").properties("time").ifNotExist().create()
19schema.edgeLabel("lives").link("character", "location").properties("reason").nullableKeys("reason").ifNotExist().create()
20schema.edgeLabel("pet").link("character", "character").ifNotExist().create()
21schema.edgeLabel("brother").link("character", "character").ifNotExist().create()

2.2 Graph Data

 1// add vertices
 2Vertex saturn = graph.addVertex(T.label, "character", "name", "saturn", "age", 10000, "type", "titan")
 3Vertex sky = graph.addVertex(T.label, "location", "name", "sky")
 4Vertex sea = graph.addVertex(T.label, "location", "name", "sea")
 5Vertex jupiter = graph.addVertex(T.label, "character", "name", "jupiter", "age", 5000, "type", "god")
 6Vertex neptune = graph.addVertex(T.label, "character", "name", "neptune", "age", 4500, "type", "god")
 7Vertex hercules = graph.addVertex(T.label, "character", "name", "hercules", "age", 30, "type", "demigod")
 8Vertex alcmene = graph.addVertex(T.label, "character", "name", "alcmene", "age", 45, "type", "human")
 9Vertex pluto = graph.addVertex(T.label, "character", "name", "pluto", "age", 4000, "type", "god")
10Vertex nemean = graph.addVertex(T.label, "character", "name", "nemean", "type", "monster")
11Vertex hydra = graph.addVertex(T.label, "character", "name", "hydra", "type", "monster")
12Vertex cerberus = graph.addVertex(T.label, "character", "name", "cerberus", "type", "monster")
13Vertex tartarus = graph.addVertex(T.label, "location", "name", "tartarus")
14
15// add edges
16jupiter.addEdge("father", saturn)
17jupiter.addEdge("lives", sky, "reason", "loves fresh breezes")
18jupiter.addEdge("brother", neptune)
19jupiter.addEdge("brother", pluto)
20neptune.addEdge("lives", sea, "reason", "loves waves")
21neptune.addEdge("brother", jupiter)
22neptune.addEdge("brother", pluto)
23hercules.addEdge("father", jupiter)
24hercules.addEdge("mother", alcmene)
25hercules.addEdge("battled", nemean, "time", 1)
26hercules.addEdge("battled", hydra, "time", 2)
27hercules.addEdge("battled", cerberus, "time", 12)
28pluto.addEdge("brother", jupiter)
29pluto.addEdge("brother", neptune)
30pluto.addEdge("lives", tartarus, "reason", "no fear of death")
31pluto.addEdge("pet", cerberus)
32cerberus.addEdge("lives", tartarus)
33
34graph.tx().commit()

2.3 Indices

HugeGraph by default automatically generates IDs. However, if a user specifies the primaryKeys field list for a VertexLabel through primaryKeys, the ID strategy for that VertexLabel will automatically switch to the primaryKeys strategy. Once the primaryKeys strategy is enabled, HugeGraph generates VertexId by concatenating vertexLabel+primaryKeys, which allows for automatic deduplication. Additionally, there is no need to create extra indexes to use the properties in primaryKeys for fast querying. For example, both “character” and “location” have the primaryKeys("name") attribute, so without creating additional indexes, vertices can be queried using g.V().hasLabel('character').has('name','hercules').

3 Graph Traversal Examples

3.1 Traversal Query

1. Find the grandfather of hercules

1g.V().hasLabel('character').has('name','hercules').out('father').out('father')

It can also be done using the repeat method:

1g.V().hasLabel('character').has('name','hercules').repeat(__.out('father')).times(2)

2. Find the name of Hercules’s father

1g.V().hasLabel('character').has('name','hercules').out('father').value('name')

3. Find the characters with age > 100

1g.V().hasLabel('character').has('age',gt(100))

4. Find who are pluto’s cohabitants

1g.V().hasLabel('character').has('name','pluto').out('lives').in('lives').values('name')

5. Find pluto can’t be his own cohabitant

1pluto = g.V().hasLabel('character').has('name', 'pluto')
2g.V(pluto).out('lives').in('lives').where(is(neq(pluto))).values('name')
3
4// use 'as'
5g.V().hasLabel('character').has('name', 'pluto').as('x').out('lives').in('lives').where(neq('x')).values('name')

6. Pluto’s Brothers

1pluto = g.V().hasLabel('character').has('name', 'pluto').next()
2// where do pluto's brothers live?
3g.V(pluto).out('brother').out('lives').values('name')
4
5// which brother lives in which place?
6g.V(pluto).out('brother').as('god').out('lives').as('place').select('god','place')
7
8// what is the name of the brother and the name of the place?
9g.V(pluto).out('brother').as('god').out('lives').as('place').select('god','place').by('name')

It is recommended to use HugeGraph-Hubble to execute the above code visually. Additionally, the code can be executed through various other methods such as HugeGraph-Client, HugeGraph-Api, GremlinConsole, and GremlinDriver.

3.2 Summary

HugeGraph currently supports Gremlin syntax, and users can implement various query requirements through Gremlin / REST-API.