Troubleshooting Queries¶
This guide covers how to debug and troubleshoot queries in Quine. Understanding the differences between query types helps you apply the right debugging approach.
Query Types in Quine¶
Quine has three types of queries, each with different troubleshooting approaches:
| Query Type | Description | When It Runs | Key Debugging Tools |
|---|---|---|---|
| Ad-hoc queries | Interactive Cypher queries you run manually | On-demand | EXPLAIN, recentNodes() |
| Ingest queries | Queries that execute for each record during data ingestion | Per-record during ingest | EXPLAIN, recentNodes() |
| Standing queries | Incremental pattern matching that fires when data matches | Continuously as data changes | standing.wiretap(), recentNodes() |
Ad-hoc Queries¶
Ad-hoc queries are interactive Cypher queries you run against the graph. Troubleshoot them when:
- Query returns unexpected results or no results
- Query is slow or times out
- Query causes high resource usage
Debugging approach: Use EXPLAIN to understand the execution plan.
Ingest Queries¶
Ingest queries run for each record in your data pipeline. Troubleshoot them when:
- Data isn't appearing in the graph
- Nodes have wrong properties or missing edges
- Ingest is slow or causing backpressure
Debugging approach: Test the query as an ad-hoc query first with sample data. Use recentNodes() to verify ingested data.
See also: Troubleshooting Ingest
Standing Queries¶
Standing queries incrementally match patterns as data enters the graph. Troubleshoot them when:
- Pattern should match but doesn't fire
- Getting unexpected matches or cancellations
- Standing query causes performance issues
Debugging approach: First run the pattern as an ad-hoc query to verify it matches expected data. Use standing.wiretap() to stream live results.
See also: Standing Queries
Debugging Tools Reference¶
| Tool | Page | Use For |
|---|---|---|
EXPLAIN |
Query Execution Plans | Understanding how queries execute |
standing.wiretap() |
Debugging Procedures | Streaming live standing query results |
recentNodes() |
Debugging Procedures | Viewing recently accessed nodes |
Debugging Workflow¶
Follow this systematic approach when queries don't behave as expected.
Step 1: Validate Ingested Data¶
Before debugging queries, confirm that data is flowing into the graph correctly:
// View recently ingested nodes
CALL recentNodes(10) YIELD node
RETURN node
In the Exploration UI, double-click nodes to view their edges and hover to see properties. Verify:
- Nodes exist with expected IDs
- Properties have correct values and types
- Edges connect the expected nodes
Step 2: Run as Ad-Hoc Query¶
If debugging a standing query or ingest query, run it as a regular Cypher query first:
// Your standing query pattern, run as ad-hoc
MATCH (order:Order)-[:PLACED_BY]->(customer:Customer)
WHERE order.total > 1000
RETURN order, customer
If this returns results but your standing query doesn't fire:
- The data may have been ingested before the standing query was registered
- Check if the query mode (DistinctId vs MultipleValues) is appropriate
Step 3: Analyze Query Plan¶
Use EXPLAIN to understand how your query executes:
EXPLAIN MATCH (order:Order)-[:PLACED_BY]->(customer:Customer)
WHERE order.total > 1000
RETURN order, customer
Look for:
- AllNodesScan in
AnchoredEntry: Consider anchoring by ID - Filter operators: Are conditions being applied efficiently?
- canContainAllNodeScan: true: Query may be slow on large graphs
Common Failure Patterns¶
Missing Data in Graph¶
If ingested data doesn't appear in the graph, common causes include inconsistent idFrom usage across data sources, ingest race conditions, and edge creation that depends on property matching instead of ID lookups.
See: Troubleshooting Ingest for detailed guidance on missing data and race conditions.
Standing Query Not Matching¶
| Symptom | Cause | Solution |
|---|---|---|
| Query works ad-hoc but not as standing query | Data ingested before standing query was registered | Re-ingest data or use standing.wiretap with isInitialResult |
| Pattern should match but doesn't | Data shape doesn't match pattern exactly | Run pattern as ad-hoc query to verify data matches |
| Matches initially then stops | Negative match canceling positive match | Check for data updates that invalidate the pattern |
Slow Query Performance¶
Slow queries typically result from full graph scans, standing query backpressure, supernodes, or cross-host messaging overhead.
See: Diagnosing Bottlenecks for metrics-based diagnosis and Troubleshooting Ingest for ingest-specific optimizations.
Debugging Procedures¶
Quine provides several procedures for inspecting query and node state.
standing.wiretap()¶
Streams live results from a running standing query. This procedure runs until the standing query is canceled, emitting results incrementally as they match.
// Wiretap "hasMaternalGrandpaJoe" and return properties of matching nodes
CALL standing.wiretap({ name: "hasMaternalGrandpaJoe" }) YIELD meta, data
WHERE meta.isPositiveMatch
MATCH (n) WHERE id(n) = data.id
RETURN properties(n)
Results appear incrementally as they match. Cancel the query when you have the information you need.
Warning
The standing.wiretap procedure only stops running if the standing query is canceled (since otherwise, it can never be certain that there won't be more forthcoming match results). This means that it is risky to use the procedure in the Cypher REST API or in other places where results are not reported incrementally and queries cannot be canceled.
Return Fields¶
| Field | Type | Description |
|---|---|---|
meta |
Map | Metadata including isPositiveMatch (boolean) and isInitialResult (boolean) |
data |
Map | The data returned by the standing query pattern |
Results API Endpoint¶
Quine can stream standing query results outside of the Exploration UI using the server-sent events (SSE) endpoint:
GET /api/v1/query/standing/{standingQueryName}/results
The endpoint surfaces new matches as they are produced.
$ curl http://localhost:8080/api/v1/query/standing/hasMaternalGrandpaJoe/results
data:
data:
data:{"data":{"id":"2756309260014435"},"meta":{"isInitialResult":true,"isPositiveMatch":true,"resultId":"8f408026-8fb3-3955-c81a-7259175f41b8"}}
event:result
id:8f408026-8fb3-3955-c81a-7259175f41b8
data:{"data":{"id":"7945274922095468"},"meta":{"isInitialResult":true,"isPositiveMatch":true,"resultId":"6a83dda3-08a1-e085-ee7d-14138398f336"}}
event:result
id:6a83dda3-08a1-e085-ee7d-14138398f336
Using the SSE output, you can query the matching nodes directly:
// Query for children of nodes with IDs from the SSE endpoint above
UNWIND [2756309260014435, 7945274922095468, 6994090876991233] AS personId
MATCH (person)<-[:HAS_MOTHER|:HAS_FATHER]-(child) WHERE id(person) = personId
RETURN person.name, child.name, child.yearBorn
recentNodes()¶
Fetches recently accessed nodes from the in-memory cache. Useful for quickly verifying that data is being ingested:
// View recently ingested nodes
CALL recentNodes(10) YIELD node
RETURN node
In the Exploration UI, double-click nodes to view their edges and hover to see properties.