# How to Use SPARQL for Reasoning in Semantica: A Complete Guide

> Master SPARQL reasoning in Semantica with our complete guide. Discover how Semantica's SPARQLReasoner class infers knowledge beyond explicit data for richer insights.

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

---

**Semantica provides a dedicated `SPARQLReasoner` class that expands standard SPARQL queries with inference rules and post-processes results to return both explicit and inferred knowledge.**

The **semantica-agi/semantica** repository implements a unified triplet-store architecture with a reasoning layer that sits between your SPARQL queries and the underlying RDF backend. This guide demonstrates how to leverage the `SPARQLReasoner` to perform rule-based inference using actual source implementations from the codebase.

## Understanding the SPARQL Reasoning Architecture

Semantica’s reasoning pipeline consists of three primary components that work together to enable SPARQL-based inference.

### Core Components

- **`SPARQLReasoner`** – Defined in [`semantica/reasoning/sparql_reasoner.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/reasoning/sparql_reasoner.py) (class starts at line 51), this high-level engine handles query expansion and result inference.
- **`TripletStore`** – Located in [`semantica/triplet_store/triplet_store.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/triplet_store/triplet_store.py) (line 40), this unified interface abstracts concrete RDF stores and provides the `execute_query` method (line 50) that forwards SPARQL to backends like Blazegraph, Jena, or Oxigraph.
- **`Reasoner`** – Implemented in [`semantica/reasoning/reasoner.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/reasoning/reasoner.py) (lines 57-73), this generic rule engine handles forward/backward chaining and converts rules to SPARQL patterns.

The `SPARQLReasoner` maintains an internal instance of the generic `Reasoner` class for rule handling, while delegating actual query execution to the `TripletStore`.

## Setting Up the Triplet Store for SPARQL Queries

Before reasoning can occur, you must initialize a `TripletStore` with a supported backend. The store validates the backend against `SUPPORTED_BACKENDS` and creates the concrete implementation via `_initialize_store_backend`.

```python
from semantica.triplet_store import TripletStore

# Initialize a Blazegraph store

store = TripletStore(backend="blazegraph")

# Load data using store methods

kg = {
    "entities": [
        {"id": "Alice", "type": "Person"},
        {"id": "Bob", "type": "Person"},
    ],
    "relationships": [
        {"source": "Alice", "target": "Bob", "type": "knows"}
    ]
}
ontology = {"classes": [{"name": "Person"}], "properties": []}
store.store(knowledge_graph=kg, ontology=ontology)

```

The `TripletStore.execute_query` method (lines 50-55) serves as the gateway that sends SPARQL strings to the selected backend’s `QueryEngine`.

## Configuring the SPARQLReasoner

Once the store contains data, create a `SPARQLReasoner` instance and optionally pass the store via the `triplet_store` configuration key.

### Initializing the Reasoner

```python
from semantica.reasoning.sparql_reasoner import SPARQLReasoner

reasoner = SPARQLReasoner(triplet_store=store)

```

The reasoner initializes with an empty `query_cache` dictionary (line 87) reserved for future optimization and creates an internal `Reasoner` instance for rule handling.

### Defining Inference Rules

Add rules using the `add_inference_rule` method (internally delegated to `reasoner.reasoner.add_rule`). Rules follow an "IF ... THEN ..." syntax and are stored as `Rule` objects:

```python

# Add a transitivity rule: Every Person is also an Agent

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

```

## Expanding SPARQL Queries with Inference Rules

The `expand_query` method (starting at line 92 in [`sparql_reasoner.py`](https://github.com/semantica-agi/semantica/blob/main/sparql_reasoner.py)) parses your SPARQL query, converts each registered rule to a SPARQL pattern via `_rule_to_sparql` (lines 55-84), and appends these patterns as comments to the original query.

```python

# Original query seeks Agents (none exist explicitly)

query = "SELECT ?x WHERE { ?x a :Agent }"

# Expand the query with inference patterns

expanded = reasoner.expand_query(query)
print(expanded)

# Output contains commented inference blocks:

#   # Inference: rule_1

#   ?x a :Agent .   # generated from the rule

```

This expansion encodes inference logic directly into the SPARQL string without modifying the original query semantics.

## Executing Queries and Processing Results

With the expanded query, you execute against the store and optionally apply additional inference to the result set.

### Running Expanded Queries Against the Store

The `TripletStore.execute_query` method forwards the SPARQL string to the backend’s `QueryEngine`, which handles parsing, optimization, and result materialization:

```python

# Execute the expanded query

raw_res = store.execute_query(expanded)

# Results contain bindings for both explicit and inferred matches

print(raw_res.bindings)

```

### Post-Processing with infer_results

For additional reasoning on the result set itself, use `infer_results` (line 91). This method applies the same rule set directly to the bindings, yielding additional inferred rows:

```python
from semantica.reasoning.sparql_reasoner import SPARQLQueryResult

# Wrap raw results in SPARQLQueryResult dataclass (lines 42-48)

result_obj = SPARQLQueryResult(
    bindings=raw_res.bindings,
    variables=raw_res.variables,
    metadata=raw_res.metadata
)

# Apply rules to the result set

final_res = reasoner.infer_results(result_obj)
print(f"Inferred rows added: {final_res.metadata['inferred_count']}")

```

## Complete End-to-End Example

This workflow demonstrates the full pipeline using an in-process Oxigraph backend:

```python
from semantica.triplet_store import TripletStore
from semantica.reasoning.sparql_reasoner import SPARQLReasoner, SPARQLQueryResult

# 1. Initialize store with Oxigraph (no external server required)

store = TripletStore(backend="oxigraph")

# 2. Load knowledge graph

kg = {
    "entities": [
        {"id": "Alice", "type": "Person"},
        {"id": "Bob", "type": "Person"}
    ],
    "relationships": []
}
store.store(knowledge_graph=kg, ontology={"classes": [{"name": "Person"}]})

# 3. Create reasoner and add inference rule

reasoner = SPARQLReasoner(triplet_store=store)
reasoner.add_inference_rule("IF ?x is_a Person THEN ?x is_a Agent")

# 4. Expand query to include inference

query = "SELECT ?x WHERE { ?x a :Agent }"
expanded = reasoner.expand_query(query)

# 5. Execute and post-process

raw = store.execute_query(expanded)
result = reasoner.infer_results(
    SPARQLQueryResult(bindings=raw.bindings, variables=raw.variables)
)

# 6. Access inferred results

for binding in result.bindings:
    print(binding['?x']['value'])  # Outputs Alice and Bob URIs

```

## 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 query expansion and result inference, starting at line 51.
- Use `expand_query` (line 92) to encode inference rules as SPARQL patterns before execution.
- The `TripletStore.execute_query` method (line 50) forwards queries to backends including Blazegraph, Jena, RDF4J, Anzo, and Oxigraph.
- Apply `infer_results` (line 91) to post-process result sets with the same rule set used during expansion.
- Rules follow "IF ... THEN ..." syntax and are managed by the internal `Reasoner` class defined in [`semantica/reasoning/reasoner.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/reasoning/reasoner.py).

## Frequently Asked Questions

### What backends does Semantica support for SPARQL reasoning?

Semantica supports **Blazegraph**, **Apache Jena**, **RDF4J**, **Anzo**, and **Oxigraph** through the `TripletStore` abstraction. The store validates against `SUPPORTED_BACKENDS` and dispatches queries via the backend-specific `QueryEngine` implementation.

### How does the expand_query method work internally?

The `expand_query` method parses the incoming SPARQL query, iterates through registered rules, and calls `_rule_to_sparql` (lines 55-84) to convert each rule into a SPARQL graph pattern. These patterns are appended as commented blocks to the original query string, allowing the backend to execute both explicit and inferred patterns in a single operation.

### Can I add multiple inference rules to a single query?

Yes. The `SPARQLReasoner` maintains a rule registry within its internal `Reasoner` instance. Multiple calls to `add_inference_rule` accumulate rules, and `expand_query` incorporates all registered rules into the expanded SPARQL output. Each rule generates a separate commented pattern block in the final query.

### What is the difference between expand_query and infer_results?

**`expand_query`** modifies the SPARQL string itself to include rule patterns before execution, allowing the RDF backend to compute inferences during query processing. **`infer_results`** operates on the already-executed `SPARQLQueryResult` object, applying rules to the binding set to derive additional conclusions that may not have been materialized by the backend.