Queries across connected data

Start with a precise set of entities, then inspect their relationships, location history, or RDF facts. These examples use the same database identity and show the request boundary for each operation.

Query a transport network as new flights arrive

Replay two months of U.S. BTS on-time flight records in scheduled departure order. Each flight becomes a graph node between its origin and destination airports; distinct airport pairs also form a route network. The full replay adds 1,066,492 flights, reaching 1,066,826 nodes and 2,138,741 relationships across 334 airports. With the optional serialized loader, two full runs loaded 14,053.6 and 14,396.6 flights per second while Cypher reads ran concurrently.

Full January–February 2024 replays with concurrent Cypher reads
PairLoader modeFlights/sJFK count p95
1Serialized ahead14,053.624.57 ms
1Ordinary prepared request12,827.427.50 ms
2Ordinary prepared request12,955.826.42 ms
2Serialized ahead14,396.623.57 ms

Count the flights scheduled from an airport as the graph grows:

MATCH (origin:Airport {code:'JFK'})-[:SCHEDULED_FROM]->(flight:Flight)
RETURN count(flight) AS flights

Follow a flight to its destination, or explore possible two-hop routes:

MATCH (origin:Airport {code:'JFK'})-[:SCHEDULED_FROM]->(flight:Flight)
      -[:SCHEDULED_TO]->(destination:Airport)
RETURN flight.flight_date AS flight_date, destination.code AS destination
LIMIT 20
MATCH (origin:Airport {code:'JFK'})-[:SCHEDULED_ROUTE]->(connection:Airport)
      -[:SCHEDULED_ROUTE]->(destination:Airport {code:'LAX'})
RETURN connection.code AS connection
LIMIT 20

The count timings include the gRPC request on the same AWS host as the database. Updates were submitted in 600-flight batches through BulkInsertGraphBlocks; reads used ExecuteCypher. See the full ingestion and live-query results or download the measurement record.

The source is historical flight data replayed into a changing database. Scheduled routes describe published flight plans, including flights later cancelled or diverted.

Find similar entities, then traverse their relationships

Search a named vector index for nearby MixedUser nodes and follow one KNOWS edge from each match. The node value is the graph UID associated with the vector entry. Bind the index, vector, and search budget through typed ExecuteCypher parameters in an application; this literal form shows the query shape.

CALL vector.knn("default", [0.0, 0.0], 8, {ef: 64})
YIELD node AS user, score
MATCH (user:MixedUser)-[:KNOWS]->(friend:MixedUser)
RETURN user, friend, score
LIMIT 20

On the recorded 16-entity fixture, adding one KNOWS edge changed the result from four to five pairs; the fifth pair remained after restart. This route uses the production vector manager. Create and search a named index · ExecuteCypher request.

In ShrikeDB Cloud, open Vectors to load JSONL embeddings under a named index, search them, and open the equivalent Cypher query. Use each graph node’s UID as the embedding’s entity_id to connect matches to graph relationships. Named indexes accept different fixed dimensions, including 768-component semantic embeddings.

Explore a paper neighborhood from semantic search

For a 768-component paper embedding, retrieve similar papers and follow citation edges in the same query. The named index and graph nodes share each paper’s UID; the application supplies $embedding as a typed vector parameter.

CALL vector.knn("arxiv_embeddings", $embedding, 50, {ef: 256})
YIELD node AS paper, score
MATCH (paper:Paper)-[:CITES]->(reference:Paper)
RETURN paper, reference, score
LIMIT 20

The arXiv vector benchmark measures one million 768-dimensional embeddings through the packed vector RPC and typed Cypher. The Cloud Vectors screen lets users load and query their own named indexes.

Locate activity inside a time and distance window

A named geospatial index stores observations by entity and UTC time. This query finds events within five kilometers of a point during one hour, returning exact coordinates after indexed candidate selection. Replace ais with your index name and use the coordinate order required by the CRS.

CALL spacekey.search('ais', {
  start_ms: 1672531200000,
  end_ms: 1672534800000,
  shape: {type:'radius_crs',
          position:{crs:'EPSG:4326', x:38.9, y:-77.0},
          meters:5000.0}
})
YIELD event, entity, time_ms, longitude, latitude, key
RETURN event, entity, time_ms, longitude, latitude, key
ORDER BY time_ms

The result can be joined to graph entities or compared with a second observation window to inspect movement. Geospatial ingestion and query options.

Find entities that returned to the same place

Search one region in two separate ten-minute windows, then match observations by entity. The windows can fall on different days or anywhere within the index’s time range. This example counts observation pairs; group or return the matching entities when building an investigation view.

CALL spacekey.search('ais', {
  start_ms: 1672531205000, end_ms: 1672531805000,
  shape: {type:'box', west:-90.23, east:-90.12,
          south:38.60, north:38.71}
}) YIELD entity AS first_entity, time_ms AS first_time
CALL spacekey.search('ais', {
  start_ms: 1672531864000, end_ms: 1672532464000,
  shape: {type:'box', west:-90.23, east:-90.12,
          south:38.60, north:38.71}
}) YIELD entity AS second_entity, time_ms AS second_time
WITH first_entity, second_entity, first_time, second_time
WHERE first_entity = second_entity AND first_time < second_time
RETURN count(*) AS visits

On the 100,000-observation AIS fixture, this returned 375 pairs, checked against an independent scan of the source data. The same two-window join was executed through SPARQL. See measured request latency.

Find entities that match a pattern across places and times

This January 2023 query finds entities observed in the first region on Saturday nights and in a second region on Monday mornings. The two conditions can match different observations. Joining on entity turns them into one pattern result.

CALL spacekey.search('paper_conjunction_v1', {
  start_ms:1672531200000, end_ms:1675209600000,
  shape:{type:'box', west:-90.23, east:-90.13,
         south:38.60, north:38.70},
  cycle:{period:'week', start_ms:511200000,
         end_ms:518400000}
}) YIELD entity AS saturday_entity
CALL spacekey.search('paper_conjunction_v1', {
  start_ms:1672531200000, end_ms:1675209600000,
  shape:{type:'box', west:-89.95, east:-89.85,
         south:30.00, north:30.10},
  cycle:{period:'week', start_ms:28800000,
         end_ms:36000000}
}) YIELD entity AS monday_entity
WITH saturday_entity, monday_entity
WHERE saturday_entity = monday_entity
RETURN count(DISTINCT saturday_entity) AS matching_entities

The weekly offsets are milliseconds after Monday 00:00 UTC. The first window is Saturday 22:00–24:00; the second is Monday 08:00–10:00. Change the regions, windows, and index name to analyze a different routine.

PREFIX sk: <urn:shrikedb:spacekey:>
SELECT (COUNT(DISTINCT ?entity) AS ?matching_entities)
WHERE {
  SERVICE <urn:shrikedb:spacekey.search> {
    _:a sk:index 'paper_conjunction_v1';
        sk:query '{"start_ms":1672531200000,"end_ms":1675209600000,"shape":{"type":"box","west":-90.23,"east":-90.13,"south":38.6,"north":38.7},"cycle":{"period":"week","start_ms":511200000,"end_ms":518400000}}';
        sk:entity ?entity.
  }
  SERVICE <urn:shrikedb:spacekey.search> {
    _:b sk:index 'paper_conjunction_v1';
        sk:query '{"start_ms":1672531200000,"end_ms":1675209600000,"shape":{"type":"box","west":-89.95,"east":-89.85,"south":30.0,"north":30.1},"cycle":{"period":"week","start_ms":28800000,"end_ms":36000000}}';
        sk:entity ?entity.
  }
}

Both queries returned 125 entities on the measured 50,000-observation trajectory fixture, matching an independent scan. See request latency and download the measurements.

Return relationships derived from observations

CONSTRUCT returns RDF triples for the observations selected by a local geospatial search. In this example, the result links each entity to its event. The derived triples are returned to the caller; saving selected relationships is a separate write.

PREFIX sk: <urn:shrikedb:spacekey:>
CONSTRUCT { ?entity <urn:analysis:observedAt> ?event }
WHERE {
  SERVICE <urn:shrikedb:spacekey.search> {
    _:q sk:index "derived";
        sk:query '{"start_ms":1000,"end_ms":2000}';
        sk:entity ?entity;
        sk:event ?event.
  }
}

The recorded server probe returned two event links and confirmed that a later graph read did not find them as stored triples. This supports query-time evidence graphs for investigations without filling the database with every inferred relationship. SPARQL result graphs.

Create a graph entity through Cypher

On a self-hosted server, grant the caller Write permission and enable the governed executor with SHRIKEDB_CYPHER_WRITE_MODE=canary or full. Send supported writes to ExecuteCypher over gRPC; the Cloud query editor and published HTTP query endpoints accept reads.

CREATE (p:Person {id: 'guide-alice', name: 'Alice'})
RETURN p

A single-action CREATE batch is validated before publication. For a relationship between existing nodes, use MATCH followed by one relationship CREATE. Review supported MERGE, property changes, constraints, and statement boundaries in the Cypher write guide.

Commit an RDF change and read it back

On a standalone self-hosted server, set SHRIKEDB_SPARQL_UPDATE_MODE=canary and grant the caller Write permission. ExecuteSPARQLUpdate accepts ordered default-graph INSERT DATA and DELETE DATA operations. This request replaces one exact RDF triple with another in one commit.

grpcurl -plaintext \
  -import-path "$SHRIKEDB_API_DIR" -proto shrikedb.v2.proto \
  -d '{"update":"DELETE DATA { <urn:example:vessel:42> <urn:example:status> \"in port\" . }; INSERT DATA { <urn:example:vessel:42> <urn:example:status> \"at sea\" . }"}' \
  127.0.0.1:50251 shrikedb.v2.ShrikeDbService/ExecuteSPARQLUpdate

Read the result with ExecuteSPARQL:

SELECT ?status WHERE {
  <urn:example:vessel:42> <urn:example:status> ?status
}

Supply the protocol definition and any database and authorization headers described in the API setup. The SPARQL guide covers exact-term deletion, request limits, and deployment settings.