# How to Query Knowledge Graphs Using SPARQLReasoner with RDF Backends

> Learn to query knowledge graphs with SPARQLReasoner and RDF backends. Instantiate, register rules, and execute queries for automatic inference and expansion.

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

---

**Instantiate `SPARQLReasoner` with an RDF triplet store (e.g., `BlazegraphStore`), register inference rules via `add_inference_rule`, and call `execute_query` to run SPARQL with automatic query expansion and result inference.**

The `semantica-agi/semantica` repository provides a high-level interface for semantic reasoning over RDF data. The `SPARQLReasoner` class serves as the primary entry point for querying knowledge graphs using SPARQL while integrating rule-based inference capabilities across various RDF backends.

## Architecture Overview

`SPARQLReasoner` orchestrates query execution through three main components:

- **SPARQLReasoner**: The high-level orchestrator that manages query expansion, execution, inference, and caching. Implemented in [[`semantica/reasoning/sparql_reasoner.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/reasoning/sparql_reasoner.py)](https://github.com/semantica-agi/semantica/blob/main/semantica/reasoning/sparql_reasoner.py#L51).
- **Reasoner**: Handles inference rules and provides forward/backward chaining capabilities. Located in [[`semantica/reasoning/reasoner.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/reasoning/reasoner.py)](https://github.com/semantica-agi/semantica/blob/main/semantica/reasoning/reasoner.py#L57).
- **Triplet Store**: The concrete RDF backend (Blazegraph, Jena, RDF4J) that executes SPARQL queries. Injected via the `triplet_store` parameter.

## Initializing the RDF Backend

Before creating a `SPARQLReasoner`, you must instantiate a compatible RDF triplet store. The repository supports multiple backends through a common `TripletStore` interface.

For example, to connect to Blazegraph:

```python
from semantica.triplet_store import BlazegraphStore

store = BlazegraphStore(
    endpoint="http://localhost:9999/blazegraph/sparql",
    namespace="mykg"
)

```

Other supported implementations include `JenaStore`, `RDF4JStore`, and `OxigraphStore`, all located in the `semantica/triplet_store/` directory.

## Configuring SPARQLReasoner

Create the reasoner instance by injecting the store and enabling inference:

```python
from semantica.reasoning import SPARQLReasoner

reasoner = SPARQLReasoner(
    triplet_store=store,
    enable_inference=True
)

```

The `enable_inference` flag activates rule-based query expansion and result enrichment.

## Adding Inference Rules

Register IF-THEN rules to expand the knowledge graph during query execution:

```python
rule_def = "IF ?x is_a Person AND ?x is_a Human THEN ?x is_a Mammal"
reasoner.add_inference_rule(rule_def)

```

Internally, `Reasoner._parse_rule_definition` processes these strings and stores them in `self.reasoner.rules`.

## Executing Queries

The `execute_query` method follows a sophisticated pipeline:

1. **Cache Check**: Verifies `self.query_cache` for existing results.
2. **Query Expansion**: Calls `expand_query` (lines 89-146 in [`sparql_reasoner.py`](https://github.com/semantica-agi/semantica/blob/main/sparql_reasoner.py)) to append inference patterns.
3. **Backend Execution**: Dispatches SPARQL to the triplet store.
4. **Result Inference**: Applies `infer_results` (lines 88-124) to enrich bindings using the rule set.
5. **Caching**: Stores the final `SPARQLQueryResult` dataclass (defined at lines 42-48) before returning.

```python
raw_query = """
    SELECT ?s ?p ?o
    WHERE { ?s ?p ?o }
    LIMIT 10
"""

result = reasoner.execute_query(raw_query)

print("Variables:", result.variables)
for binding in result.bindings:
    print(binding)

```

## Complete Implementation Example

Here is a full workflow from initialization to result inspection:

```python
from semantica.triplet_store import BlazegraphStore
from semantica.reasoning import SPARQLReasoner

# 1. Initialize RDF backend

store = BlazegraphStore(
    endpoint="http://localhost:9999/blazegraph/sparql",
    namespace="mykg"
)

# 2. Create reasoner with inference enabled

reasoner = SPARQLReasoner(
    triplet_store=store,
    enable_inference=True
)

# 3. Add inference rule

rule = "IF ?x is_a Person THEN ?x is_a Agent"
reasoner.add_inference_rule(rule)

# 4. Execute SPARQL query

query = "SELECT ?s ?p ?o WHERE { ?s ?p ?o } LIMIT 10"
result = reasoner.execute_query(query)

# 5. Inspect results

for binding in result.bindings:
    print(binding)

# 6. Clear cache if needed

reasoner.clear_cache()

```

## Summary

- `SPARQLReasoner` in [`semantica/reasoning/sparql_reasoner.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/reasoning/sparql_reasoner.py) provides the main interface for SPARQL-based reasoning.
- Any RDF backend implementing the `TripletStore` interface can be injected via the `triplet_store` parameter.
- Query execution involves caching, expansion via `expand_query`, backend execution, and inference via `infer_results`.
- Results are returned as `SPARQLQueryResult` dataclasses containing variables, bindings, and metadata.
- Progress tracking events are emitted throughout the pipeline (lines 100-110 and 150-158) for observability.

## Frequently Asked Questions

### What RDF backends are supported by SPARQLReasoner?

The system supports any store implementing the `TripletStore` interface. Reference implementations include `BlazegraphStore`, `JenaStore`, `RDF4JStore`, and `OxigraphStore`. You can swap backends by changing the import and instantiation while keeping the same `SPARQLReasoner` configuration.

### How does query caching work in SPARQLReasoner?

The reasoner maintains an in-memory `query_cache` dictionary. Before executing a query, `execute_query` checks this cache. If results exist, they are returned immediately. Otherwise, the query proceeds through expansion and execution, with the final `SPARQLQueryResult` stored in the cache before return. Use `clear_cache()` to invalidate entries.

### Can I use SPARQLReasoner without inference?

Yes. Set `enable_inference=False` when instantiating `SPARQLReasoner`. In this mode, the reasoner skips the `expand_query` and `infer_results` steps, passing SPARQL directly to the triplet store without rule-based modification.

### How are IF-THEN inference rules parsed?

Rules are parsed by `Reasoner._parse_rule_definition` in [`semantica/reasoning/reasoner.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/reasoning/reasoner.py). The parser converts IF-THEN strings into internal rule objects stored in `self.reasoner.rules`. These rules drive both query expansion (modifying the SPARQL pattern) and result inference (enriching returned bindings).