Skip to documentation content

Query the Knowledge Graph with Graph Query gq/1.3

Search, analyze, project, and traverse evidence-backed entities with an ontology-aware, bounded query language.

In this guide
  1. 1Compose Boolean predicates
  2. 2Search nested and array fields
  3. 3Facet and project results
  4. 4Traverse relationships safely
In this guide
  1. 1Compose Boolean predicates
  2. 2Search nested and array fields
  3. 3Facet and project results
  4. 4Traverse relationships safely

Your first graph query

Graph Query gq/1.3 keeps the compact, entity-first usability associated with Diffbot DQL while adding a stable product-owned AST, ontology validation, parameters, explain plans, and bounded execution. Every query begins with type:EntityType. Adjacent filters imply AND.

gq/1.3
type:Organization location.country:"FI" employees>=100 sort:-employees return:entities,evidence limit:25

Syntax reference

ClauseMeaning
type:OrganizationRequired entity type
field:"value" · field="value"Contains · exact equality
field!=value · > · >= · < · <=Typed comparisons
AND · OR · NOT · ( )Nested Boolean predicates; AND is implicit between adjacent filters
field:any(a,b) · all(a,b) · none(a,b)Array and multi-value matching
text:"search phrase"Full-text match across identity and properties
has:field.path · missing:field.pathExistence and missing-value tests
sort:-employees,+labelDeterministic multi-field sort
select:businessId,employeesProperty projection; identity fields remain stable
facet:industry,location.countryValue distribution before pagination, up to five fields
after:gqc_25 · limit:25Cursor pagination; maximum 100 entities
relation:subsidiary_of · direction:both · depth<=2Bounded relationship traversal, maximum four hops
return:entities,relationships,evidenceReturned graph layers

Boolean, arrays, time, and ontology

Use nested AND/OR/NOT groups for predicates and any(), all(), or none() when a field has multiple values. ISO timestamps participate in ordered comparisons. target.* constrains traversal targets and relationship.* constrains relationship facts. Entity types, fields, capabilities, and relationships are validated against the product ontology; unknown fields return a suggestion instead of silently matching nothing.

gq/1.3
type:Organization (industry:"Logistics" OR employees>=500) AND NOT missing:businessId aliases:any("Northstar","Polar Freight") observedAt>="2026-08-01T00:00:00Z"

Bind untrusted values as parameters

Reference a named value as $name and send it in GraphQueryInput.parameters. Values are typed and never reparsed as query syntax, so SDK callers do not need to concatenate user input. Validation, explain, and execution resolve parameters identically.

JSON
{
  "query": "type:Organization location.country:$country employees>=$minimum",
  "parameters": { "country": "FI", "minimum": 100 }
}

Facet, project, sort, and page

facet computes up to 100 value buckets from the complete filtered root set before pagination. select narrows entity properties without removing stable id, type, label, or evidence_ids. Multi-sort is deterministic and the response page.next_cursor can be supplied as cursor in the next API request or as after: in the language.

gq/1.3
type:Organization location.country:"FI" facet:industry select:businessId,employees,industry sort:-employees,+label limit:25

Traverse relationships safely

Traversal is opt-in and always bounded. direction and depth are valid only with a relation clause. Queries may traverse at most four hops, preventing accidental open-ended graph scans.

gq/1.3
type:Organization businessId="3391028-4" relation:subsidiary_of direction:out depth<=2 target.location.country:"FI" relationship.confidence>=0.9 return:entities,relationships,evidence

Explain before execution

POST /v1/graph/query/validate checks syntax and ontology. POST /v1/graph/query/explain returns the canonical plan, index use, warnings, result range, and credit estimate without executing. POST /v1/graph/query executes the same expression with the graph:read scope.

cURL
curl -X POST https://api.enrich.nordicdevhouse.com/v1/graph/query \
  -H "Authorization: Bearer enrich_live_••••••••" \
  -H "Content-Type: application/json" \
  -d '{"query":"type:Organization location.country:\"FI\" employees>=100 return:entities,evidence"}'

Publish claims as immutable workspace releases

POST /v1/graph/publications accepts an idempotent batch of entity, relationship, and evidence claims with the graph:write scope. The complete batch becomes one content-addressed release, so readers never observe a partially published graph. Supply expected_parent_release_id when concurrent writers must not overwrite a newer active release.

JSON
{
  "source_id": "crm-import-2026-08-17",
  "expected_parent_release_id": "wgr_previous",
  "claims": [
    { "entity_id": "organization:3391028-4", "entity_type": "organization", "label": "Northstar Oy", "attribute": "businessId", "value": "3391028-4" }
  ]
}

Inspect, compare, and activate releases

List or read releases, compare any release to an explicit base, and activate a previous release as a controlled rollback. Activation uses expected_current_release_id for optimistic concurrency and records actor and reason in channel history. Queries always report the exact workspace_graph_release_id they used.

Separate metadata from immutable artifacts

Production stores workspace channels, idempotency keys, ingestion state, ontologies, and events in PostgreSQL. Content-addressed Parquet releases live in S3-compatible object storage and become visible only after a commit marker. SQLite and local files implement the same boundary for local development.

Ingest only changed source records

Create a source with its connector, entity type, identity field, label field, and field mapping. Every run uses a stable source_event_id and can run inline or through the durable worker queue. Per-record fingerprints skip unchanged input, valid changes become one immutable graph release, abandoned leases are reclaimed, and invalid rows move to a dead-letter list for corrected retry.

Plan against release-scoped indexes

The query engine intersects type, exact-value, existence, and full-text indexes before evaluating fallback predicates. Candidate and wall-time budgets stop expensive plans, repeated plans use an LRU cache, and every query response reports indexes, candidate count, evaluated count, cache status, fallbacks, and elapsed time.

Scale reads with cost statistics, shards, and query workers

Every graph release carries a query-projection/2 artifact. A bounded local LRU caches immutable projections, while stable workspace shards partition artifacts and durable query work. Explain plans use field cardinality and relationship degree statistics to estimate fanout, relationship reads, working-set bytes, and execution class. Query workers heartbeat leases, retry with backoff, expose dead letters, and support explicit cancel and operator retry.

Validate before activating the workspace ontology

Create an immutable draft, validate compatibility and live-data impact, then activate it. Controlled migrations rename existing graph attributes; portable export/import moves schemas between workspaces. Incompatible or data-affecting activation returns 409 unless explicitly allowed.

Consume events and release deltas

List append-only graph events with a cursor or consume the same sequence as server-sent events. Event subscriptions project matching changes into a durable webhook outbox. Bulk consumers can export an NDJSON delta from an explicit base release to a target release and resume without rebuilding the graph.

The same contract in every SDK

Generated clients expose queryKnowledgeGraph, validateKnowledgeGraphQuery, and explainKnowledgeGraphQuery. All accept GraphQueryInput, so copied queries and cost plans behave identically in every generated language.

TypeScript
const graphApi = new KnowledgeGraphApi(configuration);
const result = await graphApi.queryKnowledgeGraph({
  graphQueryInput: {
    query: 'type:Organization location.country:$country employees>=100 facet:industry return:entities,evidence',
    parameters: { country: 'FI' }
  }
});

Evidence remains explicit

Include evidence only when the caller needs provenance. Entities and relationships carry evidence_ids; the response evidence array resolves those identifiers to source, observed time, and URL. Confidence never turns an unreviewed relationship into an accepted fact.

Limits and errors

Queries are limited to 2,000 characters, 25 filters, 100 returned entities, and four relationship hops. Invalid expressions return stable error codes with the character position. Unknown fields fail ontology validation and include a suggested field when one is close.

Was this page helpful?