xrayGraphDB Documentation
Install the engine, connect a client, learn Cypher and GFQL, then explore the complete interactive reference of 395 functions and 125 procedures. Version 1, generated 2026-06-27.
Installation: Docker
Docker is the fastest way to start xrayGraphDB. The image ships with sensible defaults — storage path, ports, and encryption at rest. Pull it, bootstrap an admin on the first run, and you're up.
Before you run anything: raise the host's memory-map limit so the database can start: sudo sysctl -w vm.max_map_count=262144 (persist it in /etc/sysctl.d/).
First run — bootstrap an admin
The daemon refuses connections without an admin user. Pass --init-admin-user and --init-admin-password on the first start to create one. These flags are bootstrap-only — they only create a user when no users exist, and become silent no-ops on every subsequent boot once the admin record is on disk.
# Pull (or `docker load < xraygraphdb-4.9.4-docker.tar.gz` for the offline tarball) docker pull xraygraphdb.emtailabs.com/xraygraphdb:v4.9.4 # First run — creates admin/<your-password> on initial boot docker run -d \ --name xraygraphdb \ --restart unless-stopped \ -p 7689:7689 \ -v xraygraphdb-data:/var/lib/xraygraphdb \ -v xraygraphdb-logs:/var/log/xraygraphdb \ xraygraphdb.emtailabs.com/xraygraphdb:v4.9.4 \ --license-acknowledge-saved=true \ --init-admin-user=admin \ --init-admin-password=YourStrongPassword!23 # Wait ~5s, then confirm the daemon is listening docker logs xraygraphdb | grep "xrayProtocol listening" # Expected: "xrayProtocol listening on 0.0.0.0:7689 with 4 workers"
Security: rotate the bootstrap flags off after the first boot. Once the daemon confirms it's listening, the admin record is persisted in /var/lib/xraygraphdb/auth/ and the --init-admin-* flags do nothing on restart. But they remain visible in three places — docker inspect xraygraphdb (full Args[]), /var/lib/docker/containers/<id>/config.v2.json on the host, and ps aux inside the container. Recreate the container without the bootstrap flags so the password isn't sitting in process args:
docker stop xraygraphdb && docker rm xraygraphdb docker run -d \ --name xraygraphdb \ --restart unless-stopped \ -p 7689:7689 \ -v xraygraphdb-data:/var/lib/xraygraphdb \ -v xraygraphdb-logs:/var/log/xraygraphdb \ xraygraphdb.emtailabs.com/xraygraphdb:v4.9.4 \ --license-acknowledge-saved=true
The named volumes xraygraphdb-data and xraygraphdb-logs persist the database state and logs across container recreations. The data path inside the image is /var/lib/xraygraphdb (matches the daemon's default --data-directory).
Enterprise license (optional)
If you have a license file, mount it read-only at /etc/xraygraphdb/license.xglicense. The daemon auto-detects and validates it on startup:
docker run -d \ --name xraygraphdb \ -p 7689:7689 \ -v xraygraphdb-data:/var/lib/xraygraphdb \ -v /path/to/license.xglicense:/etc/xraygraphdb/license.xglicense:ro \ xraygraphdb.emtailabs.com/xraygraphdb:v4.9.4 \ --license-acknowledge-saved=true docker logs xraygraphdb | grep "License loaded" # Expected: "License loaded: xg-ent-... tier=enterprise org=..."
Without a license, the community-tier graph algorithms (PageRank, BFS, triangle count, betweenness, community detection, and more) run unrestricted. An enterprise license unlocks the additional commercial procedure namespaces.
Docker Compose
services: xraygraphdb: image: xraygraphdb.emtailabs.com/xraygraphdb:v4.9.4 restart: unless-stopped ports: - "7689:7689" volumes: - xraygraphdb-data:/var/lib/xraygraphdb - xraygraphdb-logs:/var/log/xraygraphdb # Optional: Enterprise license # - ./license.xglicense:/etc/xraygraphdb/license.xglicense:ro command: - --license-acknowledge-saved=true # --- FIRST RUN ONLY: uncomment for the first `docker compose up`, # --- then comment back out and `docker compose up -d --force-recreate`. # - --init-admin-user=admin # - --init-admin-password=YourStrongPassword!23 volumes: xraygraphdb-data: xraygraphdb-logs:
docker compose up -d docker compose logs -f xraygraphdb | grep "xrayProtocol listening"
Verify the Server
# Container status docker ps --filter name=xraygraphdb # Daemon ready check — xrayProtocol on 7689 (Bolt is OFF by default; opt-in via --bolt-server-name) docker logs xraygraphdb | grep "xrayProtocol listening" # Expected: "xrayProtocol listening on 0.0.0.0:7689 with 4 workers" # Test connection (Python xray_protocol_client; HELLO must carry a database name) python3 -c 'import xray_protocol_client as xg conn = xg.connect(host="localhost", port=7689, auth_token="admin:YourStrongPassword!23", database="xraygraphdb") print(conn.execute_query("MATCH (n) RETURN count(n) AS n_count"))'
Installation: Linux
Two install paths on Ubuntu 24.04 LTS: the .deb package (recommended — auto-resolves runtime deps via apt) or the portable .tar.gz (everything bundled, runs against the system glibc).
.deb — Ubuntu / Debian
# 1. Download wget https://xraygraphdb.emtailabs.com/downloads/xraygraphdb_4.9.4_amd64.deb # 2. Install — use `apt install -f` so apt auto-resolves the libgdal34t64 + python3 deps. # `dpkg -i` directly will FAIL the first time with "depends on libgdal34t64; however ...". sudo apt install -f ./xraygraphdb_4.9.4_amd64.deb
.tar.gz — portable build (any glibc ≥ 2.39)
The tarball ships every C/C++ runtime we need (libstdc++, libLLVM, libsolclient, libssl, libcrypto, libxraygraphdb_module_support) under lib/. The install.sh wrapper drops them at /usr/lib/xraygraphdb/lib, registers the path with ldconfig, installs the systemd unit, and apt-installs the one external dep (libgdal34t64).
wget https://xraygraphdb.emtailabs.com/downloads/xraygraphdb-4.9.4-linux-x86_64.tar.gz tar xzf xraygraphdb-4.9.4-linux-x86_64.tar.gz cd xraygraphdb-4.9.4-linux-x86_64 sudo ./install.sh
Configure — required systemd drop-in
The default /lib/systemd/system/xraygraphdb.service ships an empty ExecStart sentinel so you can layer site-local flags via a drop-in without forking the unit file. Create the drop-in before the first systemctl start:
sudo mkdir -p /etc/systemd/system/xraygraphdb.service.d sudo tee /etc/systemd/system/xraygraphdb.service.d/local.conf >/dev/null <<'EOF' [Service] ExecStart= ExecStart=/usr/lib/xraygraphdb/xraygraphdb \ --data-directory=/var/lib/xraygraphdb \ --bolt-port=7687 \ --xray-port=7689 \ --storage-properties-on-edges=true \ --log-level=WARNING \ --license-acknowledge-saved=true \ --bolt_listen_mode=off EOF sudo systemctl daemon-reload sudo systemctl start xraygraphdb sudo systemctl status xraygraphdb ss -tlnp | grep :7689 # xrayProtocol
Enterprise multi-tenant deployments can encrypt each tenant's data at rest using your own key management system (HashiCorp Vault, AWS KMS, or a compatible KMS). Setup is covered in the licensed admin guide. Single-tenant and evaluation installs work out of the box with no additional configuration.
SIGTERM (graceful shutdown). Never use kill -9. A forced kill skips the final snapshot and may result in data loss on next recovery.
Installation: macOS
macOS is supported for development only. For production workloads use Linux or Docker.
# Download macOS binary (Apple Silicon or Intel) curl -LO https://releases.emtailabs.com/xraygraphdb/xraygraphdb-v4.9.4-macos-arm64.tar.gz # Extract and run tar xzf xraygraphdb-v4.9.4-macos-arm64.tar.gz cd xraygraphdb-v4.9.4 ./bin/xraygraphdb-wrapper
On macOS you may also use Docker Desktop, which is the recommended approach for local development.
First Boot: Bootstrap Admin
Fresh installs ship with no users in the auth store. The daemon will not let you create the first admin user over the wire (chicken-and-egg), so you must run the one-time bootstrap helper before the database is usable. This step does not apply to replica nodes — replicas inherit the admin user from the cluster's MAIN; see Cluster Setup.
sudo xraygraphdb-bootstrap-admin
The helper:
- Generates a 24-character random password.
- Displays it once on your terminal in red.
- Asks you to retype it to confirm you copied it.
- Writes the username/password to
/run/xraygraphdb/bootstrap.env— this is a tmpfs file, never on disk — and starts the daemon. - Schedules an
ExecStartPosthook that wipes the env file ~15 seconds after the daemon comes up.
/var/lib/xraygraphdb and re-run the bootstrap — the existing user data is unrecoverable.
Loading datasets — where to put files
The default systemd unit ships with PrivateTmp=true for sandbox hardening. That gives the daemon its own private /tmp/ namespace, separate from the host's /tmp/. Anything you place in the host's /tmp/ is invisible to the daemon, and bulk-import calls against those paths fail-fast with 0 vertices / 0 edges in under a second — no error in the journal.
/tmp/. Even though the dataset file is world-readable, the daemon cannot see it. Use /var/lib/xraygraphdb/import/ instead — this path is in the unit's ReadWritePaths=, owned by the xraygraphdb user, and shares the daemon's namespace.
# Right way — daemon can read it: sudo mkdir -p /var/lib/xraygraphdb/import sudo mv ~/com-friendster.ungraph.txt /var/lib/xraygraphdb/import/ sudo chown -R xraygraphdb:xraygraphdb /var/lib/xraygraphdb/import # Then in your bench/import script: client.bulk_import_file("/var/lib/xraygraphdb/import/com-friendster.ungraph.txt") # Wrong way — daemon's PrivateTmp namespace makes this invisible: # client.bulk_import_file("/tmp/com-friendster.ungraph.txt") ← returns 0/0 in 1s
If you need a different dataset path (e.g. a large NVMe mount at /data/), add it to the systemd unit's ReadWritePaths= via a drop-in:
[Service] ReadWritePaths=/data
Then systemctl daemon-reload && systemctl restart xraygraphdb, and the daemon can read/write under /data/.
If the host is going to join an existing cluster as a replica, skip this section and use xraygraphdb-cluster-join instead.
Creating a Database
xrayGraphDB has no default database. Every connection must name one, either in the connection string or with USE DATABASE — a connection that names none is rejected. So creating a database is the first thing you do after bootstrapping admin.
-- Connect AS the user who should own this database, then: CREATE DATABASE myapp; -- Confirm it exists and switch to it SHOW DATABASES; USE DATABASE myapp;
admin on their behalf. The creating user becomes the database's permanent owner, recorded once at creation, and that owner binding is what the analytics and embedding procedures check before returning anything. Create a database as admin, then connect as alice, and ordinary queries work perfectly — but xray.embed, the analyzers and the vector-index procedures all return zero rows with no error, because alice does not own it. The failure is silent and looks exactly like "there is no data". If analyzers return nothing on a database that plainly has data, check who created it first.
The owner is fixed at creation and there is no command to change it afterwards. If a database was created under the wrong user, the supported fix is to drop it and recreate it as the correct owner:
-- Destructive: this deletes the data. Re-import afterwards. DROP DATABASE myapp; -- Now reconnect AS the intended owner and create it again CREATE DATABASE myapp;
Two more conditions must hold for the owner binding to be recorded, and both are easy to trip over:
- Pick a name other than
xraygraphdb. That is the built-in bootstrap database, which every node creates independently at startup. It is deliberately excluded from the ownership catalog, so it can never carry an owner and the analyzers will always return zero rows on it. Use it to connect and administer; create your own database for your data. - Create it on the MAIN, not on a replica. Replicas receive databases through replication; a database created directly on a replica has no owner binding.
Ownership is per database, and it is a boundary, not a preference: it is what stops one tenant's analytics from reading another's graph. Granting a user access to a database lets them query it; it does not make them its owner.
Options
CREATE DATABASE accepts an optional WITH clause:
CREATE DATABASE analytics WITH storage_mode = 'mmap', -- overrides the server's --storage-engine default mmap_reservation_gb = '64', -- per-database mmap ceiling, fixed when the files open wal = 'true', snapshot_interval = '300';
Unknown properties are ignored with a warning in the server log rather than failing the statement, so check the log if an option appears to have had no effect.
Cluster Setup
A cluster is one or more coordinators (which hold the replicated cluster state and issue leases) plus the data instances that serve queries. A data instance joins by being registered with a coordinator; it inherits the admin user from the cluster's MAIN, so you do not run the bootstrap helper on a replica.
REGISTER INSTANCE inst_1 WITH CONFIG { "bolt_server": "10.0.0.11:7687", "management_server": "10.0.0.11:37801", "replication_server": "10.0.0.11:37811" };
Run that against a coordinator. Cluster statements require the CONFIG privilege, so the account you use must hold it. Inter-node traffic is mutually authenticated TLS and fails closed: a cluster-role node will refuse to start without valid certificate material.
Licence Seats & Replacing a Node
Your licence grants a number of seats. A seat is a concurrency limit — the maximum number of data instances attached to the cluster at any one moment. It is not a lifetime activation count, so there is no penalty for replacing hardware. You may swap machines as often as you need; only the number attached at once is counted.
If more nodes attach than you have seats for, the excess enter an overage grace state rather than being cut off abruptly, and the oldest waiting node is promoted automatically as soon as a seat frees up.
Replacing a failed node — the normal path
This path is entirely self-service. You do not need to contact eMTAi.
- Release the seat. On a coordinator, unregister the dead instance. The seat is freed immediately and any node waiting in overage grace is promoted into it.
UNREGISTER INSTANCE inst_1;
- Provision the replacement with a fresh, empty data directory.
- Register it with
REGISTER INSTANCEas above. It takes the freed seat and replication rebuilds its data from the cluster.
Both the release and the registration are recorded as audit events for your SIEM, emitted only when the change actually completed.
Reusing the failed node's data directory
Restoring the old data directory onto different hardware is a separate case and is refused by design. A data directory is cryptographically bound to the machine that activated it — that binding is what prevents a directory being copied to run extra unlicensed instances.
Which should you choose? For an ordinary hardware failure, a fresh data directory is faster and needs no vendor round-trip. Reserve the recovery-certificate path for cases where the data itself must be preserved in place — for example a single-node deployment with no replica to rebuild from.
Checking seat usage
Use SHOW INSTANCES on a coordinator to see every attached instance and its current state, including any sitting in overage grace.
SHOW INSTANCES;
Connect
First-party clients speak xrayProtocol on port 7689; the Bolt port 7689's companion 7687 is provided for triage compatibility. Pick your language below.
First Connection: Python
xrayGraphDB is compatible with the official Neo4j Python driver. Install it with pip and connect over the Bolt protocol.
pip install neo4j
from neo4j import GraphDatabase driver = GraphDatabase.driver( "bolt://localhost:7687", auth=("admin", "<your-password>") ) with driver.session() as session: # Create a node session.run( "CREATE (n:Person {name: $name, age: $age})", name="Alice", age=30 ) # Read it back result = session.run( "MATCH (n:Person {name: $name}) RETURN n.name, n.age", name="Alice" ) record = result.single() print(record["n.name"], record["n.age"]) # Output: Alice 30 driver.close()
First Connection: JavaScript
npm install neo4j-driver
const neo4j = require('neo4j-driver'); const driver = neo4j.driver( 'bolt://localhost:7687', neo4j.auth.basic('admin', '<your-password>') ); const session = driver.session(); try { // Create a node await session.run( 'CREATE (n:Person {name: $name, age: $age})', { name: 'Bob', age: 25 } ); // Read it back const result = await session.run( 'MATCH (n:Person {name: $name}) RETURN n', { name: 'Bob' } ); console.log(result.records[0].get('n').properties); } finally { await session.close(); await driver.close(); }
First Connection: Java
Add the Neo4j Java driver to your Maven or Gradle project.
<!-- Maven dependency --> <dependency> <groupId>org.neo4j.driver</groupId> <artifactId>neo4j-java-driver</artifactId> <version>5.x</version> </dependency>
import org.neo4j.driver.*; public class XRayExample { public static void main(String[] args) { var driver = GraphDatabase.driver( "bolt://localhost:7687", AuthTokens.basic("admin", "<your-password>") ); try (var session = driver.session()) { session.run( "CREATE (n:Person {name: $name})", Values.parameters("name", "Carol") ); var result = session.run( "MATCH (n:Person) RETURN n.name" ); while (result.hasNext()) { System.out.println(result.next().get("n.name").asString()); } } driver.close(); } }
First Connection: Go
go get github.com/neo4j/neo4j-go-driver/v5
package main import ( "context" "fmt" "github.com/neo4j/neo4j-go-driver/v5/neo4j" ) func main() { ctx := context.Background() driver, err := neo4j.NewDriverWithContext( "bolt://localhost:7687", neo4j.BasicAuth("admin", "<your-password>", ""), ) if err != nil { panic(err) } defer driver.Close(ctx) session := driver.NewSession(ctx, neo4j.SessionConfig{}) defer session.Close(ctx) _, err = session.Run(ctx, "CREATE (n:Person {name: $name})", map[string]any{"name": "Dave"}, ) if err != nil { panic(err) } result, err := session.Run(ctx, "MATCH (n:Person) RETURN n.name", nil, ) if err != nil { panic(err) } for result.Next(ctx) { fmt.Println(result.Record().Values[0]) } }
First Connection: .NET
dotnet add package Neo4j.Driver
using Neo4j.Driver; var driver = GraphDatabase.Driver( "bolt://localhost:7687", AuthTokens.Basic("admin", "<your-password>") ); await using var session = driver.AsyncSession(); await session.RunAsync( "CREATE (n:Person {name: $name})", new { name = "Eve" } ); var result = await session.RunAsync( "MATCH (n:Person) RETURN n.name" ); var records = await result.ToListAsync(); foreach (var record in records) { Console.WriteLine(record["n.name"].As<string>()); } await driver.DisposeAsync();
Quick Start Tutorial
This tutorial walks through creating a small graph, querying it, and cleaning up. It assumes you have a running xrayGraphDB instance and a Python driver installed.
// Step 1: Create some nodes CREATE (alice:Person {name: "Alice", age: 30}) CREATE (bob:Person {name: "Bob", age: 25}) CREATE (carol:Person {name: "Carol", age: 35}) CREATE (proj:Project {name: "xrayGraphDB"}) RETURN alice, bob, carol, proj; // Step 2: Create relationships MATCH (a:Person {name: "Alice"}), (b:Person {name: "Bob"}) CREATE (a)-[:KNOWS]->(b) RETURN a, b; MATCH (a:Person {name: "Alice"}), (p:Project {name: "xrayGraphDB"}) CREATE (a)-[:WORKS_ON {role: "lead"}]->(p) RETURN a, p; MATCH (b:Person {name: "Bob"}), (p:Project {name: "xrayGraphDB"}) CREATE (b)-[:WORKS_ON {role: "contributor"}]->(p) RETURN b, p; // Step 3: Query the graph MATCH (p:Person)-[:WORKS_ON]->(proj:Project) RETURN p.name, proj.name; // Step 4: Update properties MATCH (a:Person {name: "Alice"}) SET a.email = "alice@example.com" RETURN a; // Step 5: Clean up MATCH (n) DETACH DELETE n;
$name, $age, etc.) to prevent injection and improve plan cache hit rates.
MATCH
The MATCH clause is the primary read operation. It describes a pattern to find in the graph and binds matching subgraphs to variables.
// Match all nodes with a specific label MATCH (n:Person) RETURN n; // Match a relationship pattern MATCH (a:Person)-[:KNOWS]->(b:Person) RETURN a.name, b.name; // Match with relationship variable MATCH (a:Person)-[r:WORKS_ON]->(p:Project) RETURN a.name, r.role, p.name; // Match any direction MATCH (a:Person)-[:KNOWS]-(b:Person) RETURN a.name, b.name; // Match with multiple labels MATCH (n:Person:Employee) RETURN n;
Patterns can include any combination of nodes, relationships, and directions. Nodes are enclosed in parentheses (), relationships in square brackets [], and direction is indicated by arrows -> or <-.
WHERE
The WHERE clause filters results from MATCH patterns. It supports comparison operators, boolean logic, string matching, list predicates, and null checks.
// Comparison operators MATCH (n:Person) WHERE n.age > 25 AND n.age <= 40 RETURN n.name, n.age; // String matching MATCH (n:Person) WHERE n.name STARTS WITH "A" RETURN n; // Regular expression MATCH (n:Person) WHERE n.email =~ ".*@example\\.com" RETURN n; // Null checks MATCH (n:Person) WHERE n.email IS NOT NULL RETURN n; // IN list MATCH (n:Person) WHERE n.name IN ["Alice", "Bob", "Carol"] RETURN n; // Pattern predicates (exists) MATCH (n:Person) WHERE (n)-[:WORKS_ON]->() RETURN n.name;
| Operator | Description | Example |
|---|---|---|
| = | Equal | n.age = 30 |
| <> | Not equal | n.name <> "Alice" |
| <, >, <=, >= | Comparison | n.age >= 18 |
| AND, OR, NOT | Boolean logic | n.age > 20 AND n.active = true |
| IN | List membership | n.status IN ["active", "pending"] |
| STARTS WITH | String prefix | n.name STARTS WITH "Al" |
| ENDS WITH | String suffix | n.name ENDS WITH "ice" |
| CONTAINS | String contains | n.name CONTAINS "li" |
| =~ | Regex match | n.email =~ ".*@example\\.com" |
| IS NULL | Null check | n.deleted IS NULL |
| IS NOT NULL | Not null | n.email IS NOT NULL |
RETURN
RETURN specifies which values to include in the result set. You can return nodes, relationships, properties, expressions, or aggregations.
// Return specific properties MATCH (n:Person) RETURN n.name, n.age; // Alias with AS MATCH (n:Person) RETURN n.name AS person_name, n.age AS years; // Return all properties as a map MATCH (n:Person) RETURN properties(n); // Return distinct values MATCH (n:Person)-[:WORKS_ON]->(p:Project) RETURN DISTINCT p.name; // Expressions in RETURN MATCH (n:Person) RETURN n.name, n.age * 12 AS age_in_months;
ORDER BY / LIMIT / SKIP
Control the ordering and pagination of results.
// Order by a property MATCH (n:Person) RETURN n.name, n.age ORDER BY n.age DESC; // Limit results MATCH (n:Person) RETURN n.name ORDER BY n.name LIMIT 10; // Pagination with SKIP and LIMIT MATCH (n:Person) RETURN n.name ORDER BY n.name SKIP 20 LIMIT 10; // Multiple sort keys MATCH (n:Person) RETURN n.name, n.age ORDER BY n.age DESC, n.name ASC;
WITH
WITH acts as a pipeline separator, allowing you to chain query stages together. Variables not listed in WITH are not available in subsequent clauses.
// Filter intermediate results MATCH (p:Person)-[:WORKS_ON]->(proj:Project) WITH proj, count(p) AS team_size WHERE team_size > 3 RETURN proj.name, team_size ORDER BY team_size DESC; // Chain queries MATCH (n:Person) WITH n ORDER BY n.age DESC LIMIT 5 MATCH (n)-[:KNOWS]->(friend) RETURN n.name, collect(friend.name) AS friends;
UNWIND
UNWIND expands a list into individual rows. Useful for bulk operations and working with list parameters.
// Expand a list UNWIND [1, 2, 3] AS x RETURN x; // Bulk create from parameters UNWIND $people AS person CREATE (n:Person {name: person.name, age: person.age}); // Combine with MATCH UNWIND ["Alice", "Bob"] AS name MATCH (n:Person {name: name}) RETURN n;
OPTIONAL MATCH
OPTIONAL MATCH works like MATCH but returns null for missing parts of the pattern instead of excluding the row entirely. Equivalent to a left outer join.
// Return all people, even those without projects MATCH (p:Person) OPTIONAL MATCH (p)-[:WORKS_ON]->(proj:Project) RETURN p.name, proj.name;
CREATE
CREATE adds new nodes and relationships to the graph. It always creates new elements (use MERGE to avoid duplicates).
// Create a single node CREATE (n:Person {name: "Frank", age: 28}) RETURN n; // Create multiple nodes CREATE (a:Person {name: "Grace"}), (b:Person {name: "Hank"}); // Create a node with multiple labels CREATE (n:Person:Developer {name: "Ivy"}); // Create a relationship between existing nodes MATCH (a:Person {name: "Grace"}), (b:Person {name: "Hank"}) CREATE (a)-[:KNOWS {since: 2024}]->(b) RETURN a, b; // Create a full path in one statement CREATE (a:Module {name: "auth"})-[:IMPORTS]->(b:Module {name: "crypto"}) RETURN a, b;
MERGE
MERGE ensures a pattern exists in the graph. If the pattern is found, it is bound. If not found, it is created. Use ON CREATE SET and ON MATCH SET to conditionally set properties.
// Merge a node (create if not exists) MERGE (n:Person {name: "Alice"}) ON CREATE SET n.created = timestamp() ON MATCH SET n.lastSeen = timestamp() RETURN n; // Merge a relationship MATCH (a:Person {name: "Alice"}), (b:Person {name: "Bob"}) MERGE (a)-[r:KNOWS]->(b) ON CREATE SET r.since = 2024 RETURN r;
MERGE matches the entire pattern. If you merge on (a)-[:KNOWS]->(b) and the relationship does not exist, it creates only the relationship, not the nodes (they must already be bound by a preceding MATCH or MERGE).
SET
SET updates properties on nodes and relationships, or adds labels to nodes.
// Set a property MATCH (n:Person {name: "Alice"}) SET n.age = 31 RETURN n; // Set multiple properties MATCH (n:Person {name: "Alice"}) SET n.age = 31, n.email = "alice@example.com" RETURN n; // Replace all properties with a map MATCH (n:Person {name: "Alice"}) SET n = {name: "Alice", age: 31, active: true} RETURN n; // Merge properties (add without removing existing) MATCH (n:Person {name: "Alice"}) SET n += {department: "engineering"} RETURN n; // Add a label MATCH (n:Person {name: "Alice"}) SET n:Employee RETURN n;
REMOVE
REMOVE deletes properties from nodes/relationships and removes labels from nodes.
// Remove a property MATCH (n:Person {name: "Alice"}) REMOVE n.email RETURN n; // Remove a label MATCH (n:Person:Employee {name: "Alice"}) REMOVE n:Employee RETURN labels(n);
DELETE / DETACH DELETE
DELETE removes nodes and relationships. A node cannot be deleted if it still has relationships. Use DETACH DELETE to delete a node and all its relationships in one operation.
// Delete a relationship MATCH (a:Person)-[r:KNOWS]->(b:Person) WHERE a.name = "Alice" AND b.name = "Bob" DELETE r; // Delete a node (must have no relationships) MATCH (n:Person {name: "Frank"}) DELETE n; // Detach delete (node + all relationships) MATCH (n:Person {name: "Alice"}) DETACH DELETE n; // Delete all nodes and relationships in the database MATCH (n) DETACH DELETE n;
MATCH (n) DETACH DELETE n removes the entire graph. There is no undo. Make a snapshot before running destructive queries on production data.
Variable-length Paths
Variable-length path patterns match paths of varying depth using the * syntax inside relationship brackets.
// Paths of exactly 2 hops MATCH (a:Person)-[:KNOWS*2]->(c:Person) RETURN a.name, c.name; // Paths of 1 to 5 hops MATCH (a:Person)-[:KNOWS*1..5]->(c:Person) RETURN a.name, c.name; // Paths of any length (use with caution) MATCH (a:Person {name: "Alice"})-[:KNOWS*]->(c:Person) RETURN DISTINCT c.name; // Capture the path MATCH path = (a:Person {name: "Alice"})-[:KNOWS*1..3]->(c:Person) RETURN path, length(path) AS hops;
* without limits) can be expensive on large graphs. Always set an upper bound when possible.
shortestPath / allShortestPaths
shortestPath() and allShortestPaths() are not yet in the Cypher grammar and will fail to parse. Verified against the engine on 2026-08-13. Use a bounded variable-length pattern and take the shortest match: MATCH p=(a)-[:REL*1..5]->(b) RETURN length(p) ORDER BY length(p) LIMIT 1 — or min(length(p)). Both are verified working. Note this enumerates paths rather than stopping at the first, so bound the depth on large graphs.Find the shortest path(s) between two nodes.
// Find one shortest path MATCH (a:Person {name: "Alice"}), (b:Person {name: "Eve"}) MATCH p = shortestPath((a)-[*..10]-(b)) RETURN p, length(p) AS hops; // Find all shortest paths (same length) MATCH (a:Person {name: "Alice"}), (b:Person {name: "Eve"}) MATCH p = allShortestPaths((a)-[*..10]-(b)) RETURN p; // With relationship type filter MATCH (a:Person {name: "Alice"}), (b:Person {name: "Eve"}) MATCH p = shortestPath((a)-[:KNOWS|WORKS_WITH*..10]-(b)) RETURN p;
BFS Traversal
BFS edge-modifier syntax (-[:REL BFS]->) is not in the Cypher grammar and will fail to parse. Verified against the engine on 2026-08-13. Use an ordinary variable-length pattern: MATCH p=(a)-[:REL*1..3]->(b), which is verified working and breadth-bounded by the depth you give it.Breadth-first search traversal is available for exploring graphs level by level. BFS guarantees that nodes are visited in order of increasing distance from the start node.
// BFS with upper bound MATCH (start:Person {name: "Alice"}) MATCH path = (start)-[:KNOWS BFS]->(target) RETURN target.name, length(path) AS distance ORDER BY distance;
BFS traversal is the default algorithm used by shortestPath. Use the explicit BFS syntax when you need to enumerate all reachable nodes by distance layer.
Aggregation
Aggregation functions operate on groups of rows. Non-aggregated columns in RETURN act as implicit group keys (similar to SQL GROUP BY).
// Count MATCH (n:Person) RETURN count(n) AS total_people; // Group and count MATCH (p:Person)-[:WORKS_ON]->(proj:Project) RETURN proj.name, count(p) AS team_size ORDER BY team_size DESC; // Sum, average, min, max MATCH (n:Person) RETURN sum(n.age) AS total_age, avg(n.age) AS avg_age, min(n.age) AS youngest, max(n.age) AS oldest; // Collect into a list MATCH (p:Person)-[:WORKS_ON]->(proj:Project) RETURN proj.name, collect(p.name) AS members; // Standard deviation and percentile MATCH (n:Person) RETURN stDev(n.age) AS std_dev, percentileCont(n.age, 0.5) AS median;
| Function | Description | Example |
|---|---|---|
| count(expr) | Number of non-null values | count(n) |
| sum(expr) | Sum of numeric values | sum(n.salary) |
| avg(expr) | Average of numeric values | avg(n.age) |
| min(expr) | Minimum value | min(n.created) |
| max(expr) | Maximum value | max(n.score) |
| collect(expr) | Collect values into a list | collect(n.name) |
| percentileCont(expr, p) | Continuous percentile (interpolated) | percentileCont(n.age, 0.5) |
| percentileDisc(expr, p) | Discrete percentile (nearest value) | percentileDisc(n.age, 0.9) |
| stDev(expr) | Standard deviation (sample) | stDev(n.score) |
| stDevP(expr) | Standard deviation (population) | stDevP(n.score) |
Indexing & Constraints
Indexes accelerate lookups by property value. Constraints enforce data integrity rules.
// Create a label-property index CREATE INDEX ON :Person(name); // Neo4j-compatible named index syntax CREATE INDEX person_name_idx FOR (n:Person) ON (n.name); // Composite index CREATE INDEX ON :Person(name, age); // Drop an index DROP INDEX ON :Person(name); // Unique constraint CREATE CONSTRAINT ON (n:Person) ASSERT n.email IS UNIQUE; // Existence constraint CREATE CONSTRAINT ON (n:Person) ASSERT EXISTS (n.name); // Show index info SHOW INDEX INFO; // List all constraints SHOW CONSTRAINT INFO;
WHERE clauses and MATCH patterns. Without an index, the engine must scan all nodes of a given label.
Transactions
BEGIN; / COMMIT; / ROLLBACK; statements are not supported — none of BEGIN, COMMIT, ROLLBACK, TRANSACTION or EXPLICIT is an accepted top-level keyword. Verified against the engine on 2026-08-13. Use driver-managed transactions (the client example above: session.begin_transaction() → tx.commit() / tx.rollback()). Every single statement is already atomic on its own, and SHOW TRANSACTIONS is available for inspection.xrayGraphDB supports both auto-commit transactions (single query) and explicit transactions (multi-query).
Auto-commit Transactions
Every query sent via session.run() runs in its own auto-commit transaction. If the query succeeds, it is committed. If it fails, it is rolled back.
Explicit Transactions
Use explicit transactions when you need to execute multiple queries atomically.
with driver.session() as session: tx = session.begin_transaction() try: tx.run("CREATE (a:Account {id: $id, balance: $bal})", id="A001", bal=1000) tx.run("CREATE (a:Account {id: $id, balance: $bal})", id="A002", bal=500) tx.commit() except Exception: tx.rollback() raise
// Explicit transaction commands (Bolt protocol) BEGIN; CREATE (n:Temp {data: "test"}); COMMIT; // Or rollback BEGIN; CREATE (n:Temp {data: "test"}); ROLLBACK;
CALL xg.builtin_functions() and available in the Community edition at no cost.
GFQL Overview
chain().n(label='Person').filter(age >= 18)). That form does not parse. GFQL composes operations comma-separated inside chain(…), uses : for named arguments (not =), and expresses filters as object literals. Every example below was executed against the engine.Sending a GFQL query
GFQL is a second language on the same connection, not a Cypher function. It is selected by the language byte of the xrayProtocol EXECUTE frame: 0 = Cypher, 1 = GFQL. There is no CALL gfql(…) procedure, and chain() / n() are not callable from Cypher — attempting either returns “Function 'chain' doesn't exist”.
# Python, via the xrayProtocol client
client.execute("chain(n(), e_forward(hops: 2), n())", language=1) # 1 = GFQL
client.execute("MATCH (n) RETURN count(n)", language=0) # 0 = Cypher
Verified operations
Executed against a three-node graph (Alice → Bob → Carol, joined by KNOWS; complexity 12 / 3 / 20). The row counts are the actual results returned.
| GFQL | Rows | Meaning |
|---|---|---|
chain(n()) | 3 | every node |
chain(n(), e_forward(), n()) | 2 | one-hop outgoing pairs |
chain(n(), e_forward(hops: 2), n()) | 1 | exactly two hops (Alice→Carol) |
chain(n(), e_forward(min_hops: 1, max_hops: 3), n()) | 3 | bounded range of hops |
chain(n({complexity_gt: 10})) | 2 | object-literal filter (Alice 12, Carol 20) |
chain(n(), e_reverse(), n()) | 2 | incoming edges |
chain(n(), distinct()) | 3 | deduplicate |
chain(n(), limit(2)) | 2 | row cap |
Named arguments take a colon (hops: 2, min_hops: 1). Analytic operations follow the same shape — e.g. betweenness_centrality_sampled(epsilon: 0.05). Enumerate everything available with CALL xg.procedures().
GFQL (Graph Frame Query Language) is a dataframe-native query language for graph traversal and analysis. It is designed for data scientists and developers who prefer chainable, functional-style operations over declarative pattern matching.
GFQL queries run natively inside the xrayGraphDB engine alongside Cypher. They operate on the same in-memory graph as Cypher queries, with the same transaction isolation guarantees.
SET GFQL_CONTEXT
Before executing GFQL operations, set a query context that defines the working scope (labels, edge types, or property filters).
// Set context to all Function nodes SET GFQL_CONTEXT label='Function'; // Set context with edge filter SET GFQL_CONTEXT label='Module', edge_type='IMPORTS'; // Set context with property filter SET GFQL_CONTEXT label='Person', WHERE age > 25;
chain(), n(), e_forward(), e_reverse()
GFQL operations are chained together using a fluent API. The core primitives are:
| Function | Description | Example |
|---|---|---|
| chain() | Start a GFQL operation chain | chain() |
| n() | Select nodes (optionally filtered) | n(label='Person') |
| e_forward() | Traverse outgoing edges | e_forward(type='CALLS') |
| e_reverse() | Traverse incoming edges | e_reverse(type='CALLS') |
| .filter() | Filter current frame | .filter(complexity > 5) |
| .hop() | Multi-hop traversal | .hop(edge_type='CALLS', depth=3) |
| .select() | Project specific columns | .select('name', 'module') |
| .aggregate() | Group and aggregate | .aggregate(by='module', count='name') |
// Find high-complexity functions and their callees chain() .n(label='Function') .filter(complexity > 10) .e_forward(type='CALLS') .select('source.name', 'target.name'); // Multi-hop traversal chain() .n(label='Module', name='auth') .hop(edge_type='IMPORTS', depth=3) .select('name', '_hop_depth'); // Aggregate by module chain() .n(label='Function') .aggregate(by='module', count='name', avg_complexity='complexity');
Filter Predicates
GFQL supports the following predicates inside .filter() expressions:
| Operator | Description | Example |
|---|---|---|
| =, != | Equality / inequality | .filter(status = 'active') |
| >, <, >=, <= | Comparison | .filter(age >= 18) |
| AND, OR | Logical operators | .filter(age > 18 AND active = true) |
| NOT | Logical negation | .filter(NOT deleted) |
| IN | List membership | .filter(status IN ['active', 'pending']) |
| LIKE | Pattern matching (% wildcard) | .filter(name LIKE 'auth%') |
| IS NULL | Null check | .filter(email IS NULL) |
| IS NOT NULL | Not null | .filter(email IS NOT NULL) |
Function Reference
489 built-in functions. Click a category in the sidebar to filter, or use the search box. Click any card to expand its full signature and details.
Procedure Reference
CALL xg.procedures() YIELD name, signature, description, mode lists every callable procedure with its full signature, and CALL xg.builtin_functions() YIELD name lists every function. Note the namespace is xg. — mg.procedures() and mg.functions() do not exist on xrayGraphDB, nor do SHOW PROCEDURES / SHOW FUNCTIONS. Verified 2026-08-13.284 callable procedures invoked with CALL.
Additional Procedure Namespaces
Generated from the engine's own metadata via CALL xg.procedures() on 2026-08-13. The engine exposes 284 callable procedures in total; the 76 below were not previously documented.
xg.* — 59 procedures
| Procedure | Signature | Description | Mode |
|---|---|---|---|
xg._internal_repair_tenant_id | xg._internal_repair_tenant_id() :: (repaired :: INTEGER, skipped :: INTEGER, total :: INTEGER) | Internal maintenance procedure that repairs missing or invalid tenant identifiers on existing records. | read |
xg.allocator_purge_now | xg.allocator_purge_now() :: (elapsed_us :: INTEGER, ok :: BOOLEAN) | Force the memory allocator to purge unused arenas immediately, returning whether it succeeded and the elapsed time. | write |
xg.chain_reclaim_stats | xg.chain_reclaim_stats() :: (counter_name :: STRING, value :: INTEGER) | Report counters for the version-chain reclamation subsystem. | read |
xg.compute_rabbit_order | xg.compute_rabbit_order(community_max_iter :: INTEGER, output_path :: STRING) :: (new_id :: INTEGER, num_communities :: INTEGER, old_id :: INTEGER, time_ms :: INTEGER) | Compute a cache-friendly Rabbit-Order vertex permutation via community clustering and optionally write it to a file. | read |
xg.concept.list | xg.concept.list() :: (concept_id :: INTEGER, dimension :: STRING, has_embedding :: BOOLEAN, name :: STRING, near_count :: INTEGER) | List registered concept labels with their concept id, dimension, embedding presence, and near-neighbor count. | read |
xg.concept.near | xg.concept.near(label_name :: STRING) :: (concept_id :: INTEGER, name :: STRING, similarity :: FLOAT) | List concepts most similar to a given label by embedding similarity. | read |
xg.concept.rebuild_near | xg.concept.rebuild_near() :: (rebuilt :: INTEGER) | Rebuild the precomputed :NEAR concept-similarity edges from current concept embeddings. | write |
xg.concept.set_dimension | xg.concept.set_dimension(label_name :: STRING, dimension :: STRING) :: (dimension :: STRING, name :: STRING) | Assign a semantic dimension to a concept label. | write |
xg.concept.set_embedding | xg.concept.set_embedding(label_name :: STRING, embedding :: LIST OF ANY) :: (dim :: INTEGER, has_embedding :: BOOLEAN, name :: STRING) | Set the embedding vector for a concept label. | write |
xg.cptcs_truncate | xg.cptcs_truncate(below_lsn :: INTEGER, operator_note :: STRING, operator_id :: STRING) :: (actual_below_lsn :: INTEGER, error_code :: STRING, lagging_replicas :: STRING, ok :: BOOLEAN, truncated_coun | Operator procedure to truncate the CPTCS catalog log below a given LSN, refusing if replicas are still lagging. | write |
xg.create_module_file | xg.create_module_file(filename :: STRING, content :: STRING) :: (path :: STRING) | Create a new query-module source file with the given filename and content. | read |
xg.delete_module_file | xg.delete_module_file(path :: STRING) :: () | Delete a query-module source file at the given path. | read |
xg.disclosure_audit | xg.disclosure_audit(query_text :: STRING, nodes_used :: LIST OF INTEGER, edges_used :: LIST OF INTEGER, columns_used :: LIST OF STRING, vectors_used :: LIST OF STRING, source_refs :: LIST OF STRING, a | Write a disclosure-grade audit record capturing the query, the nodes/edges/columns/vectors used, source references, assumptions, confidence, and model version. | write |
xg.envelope_validate | xg.envelope_validate(prop_names :: LIST OF STRING, kind :: STRING) :: (missing :: LIST OF STRING, ok :: BOOLEAN) | Validate that a set of property names satisfies the required envelope for a given kind, reporting any missing properties. | read |
xg.functions | xg.functions() :: (description :: STRING, is_editable :: BOOLEAN, mode :: STRING, name :: STRING, path :: STRING, signature :: STRING) | List all registered functions (built-in and user-defined). | read |
xg.get_module_file | xg.get_module_file(path :: STRING) :: (content :: STRING) | Return the source content of a query-module file at the given path. | read |
xg.get_module_files | xg.get_module_files() :: (is_editable :: BOOLEAN, path :: STRING) | List all query-module files with their path and whether they are editable. | read |
xg.governance_disclosure_text | xg.governance_disclosure_text() :: (text :: STRING) | Return the canonical governance/disclosure text for the deployment. | read |
xg.graphrag.retrieve | xg.graphrag.retrieve(query_text :: STRING, k :: INTEGER) :: (gid :: INTEGER, score :: FLOAT, signals :: STRING) | Retrieve the top-k nodes for a natural-language query using native GraphRAG, returning each node's gid, score, and contributing signals. | read |
xg.kafka_set_stream_offset | xg.kafka_set_stream_offset(stream_name :: STRING, offset :: INTEGER) :: () | Set the consumer offset for a named Kafka ingestion stream so it resumes consuming from that position. | read |
xg.kafka_stream_info | xg.kafka_stream_info(stream_name :: STRING) :: (bootstrap_servers :: STRING, configs :: MAP, consumer_group :: STRING, credentials :: MAP, topics :: LIST OF STRING) | Report configuration for a named Kafka ingestion stream: bootstrap servers, consumer group, topics, configs, and credentials. | read |
xg.knn_graph_build | xg.knn_graph_build(label :: STRING, vector_property :: STRING, config :: MAP) :: (ann_recall_estimate :: FLOAT, batch_count :: INTEGER, bridges_added :: INTEGER, components_after :: INTEGER, component | Procedure xg.knn_graph_build (write) | write |
xg.load | xg.load(module_name :: STRING) :: () | Load a single query module by name. | read |
xg.load_all | xg.load_all() :: () | Reload all query modules from the modules directory. | read |
xg.model_version_stamp | xg.model_version_stamp(model_id :: STRING, version :: STRING, notes :: STRING) :: (model_vertex_id :: STRING, stamped_at_us :: INTEGER) | Stamp a model version onto a :Model vertex, recording the model id, version, notes, and write timestamp. | write |
xg.node_count_by_label | xg.node_count_by_label() :: (count :: INTEGER, label :: STRING) | Procedure xg.node_count_by_label | read |
xg.plugins_disable | xg.plugins_disable(name :: STRING) :: (message :: STRING, success :: STRING) | Disable a running plugin (stops the process). License is kept but plugin won't auto-start. Args: name (string). Yields: success, message. Example: CALL xg.plugins_disable('swim') YIELD success | read |
xg.plugins_enable | xg.plugins_enable(name :: STRING) :: (message :: STRING, success :: STRING) | Enable a licensed plugin (starts the process). Requires valid license. Args: name (string). Yields: success, message. Example: CALL xg.plugins_enable('swim') YIELD success | read |
xg.plugins_license | xg.plugins_license(name :: STRING, key :: STRING) :: (message :: STRING, success :: STRING) | Store and validate a license key for a plugin. The key is a JSON object with Ed25519 signature. Args: name (string), key (string — JSON). Yields: success, message. Example: CALL xg.plugins_license('swim', ' | read |
xg.plugins_list | xg.plugins_list() :: (author :: STRING, crash_count :: INTEGER, description :: STRING, display_name :: STRING, last_error :: STRING, license_expires_at :: INTEGER, license_issued_to :: STRING, license | List all discovered plugins with state, license, version, and process info. Yields: name, display_name, version, description, author, type, state, licensed, license_tier, license_issued_to, license_expires_at, pid, crash | read |
xg.plugins_revoke | xg.plugins_revoke(name :: STRING) :: (message :: STRING, success :: STRING) | Revoke a plugin license. Stops the plugin if running, removes stored license. Args: name (string). Yields: success, message. Example: CALL xg.plugins_revoke('swim') YIELD message | read |
xg.plugins_scan | xg.plugins_scan() :: (message :: STRING, success :: STRING) | Rescan the plugins directory for new or updated plugins. Loads stored licenses. Yields: success, message. Example: CALL xg.plugins_scan() YIELD message | read |
xg.procedures | xg.procedures() :: (description :: STRING, is_editable :: BOOLEAN, is_write :: BOOLEAN, mode :: STRING, name :: STRING, path :: STRING, signature :: STRING) | List all registered procedures with signature, mode, and description. | read |
xg.protocol_error_codes | xg.protocol_error_codes() :: (category :: STRING, code :: INTEGER, description :: STRING, name :: STRING) | List the xrayProtocol error codes with their numeric code, category, name, and description. | read |
xg.protocol_messages | xg.protocol_messages() :: (body :: STRING, category :: STRING, description :: STRING, direction :: STRING, name :: STRING, opcode :: STRING) | List the xrayProtocol wire messages with their opcode, direction, category, body layout, and description. | read |
xg.read_mode_status | xg.read_mode_status() :: (mode :: STRING, source :: STRING, tenant :: STRING) | Report the effective read mode for a tenant and the source that set it. | read |
xg.reclaim_chain_now | xg.reclaim_chain_now(tenant :: STRING, limit_gids :: INTEGER, cursor_in :: STRING) :: (cursor_out :: STRING, done :: BOOLEAN, error_code :: STRING, gids_reclaimed :: INTEGER, gids_visited :: INTEGER) | Operator procedure that reclaims version-chain storage for a tenant in cursor-paged batches, returning the resume cursor and reclaimed count. | write |
xg.scenario_compute | xg.scenario_compute(booster_name :: STRING, op = "decommission" :: STRING) :: (audit_id :: STRING, baseline_launches :: INTEGER, baseline_payloads :: INTEGER, baseline_satellites :: INTEGER, | Run an engine-side what-if scenario over a booster's downstream subgraph (e.g. decommission), stamping reproducible baseline counts and an audit record. | write |
xg.segment_repair | xg.segment_repair(action :: STRING, tenant :: STRING, segment_id :: INTEGER, operator_note = "" :: STRING, operator_id = "" :: STRING, force = false :: BOOLEAN, expected_state = &q | Operator procedure to repair a storage segment for a tenant (reconcile catalog vs. disk state) with optional force and expected-state guards. | write |
xg.segment_repair_remove_stale | xg.segment_repair_remove_stale(tenant :: STRING, operator_note = "" :: STRING, operator_id = "" :: STRING, dry_run = false :: BOOLEAN, batch_cap = 100000 :: INTEGER) :: (dry_run :: | Operator procedure to scan and remove stale storage segments for a tenant, with dry-run and batch-cap controls. | write |
xg.set_chain_retain | xg.set_chain_retain(tenant :: STRING, retain :: BOOLEAN) :: (error_code :: STRING, ok :: BOOLEAN, retain :: BOOLEAN, tenant :: STRING) | Operator procedure to enable or disable version-chain retention for a tenant. | write |
xg.set_read_mode | xg.set_read_mode(tenant :: STRING, mode :: STRING, operator_note = "" :: STRING, operator_id = "" :: STRING) :: (error_code :: STRING, mode :: STRING, ok :: BOOLEAN, tenant :: STRI | Operator procedure to set the read mode for a tenant, with optional operator note and id for auditing. | write |
xg.source_confidence_enforcement | xg.source_confidence_enforcement(label :: STRING, raw :: FLOAT) :: (capped :: FLOAT) | Clamp a raw confidence value to the per-tier confidence ceiling for the given source label. | read |
xg.tenant_access_revoke | xg.tenant_access_revoke(tenant_id :: STRING) :: (error_code :: INTEGER, ok :: BOOLEAN, reversible :: BOOLEAN, tenant_id :: STRING) | Operator procedure to revoke access for a tenant, reporting whether the action succeeded and is reversible. | read |
xg.tenant_crypto_shred | xg.tenant_crypto_shred(tenant_id :: STRING) :: (dek_versions_destroyed :: INTEGER, error_code :: INTEGER, ok :: BOOLEAN, tenant_id :: STRING) | Operator procedure to crypto-shred a tenant by destroying its data-encryption key versions, rendering its at-rest data unrecoverable. | read |
xg.tenant_encryption_provision | xg.tenant_encryption_provision(tenant_id :: STRING) :: (error_code :: INTEGER, error_message :: STRING, ok :: BOOLEAN, tenant_id :: STRING) | Provision per-tenant encryption for a tenant, creating its key material and enabling at-rest encryption. | read |
xg.tenant_encryption_status | xg.tenant_encryption_status(tenant_id :: STRING) :: (current_write_version :: INTEGER, dek_versions :: INTEGER, kek_ref :: STRING, provisioned :: BOOLEAN, rotation_in_progress :: BOOLEAN, status :: ST | Report a tenant's encryption status: whether provisioned, KEK reference, DEK version count, current write version, and rotation state. | read |
xg.tenant_key_rotate_dek | xg.tenant_key_rotate_dek(tenant_id :: STRING) :: (error_code :: INTEGER, new_version :: INTEGER, ok :: BOOLEAN, old_version :: INTEGER, tenant_id :: STRING) | Rotate the per-tenant data-encryption key, advancing the write version. | read |
xg.tenant_key_rotate_kek | xg.tenant_key_rotate_kek(tenant_id :: STRING, new_kek_ref :: STRING) :: (error_code :: INTEGER, new_kek_ref :: STRING, ok :: BOOLEAN, tenant_id :: STRING) | Rotate the per-tenant key-encryption key to a new KEK reference. | read |
xg.transformations | xg.transformations() :: (is_editable :: BOOLEAN, name :: STRING, path :: STRING) | List all registered stream transformations. | read |
xg.update_module_file | xg.update_module_file(path :: STRING, content :: STRING) :: () | Overwrite the content of an existing query-module file at the given path. | read |
xg.vector.describe_index | xg.vector.describe_index(name :: STRING) :: (label :: STRING, name :: STRING, property :: STRING) | Describe a named vector index, returning its label, property, and name. | read |
xg.vector.list_indexes | xg.vector.list_indexes() :: (label :: STRING, name :: STRING, property :: STRING) | List all vector indexes with their name, label, and property. | read |
xg.vector.search | xg.vector.search(name :: STRING, q :: LIST OF FLOAT, k :: INTEGER) :: (node :: NODE, score :: FLOAT) | Find the k nearest vectors in a named vector index to a query vector, returning each node and its similarity score. | read |
xg.vector.search_by_node | xg.vector.search_by_node(name :: STRING, source :: NODE, k :: INTEGER) :: (node :: NODE, score :: FLOAT) | Find the k nearest vectors in a named vector index to the vector of a given source node. | read |
xg.vector.search_edges | xg.vector.search_edges(name :: STRING, q :: LIST OF FLOAT, k :: INTEGER) :: (edge :: RELATIONSHIP, score :: FLOAT) | Find the k nearest vectors in a named edge vector index to a query vector, returning each relationship and its score. | read |
xg.vector.search_radius | xg.vector.search_radius(name :: STRING, q :: LIST OF FLOAT, threshold :: FLOAT) :: (node :: NODE, score :: FLOAT) | Find all vectors in a named vector index within a similarity threshold of a query vector. | read |
xg.w6b_router_status | xg.w6b_router_status(tenant :: STRING) :: (aead_fail :: INTEGER, auto_demoted :: BOOLEAN, coverage_miss :: INTEGER, dek_unavail :: INTEGER, drift :: INTEGER, effective_mode :: STRING, mmap_fault :: IN | Report W6B storage-router status for a tenant: effective mode, auto-demotion, and fault counters (AEAD, mmap, drift, coverage, DEK). | read |
xg.xray_vision_builtin_functions | xg.xray_vision_builtin_functions() :: (category :: STRING, description :: STRING, kind :: STRING, name :: STRING, signature :: STRING, tier :: STRING) | List the XRay-Vision built-in functions with their category, kind, signature, description, and tier. | read |
prov.* — 7 procedures
Provenance — attach evidence to facts and explain how a conclusion was reached.
| Procedure | Signature | Description | Mode |
|---|---|---|---|
prov.attach_evidence | prov.attach_evidence(fact_node :: NODE, evidence_type :: STRING, content :: STRING, source_url :: STRING) :: (evidence :: NODE) | Attach an evidence node (with type, content, and source URL) to an existing provenance fact node. | write |
prov.create_fact | prov.create_fact(entity_type :: STRING, content :: STRING, source_id :: STRING, confidence :: FLOAT) :: (node :: NODE) | Create a provenance fact node with an entity type, content, source identifier, and confidence score. | write |
prov.explain | prov.explain(fact_node :: NODE) :: (depth :: INTEGER, relationship :: STRING, summary :: STRING, type :: STRING) | Explain how a provenance fact was derived by walking its supporting relationships and summarizing each step. | read |
prov.lineage | prov.lineage(start_node :: NODE, max_depth :: INTEGER) :: (depth :: INTEGER, node :: NODE, type :: STRING) | Trace the provenance lineage of a node up to a maximum depth, yielding each ancestor node and its relationship type. | read |
prov.record_decision | prov.record_decision(decision_text :: STRING, reasoning :: STRING, fact_nodes :: LIST OF ANY) :: (decision :: NODE) | Record a decision provenance node capturing the decision text, reasoning, and the fact nodes it relied on. | write |
prov.record_model_run | prov.record_model_run(model_name :: STRING, prompt :: STRING, output :: STRING, fact_nodes :: LIST OF ANY) :: (model_run :: NODE) | Record a model-run provenance node capturing the model name, prompt, output, and the fact nodes it relied on. | write |
prov.record_tool_call | prov.record_tool_call(tool_name :: STRING, input :: STRING, output :: STRING, fact_nodes :: LIST OF ANY) :: (tool_call :: NODE) | Record a tool-call provenance node capturing the tool name, input, output, and the fact nodes it relied on. | write |
xggpu.* — 5 procedures
GPU-accelerated graph algorithms.
| Procedure | Signature | Description | Mode |
|---|---|---|---|
xggpu.gpu_bfs | xggpu.gpu_bfs(source_id :: INTEGER) :: (distance :: INTEGER, node_id :: INTEGER, time_ms :: INTEGER) | Procedure xggpu.gpu_bfs | read |
xggpu.gpu_kcore | xggpu.gpu_kcore() :: (core_number :: INTEGER, max_core :: INTEGER, node_id :: INTEGER, time_ms :: INTEGER) | Procedure xggpu.gpu_kcore | read |
xggpu.gpu_label_propagation | xggpu.gpu_label_propagation(iterations :: INTEGER) :: (community_id :: INTEGER, community_size :: INTEGER, iterations_actual :: INTEGER, node_id :: INTEGER, num_communities :: INTEGER, time_ms :: INTE | Procedure xggpu.gpu_label_propagation | read |
xggpu.gpu_pagerank | xggpu.gpu_pagerank(iterations :: INTEGER, damping :: FLOAT, label :: STRING) :: (iterations :: INTEGER, name :: STRING, node_id :: INTEGER, rank :: FLOAT, time_ms :: INTEGER) | Procedure xggpu.gpu_pagerank | read |
xggpu.gpu_triangle_count | xggpu.gpu_triangle_count() :: (edges_checked :: INTEGER, time_ms :: INTEGER, triangles :: INTEGER, vertices :: INTEGER) | Procedure xggpu.gpu_triangle_count | read |
db.* — 3 procedures
Schema introspection — labels, relationship types and indexes.
| Procedure | Signature | Description | Mode |
|---|---|---|---|
db.indexes | db.indexes() :: (labelsOrTypes :: STRING, name :: STRING, properties :: STRING, type :: STRING) | List all indexes in the database with their label/type, name, properties, and index type. | read |
db.labels | db.labels() :: (label :: STRING) | List all node labels present in the database. | read |
db.relationshipTypes | db.relationshipTypes() :: (relationshipType :: STRING) | List all relationship types present in the database. | read |
repl.* — 2 procedures
Replication control and status.
| Procedure | Signature | Description | Mode |
|---|---|---|---|
repl.set_sync_policy | repl.set_sync_policy(address :: STRING, mode :: STRING, targets :: STRING) :: (status :: STRING) | Set the replication synchronization policy (mode and sync targets) for a replica at the given address. | write |
repl.show_replicas | repl.show_replicas() :: (acked_lsn :: INTEGER, address :: STRING, status :: STRING, sync_mode :: STRING, sync_targets :: STRING) | List configured replicas with their address, status, acked LSN, and synchronization mode and targets. | read |
GFQL Operators
Graph operators available through the GFQL chain syntax.