# How to Query the Knowledge Graph Using SPARQL in Semantica: API and Programmatic Methods

> Learn to query the Semantica knowledge graph using SPARQL via its API endpoint or programmatically with the QueryEngine class. Get normalized JSON results safely.

- Repository: [Semantica /semantica](https://github.com/semantica-agi/semantica)
- Tags: how-to-guide
- Published: 2026-09-04

---

**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`](https://github.com/semantica-agi/semantica/blob/main/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:

```bash
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:

```json
{
  "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:

```python
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`](https://github.com/semantica-agi/semantica/blob/main/semantica/triplet_store/query_engine.py) to execute SPARQL directly against store backends like Blazegraph or RDF4J.

```python
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`](https://github.com/semantica-agi/semantica/blob/main/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/sparql` endpoint in [`semantica/explorer/routes/sparql.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/explorer/routes/sparql.py) provides read-only access with multi-layered validation.
- Queries must start with `SELECT`, `ASK`, `CONSTRUCT`, or `DESCRIBE`; mutating keywords trigger immediate rejection.
- The system materializes a temporary rdflib graph capped by `_SPARQL_MAX_GRAPH_NODES` before execution.
- Use `QueryEngine` in [`semantica/triplet_store/query_engine.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/triplet_store/query_engine.py) for 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`](https://github.com/semantica-agi/semantica/blob/main/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`](https://github.com/semantica-agi/semantica/blob/main/rdf4j_store.py) for RDF4J endpoints, and you can extend it for other triple stores like Blazegraph by implementing the `execute_sparql` method.