How to Query the Knowledge Graph Using SPARQL in Semantica: API and Programmatic Methods
Semantica stores its knowledge graph as a triplet store and exposes a safe, read-only SPARQL interface through the /api/sparql endpoint, which validates queries against mutating keywords, materializes an in-memory rdflib projection, and returns normalized JSON results, while the QueryEngine class enables direct programmatic execution against backend stores.
Semantica is an open-source framework that structures data as a semantic knowledge graph. When you need to retrieve specific entities, relationships, or patterns from this graph, you can query the knowledge graph using SPARQL in Semantica through either its protected HTTP API or the internal QueryEngine class.
How the SPARQL Endpoint Processes Queries
The /api/sparql route in semantica/explorer/routes/sparql.py handles incoming requests through a four-stage pipeline that ensures safety and performance.
Request Validation
Every incoming query string undergoes strict validation before execution. The _is_read_only_query function strips comments and PREFIX/BASE declarations, then verifies the first keyword matches _ALLOWED_QUERY_TYPES (SELECT, ASK, CONSTRUCT, or DESCRIBE). If the query contains any _FORBIDDEN_KEYWORDS such as INSERT, DELETE, or DROP, the system rejects it immediately. The query length is also checked against _SPARQL_MAX_QUERY_LEN to prevent resource exhaustion.
Graph Materialization
Once validated, the system calls _build_rdflib_graph to create a temporary in-memory RDF representation. This process fetches nodes and edges from the current session, capped by _SPARQL_MAX_GRAPH_NODES to prevent out-of-memory errors. Each node becomes an RDF subject with type, label, and property triples, while edges translate to predicate triples connecting these subjects.
Query Execution
The validated query runs against the materialized graph using graph.query() inside an asyncio thread. Execution is guarded by _sparql_semaphore to limit concurrent queries and bounded by _SPARQL_TIMEOUT_S. If rdflib raises parsing or execution errors, the system captures line and column details for debugging.
Result Normalization
Results transform into a uniform SparqlResponse JSON structure depending on query type. ASK queries return a single boolean row, while CONSTRUCT and DESCRIBE return rows of {subject, predicate, object} triples. SELECT queries return rows keyed by projected variable names. The system enforces _SPARQL_MAX_ROWS and sets a truncated flag when results exceed this limit.
Querying via the HTTP API
You can query the knowledge graph using SPARQL in Semantica by sending POST requests to the /api/sparql endpoint with a JSON payload containing your query string.
Using cURL
Send a simple SELECT query to retrieve triples:
curl -X POST https://your-semantic-server/api/sparql \
-H "Content-Type: application/json" \
-d '{"query":"SELECT ?s ?p ?o WHERE { ?s ?p ?o } LIMIT 10"}'
The response follows the SparqlResponse schema:
{
"columns": ["s", "p", "o"],
"rows": [
{"s":"http://semantica.local/entity/1","p":"http://semantica.local/prop/name","o":"Alice"},
{"s":"http://semantica.local/entity/2","p":"http://semantica.local/prop/name","o":"Bob"}
],
"total": 2,
"truncated": false,
"error": null
}
Using Python Requests
For programmatic HTTP access, use the requests library to handle prefixes and filtering:
import requests
url = "https://your-semantic-server/api/sparql"
payload = {"query": """
PREFIX ent: <http://semantica.local/entity/>
PREFIX prop: <http://semantica.local/prop/>
SELECT ?name WHERE {
?person a ent:Person ;
prop:name ?name .
} LIMIT 5
"""}
resp = requests.post(url, json=payload)
data = resp.json()
print(data["columns"], data["rows"])
Programmatic Querying with QueryEngine
For server-side logic or backend integrations, instantiate the QueryEngine class from semantica/triplet_store/query_engine.py to execute SPARQL directly against store backends like Blazegraph or RDF4J.
from semantica.triplet_store.query_engine import QueryEngine
engine = QueryEngine(enable_caching=False, enable_optimization=False)
sparql = """
SELECT ?entity ?label WHERE {
?entity a <http://semantica.local/entity/Entity> ;
<http://www.w3.org/2000/01/rdf-schema#label> ?label .
} ORDER BY ?label LIMIT 5
"""
result = engine.execute_query(sparql, store)
print(result.variables) # ['entity', 'label']
print(result.bindings) # [{'entity': 'http://...', 'label': 'Alice'}, ...]
The execute_query method performs the same validation as the API route through its internal _validate_query function (lines 44-60 in query_engine.py). You can enable caching and query optimization by setting enable_caching=True and enable_optimization=True during engine initialization.
Security Constraints and Performance Limits
Semantica implements multiple safeguards to protect the knowledge graph integrity. The SPARQL interface is strictly read-only, rejecting any data manipulation language. Resource limits include maximum query length (_SPARQL_MAX_QUERY_LEN), concurrent query throttling via _sparql_semaphore, execution timeouts (_SPARQL_TIMEOUT_S), and result set truncation (_SPARQL_MAX_ROWS). Graph materialization is bounded by _SPARQL_MAX_GRAPH_NODES to prevent memory exhaustion during temporary rdflib construction.
Summary
- The
/api/sparqlendpoint insemantica/explorer/routes/sparql.pyprovides read-only access with multi-layered validation. - Queries must start with
SELECT,ASK,CONSTRUCT, orDESCRIBE; mutating keywords trigger immediate rejection. - The system materializes a temporary rdflib graph capped by
_SPARQL_MAX_GRAPH_NODESbefore execution. - Use
QueryEngineinsemantica/triplet_store/query_engine.pyfor programmatic access to backend stores. - All execution paths enforce timeouts, concurrency limits, and row count caps to ensure stability.
Frequently Asked Questions
Can I use SPARQL UPDATE queries to modify the knowledge graph in Semantica?
No. The _is_read_only_query function explicitly blocks INSERT, DELETE, DROP, and other mutating keywords. The /api/sparql endpoint is designed solely for read operations to prevent accidental or malicious graph modifications.
What happens if my SPARQL query returns too many results?
The system enforces _SPARQL_MAX_ROWS during result normalization. If your query exceeds this limit, the response includes a truncated: true flag and returns only the maximum allowed rows.
How does Semantica prevent SPARQL injection attacks?
The validation layer strips comments and PREFIX/BASE declarations before checking query structure. Additionally, sparql_escaping.py provides utilities for safe literal escaping and IRI validation used throughout the query pipeline.
What backend stores does QueryEngine support?
The QueryEngine class abstracts over multiple backends through a common interface. The repository includes implementations such as rdf4j_store.py for RDF4J endpoints, and you can extend it for other triple stores like Blazegraph by implementing the execute_sparql method.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →