databrickslabs / databrickslabs/ontobricks
[BUG]: Spark SPARQL translator silently drops unsupported clauses and breaks OPTIONAL
@benoitcayladbx is already working on this.
Since Sep 11, 2026.
- Dominant language
- Python
- Stars
- 377
- Forks
- 69
- Avg merge
- 7h 42m
- Merged PRs (30d)
- 5
Description
Is there an existing issue for this?
- I have searched the existing issues
Current Behavior
The Explorer SPARQL path (SparqlTranslator.translate_sparql_to_spark) translates SPARQL to Spark SQL with a regex pipeline. Valid SPARQL outside the supported subset can disappear from the generated SQL without an error. The SQL is executable but has different semantics from the submitted query.
Confirmed silent drops:
GROUP BY/ aggregates- numeric or complex
FILTERexpressions (the parser never emitsgt/lt/gte/lte, despite the docstring advertisingFILTER(?var > value)) - property paths
A second, independent defect: relationship OPTIONAL patterns emit LEFT JOINs, then add {rel}.{col} IS NOT NULL predicates to the top-level WHERE. A single OPTIONAL becomes mandatory; multiple OPTIONALs are OR-joined, so the query requires at least one optional match.
The public /api/v1/query default (engine=local) is not an equivalent fallback: RDFLib queries the R2RML mapping graph, not warehouse data. Explorer (/dtwin/execute, /dtwin/translate) always uses the Spark translator with no RDFLib fallback.
Expected Behavior
- Valid-but-unsupported Spark SPARQL is rejected with
ValidationErrorbefore SQL generation (fail-closed). Messages identify the construct, e.g.Spark SPARQL does not support GROUP BY. - The currently supported subset still translates (SELECT, DISTINCT, LIMIT, simple BGP, supported string FILTERs, literal BIND, specialized relationship UNION).
- Relationship OPTIONAL preserves unmatched primary rows (
LEFT JOINwithout a top-level presence predicate). Unbound optional vars are NULL. - Local RDFLib is not advertised as a warehouse-data fallback.
Steps To Reproduce
- Open Explorer SPARQL against a mapped domain with warehouse data.
- Run:
SELECT ?s WHERE { ?s a <http://example.org/Customer> } GROUP BY ?s
- Observe a successful SQL translation with no
GROUP BY(same for numericFILTERand property paths). - Run a relationship OPTIONAL:
SELECT ?c ?o WHERE {
?c a <http://example.org/Customer> .
OPTIONAL { ?c <http://example.org/hasOrder> ?o }
}
- Inspect generated SQL:
LEFT JOINplusWHERE (rel.customer_id IS NOT NULL), which drops customers with no order.
Unit-level reproduction (no warehouse):
from back.core.w3c.sparql.SparqlTranslator import SparqlTranslator
# GROUP BY / FILTER / property path currently return success with incomplete SQL
# OPTIONAL currently emits WHERE (rel_o.customer_id IS NOT NULL)
Cloud
Azure
Browser
Chrome
OntoBricks Version
0.9.0
Relevant log output
# Example: GROUP BY query currently succeeds with incomplete SQL
SELECT t_s.customer_id AS s
FROM (SELECT * FROM test_catalog.test_schema.customers) AS t_s
WHERE 1=1 LIMIT 10
# Example: relationship OPTIONAL currently adds a presence filter
SELECT t_c.customer_id AS c, rel_o.order_id AS o
FROM ... LEFT JOIN (...) AS rel_o ON t_c.customer_id = rel_o.customer_id
WHERE (rel_o.customer_id IS NOT NULL)
LIMIT 10
Additional Context
Primary files
src/back/core/w3c/sparql/SparqlTranslator.py(_parse_value_filters~505–611,_spark_finalize_query_sql~2036–2041, OPTIONAL LEFT JOIN +optional_rel_conditions~1813–1943)src/back/core/w3c/sparql/DomainQueryService.py(local engine queries R2RML, not warehouse)tests/back/core/w3c/sparql/test_sparql_translator_units.py(19 tests; 9 useif result.get("success")and can pass on failed translation)
Approved design (this issue)
docs/superpowers/specs/2026-09-11-spark-sparql-fail-closed-design.md
Scope: RDFLib algebra capability gate + OPTIONAL correction + test hardening. Non-goals: full SPARQL 1.1, numeric FILTER implementation, algebra-to-SQL rewrite, RDFLib fallback, SWRL/T-Box changes.
Related findings (separate follow-ups, not this issue)
- SWRL: negated built-ins silently skipped in
_build_negated_atoms; unbound vars become string literals - Reasoning: no T-Box ↔ A-Box fixed-point; CWA/UNA from
NOT EXISTSunder-documented - Lint noise: claimed F821 locations are stale (0 on current tree); B904/F841 are hygiene
Acceptance
- Unsupported constructs raise
ValidationErrorinstead of returning incomplete SQL - Relationship OPTIONAL keeps unmatched rows
- Translator unit tests assert success unconditionally
- Docs state the Spark SPARQL subset and that local RDFLib is not a warehouse fallback
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.