SPARQL query service (#754)

SPARQL 1.1 query service wrapping pub/sub triples interface

Add a backend-agnostic SPARQL query service that parses SPARQL
queries using rdflib, decomposes them into triple pattern lookups
via the existing TriplesClient pub/sub interface, and performs
in-memory joins, filters, and projections.

Includes:
- SPARQL parser, algebra evaluator, expression evaluator, solution
  sequence operations (BGP, JOIN, OPTIONAL, UNION, FILTER, BIND,
  VALUES, GROUP BY, ORDER BY, LIMIT/OFFSET, DISTINCT, aggregates)
- FlowProcessor service with TriplesClientSpec
- Gateway dispatcher, request/response translators, API spec
- Python SDK method (FlowInstance.sparql_query)
- CLI command (tg-invoke-sparql-query)
- Tech spec (docs/tech-specs/sparql-query.md)

New unit tests for SPARQL query
This commit is contained in:
cybermaggedon 2026-04-02 17:21:39 +01:00 committed by GitHub
parent 62c30a3a50
commit d9dc4cbab5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 3498 additions and 3 deletions

View file

@ -1122,6 +1122,45 @@ class FlowInstance:
return result
def sparql_query(
self, query, user="trustgraph", collection="default",
limit=10000
):
"""
Execute a SPARQL query against the knowledge graph.
Args:
query: SPARQL 1.1 query string
user: User/keyspace identifier (default: "trustgraph")
collection: Collection identifier (default: "default")
limit: Safety limit on results (default: 10000)
Returns:
dict with query results. Structure depends on query type:
- SELECT: {"query-type": "select", "variables": [...], "bindings": [...]}
- ASK: {"query-type": "ask", "ask-result": bool}
- CONSTRUCT/DESCRIBE: {"query-type": "construct", "triples": [...]}
Raises:
ProtocolException: If an error occurs
"""
input = {
"query": query,
"user": user,
"collection": collection,
"limit": limit,
}
response = self.request("service/sparql", input)
if "error" in response and response["error"]:
error_type = response["error"].get("type", "unknown")
error_message = response["error"].get("message", "Unknown error")
raise ProtocolException(f"{error_type}: {error_message}")
return response
def nlp_query(self, question, max_results=100):
"""
Convert a natural language question to a GraphQL query.