Configure Queries

Define continuous queries to detect and react to data changes

Continuous Queries Continuous Query A query that runs continuously, maintaining an always-current result set as data changes. Learn more are the heart of Drasi. They define what data changes you want to detect and react to.

Quick Start

A minimal query that matches all nodes from a source:

queries:
  - id: all-orders
    query: "MATCH (o:Order) RETURN o"
    sources:
      - sourceId: my-source

Configuration Reference

Field Type Default Description
id string Required Unique query identifier (referenced by reactions)
query string Required The Cypher/GQL query text
queryLanguage string GQL Query language: GQL or Cypher
sources array [] Source subscriptions (see below)
autoStart boolean false Start query automatically on server startup
enableBootstrap boolean true Request bootstrap data for initial state
bootstrapBufferSize integer 10000 Buffer size during bootstrap replay
joins array None Join configuration for multi-label queries
priorityQueueCapacity integer None Override default event queue capacity
dispatchBufferCapacity integer None Override default dispatch buffer capacity

Source Subscriptions

Each query subscribes to one or more sources:

queries:
  - id: my-query
    query: "MATCH (o:Order) RETURN o"
    sources:
      - sourceId: orders-db        # Required: which source
        nodes: []                   # Optional: filter node labels
        relations: []               # Optional: filter relation labels
        pipeline: []                # Optional: processing pipeline

Filtering by Label

Limit which data the query receives:

sources:
  - sourceId: orders-db
    nodes: [Order, Customer]       # Only receive Order and Customer nodes
    relations: [PLACED_BY]         # Only receive PLACED_BY relations

Query Language

Drasi supports two query languages:

GQL (Default)

Graph Query Language - the emerging ISO standard:

queries:
  - id: high-value-orders
    queryLanguage: GQL
    query: |
      MATCH (o:Order)
      WHERE o.total > 1000
      RETURN o.id, o.customer_id, o.total

Cypher

Neo4j’s query language (widely adopted):

queries:
  - id: high-value-orders
    queryLanguage: Cypher
    query: |
      MATCH (o:Order)
      WHERE o.total > 1000
      RETURN o.id, o.customer_id, o.total

Both languages are functionally similar for most use cases.

Common Query Patterns

Simple Node Query

Match all nodes of a type:

queries:
  - id: all-products
    query: "MATCH (p:Product) RETURN p.id, p.name, p.price"
    sources:
      - sourceId: inventory-db

Filtered Query

Match nodes meeting a condition:

queries:
  - id: low-stock
    query: |
      MATCH (p:Product)
      WHERE p.stock < p.reorder_point
      RETURN p.id, p.name, p.stock, p.reorder_point
    sources:
      - sourceId: inventory-db

Aggregation Query

Compute aggregates that update in real-time:

queries:
  - id: order-summary
    query: |
      MATCH (o:Order)
      RETURN count(o) AS total_orders, 
             sum(o.total) AS revenue,
             avg(o.total) AS avg_order_value
    sources:
      - sourceId: orders-db

Relationship Query with Joins

Query across related entities (requires join configuration):

queries:
  - id: orders-with-customers
    query: |
      MATCH (o:Order)-[:PLACED_BY]->(c:Customer)
      WHERE o.status = 'pending'
      RETURN o.id, o.total, c.name, c.email
    sources:
      - sourceId: orders-db
    joins:
      - id: PLACED_BY
        keys:
          - label: Order
            property: customer_id
          - label: Customer
            property: id

Join Configuration

Joins connect nodes that don’t have explicit relationships in the source data. This is common when working with relational databases where foreign keys define relationships.

Basic Join

joins:
  - id: PLACED_BY              # Relationship label used in query
    keys:
      - label: Order            # First node label
        property: customer_id   # Foreign key property
      - label: Customer         # Second node label  
        property: id            # Primary key property

This creates a virtual PLACED_BY relationship from Order to Customer where Order.customer_id = Customer.id.

Multiple Joins

queries:
  - id: order-details
    query: |
      MATCH (o:Order)-[:PLACED_BY]->(c:Customer),
            (o)-[:CONTAINS]->(i:OrderItem)
      RETURN o.id, c.name, i.product_name, i.quantity
    sources:
      - sourceId: orders-db
    joins:
      - id: PLACED_BY
        keys:
          - label: Order
            property: customer_id
          - label: Customer
            property: id
      - id: CONTAINS
        keys:
          - label: Order
            property: id
          - label: OrderItem
            property: order_id

Bootstrap Configuration

Bootstrap loads initial data when a query starts, so results reflect existing state (not just new changes).

Enable/Disable Bootstrap

queries:
  - id: streaming-only
    query: "MATCH (e:Event) RETURN e"
    enableBootstrap: false      # Only process new events
    sources:
      - sourceId: event-stream

Bootstrap Buffer Size

For large datasets, increase the buffer:

queries:
  - id: large-dataset
    query: "MATCH (p:Product) RETURN p"
    enableBootstrap: true
    bootstrapBufferSize: 50000  # Default is 10000
    sources:
      - sourceId: catalog-db

Performance Tuning

Queue Capacity

For high-volume queries, increase queue capacity:

queries:
  - id: high-volume
    query: "MATCH (e:Event) RETURN e"
    priorityQueueCapacity: 100000    # Events waiting to be processed
    dispatchBufferCapacity: 10000    # Events waiting to be dispatched
    sources:
      - sourceId: event-stream

Multiple Sources

A query can subscribe to multiple sources:

queries:
  - id: unified-view
    query: "MATCH (p:Product) RETURN p.id, p.name, p.source"
    sources:
      - sourceId: warehouse-a
      - sourceId: warehouse-b

Complete Example

host: 0.0.0.0
port: 8080

sources:
  - kind: postgres
    id: orders-db
    host: ${DB_HOST}
    database: ecommerce
    user: ${DB_USER}
    password: ${DB_PASSWORD}
    tables:
      - public.orders
      - public.customers
      - public.order_items
    bootstrapProvider:
      kind: postgres

queries:
  # Simple: All pending orders
  - id: pending-orders
    autoStart: true
    query: |
      MATCH (o:orders)
      WHERE o.status = 'pending'
      RETURN o.id, o.customer_id, o.total, o.created_at
    sources:
      - sourceId: orders-db

  # Aggregation: Order statistics  
  - id: order-stats
    autoStart: true
    query: |
      MATCH (o:orders)
      RETURN o.status AS status,
             count(o) AS count,
             sum(o.total) AS total_value
    sources:
      - sourceId: orders-db

  # Join: Orders with customer details
  - id: orders-with-customers
    autoStart: true
    query: |
      MATCH (o:orders)-[:CUSTOMER]->(c:customers)
      WHERE o.total > 100
      RETURN o.id, o.total, c.name, c.email
    sources:
      - sourceId: orders-db
    joins:
      - id: CUSTOMER
        keys:
          - label: orders
            property: customer_id
          - label: customers
            property: id

reactions:
  - kind: log
    id: console
    queries: [pending-orders, order-stats, orders-with-customers]
    autoStart: true

Troubleshooting

Issue Cause Solution
Query returns no results Labels don’t match source data Check label names match exactly (case-sensitive)
Join not working Keys don’t match Verify join key properties exist and values match
Bootstrap timeout Large dataset Increase bootstrapBufferSize
Query not starting autoStart: false Set autoStart: true or start via API
Missing data Wrong source subscription Verify sourceId matches your source’s id

Verifying Query Results

Check current results via API:

curl http://localhost:8080/api/v1/queries/my-query/results

Check query status:

curl http://localhost:8080/api/v1/queries/my-query