--- title: "Triplet Store Module" description: "RDF triple storage with SPARQL queries and bulk loading — Blazegraph, Apache Jena, and RDF4J." icon: "table" --- `semantica.triplet_store` provides W3C-standard RDF storage with full SPARQL query support. Use it when you need semantic web compatibility, OWL reasoning, SPARQL-based queries, or standards-compliant RDF serialization. ## Exported Classes | Class | Role | | --- | --- | | `TripletStore` | Unified interface: `add_triplet`, `get_triplets`, `delete_triplet`, `execute_query`, `bulk_load` | | `QueryEngine` | SPARQL 1.1 execution with query optimization and result streaming | | `BulkLoader` | High-volume RDF loading with progress tracking and transaction batching | | `BlazegraphStore` | Blazegraph REST API — Named Graphs, SPARQL 1.1 Update, GeoSPARQL | | `JenaStore` | Apache Jena Fuseki — TDB2 backend, GeoSPARQL, SPARQL 1.1 | | `RDF4JStore` | Eclipse RDF4J — SailRepository, in-memory or native store | ## What You Get Unified interface across Blazegraph, Apache Jena (Fuseki), and RDF4J — swap backends with one parameter. Zero-setup in-memory mode via `backend="memory"` for unit tests and small datasets — no server required. Full SELECT, CONSTRUCT, ASK, and UPDATE query support with pagination for large result sets. Apache Jena supports OWL and RDFS inference natively — subclass and property chain queries automatically resolved. Isolate triples by source, dataset, or time period using named graph management. Load and serialize to Turtle, JSON-LD, N-Triples, and RDF/XML with a single method call. ## Quick Start ```python from semantica.triplet_store import TripletStore store = TripletStore( backend="blazegraph", endpoint="http://localhost:9999/blazegraph/sparql" ) ``` ```python # Add a single triplet store.add_triplet( subject="http://example.org/apple_inc", predicate="http://example.org/founded_by", obj="http://example.org/steve_jobs" ) # Bulk load a list of triplets store.add_triplets_bulk(triplets) ``` ```python results = store.sparql(""" PREFIX ex: SELECT ?person ?company WHERE { ?person ex:founded ?company . ?company ex:located_in ex:SiliconValley . } """) for row in results: print(row["person"], row["company"]) ``` ```python store.export("output.ttl", format="turtle") store.export("output.nt", format="nt") store.export("output.xml", format="xml") ``` ## Backends ```python from semantica.triplet_store import TripletStore store = TripletStore( backend="blazegraph", endpoint="http://localhost:9999/blazegraph/sparql", namespace="semantica" ) ``` Best for: Wikidata-style workloads, high triple counts, SPARQL 1.1 full support. ```python store = TripletStore( backend="jena", endpoint="http://localhost:3030/dataset/sparql", update_endpoint="http://localhost:3030/dataset/update" ) ``` Best for: General RDF, standard SPARQL, production deployments needing OWL inference. **Enable OWL reasoning:** ```python store = TripletStore( backend="jena", endpoint="http://localhost:3030/dataset/sparql", update_endpoint="http://localhost:3030/dataset/update", reasoner="OWL", # "OWL" | "RDFS" | "OWL_MINI" | None ) # Load an OWL ontology — subclass/property chain inferences are automatic store.import_file("ontology.ttl", format="turtle") store.add_triplets_bulk(data_triplets) # Query using inferred relationships results = store.sparql(""" SELECT ?person WHERE { ?person a ex:Employee . # inferred via subClassOf chain } """) ``` ```python store = TripletStore( backend="rdf4j", server_url="http://localhost:8080/rdf4j-server", repository_id="semantica" ) ``` Best for: Enterprise Java ecosystems, Eclipse Foundation deployments, plugin-based reasoning. | Backend | License | OWL Reasoning | Hosted Option | Best For | | ------- | ------- | ------------- | ------------- | -------- | | Blazegraph | Open source | No | Self-hosted | Wikidata-style workloads, high triple count | | Apache Jena | Apache 2.0 | Yes (OWL/RDFS) | Self-hosted | General RDF, OWL reasoning, standard SPARQL | | RDF4J | Eclipse 1.0 | Via plugin | Self-hosted or cloud | Enterprise Java ecosystems | | InMemory | Built-in | No | N/A | Unit tests, small graphs, no server required | ## Namespace Prefix Management Register custom prefixes to keep SPARQL queries readable: ```python from semantica.triplet_store import TripletStore from semantica.ontology import NamespaceManager ns = NamespaceManager(base_uri="http://example.org/") ns.register("ex", "http://example.org/") ns.register("schema", "https://schema.org/") ns.register("owl", "http://www.w3.org/2002/07/owl#") store = TripletStore(backend="jena", endpoint="...") # Registered prefixes are automatically prepended to every SPARQL query results = store.sparql(""" SELECT ?company WHERE { ?person ex:works_for ?company ; schema:name "Alice" . } """) ``` ## TripletStore Methods | Method | Returns | Description | | ------ | ------- | ----------- | | `add_triplet(s, p, o, graph=None)` | `str` | Add a single triplet, returns triplet ID | | `add_triplets_bulk(triplets)` | `List[str]` | Batch add triplets with transaction support | | `get_triplets(graph=None)` | `List[dict]` | Retrieve all triplets or from a named graph | | `delete_triplet(triplet_id)` | `bool` | Delete a triplet by ID | | `sparql(query)` | `List[dict]` | Execute SPARQL SELECT query | | `sparql_construct(query)` | `Graph` | Execute SPARQL CONSTRUCT query | | `sparql_ask(query)` | `bool` | Execute SPARQL ASK query | | `sparql_update(query)` | `None` | Execute SPARQL UPDATE (INSERT/DELETE) | | `bulk_load(file, format)` | `None` | Load RDF file (turtle, nt, xml) | | `export(path, format)` | `None` | Export to turtle, nt, xml | | `list_graphs()` | `List[str]` | List all named graphs | | `clear_graph(graph_uri)` | `None` | Delete all triples from a named graph | ## SPARQL Queries ```python # SELECT — returns tabular results results = store.sparql(""" PREFIX ex: SELECT ?person ?company WHERE { ?person ex:founded ?company . ?company ex:located_in ex:SiliconValley . } """) # CONSTRUCT — returns a graph of matched triples graph = store.sparql_construct(""" PREFIX ex: CONSTRUCT { ?s ex:connected_to ?o } WHERE { ?s ex:founded ?company . ?company ex:has_investor ?o . } """) # ASK — returns True/False exists = store.sparql_ask(""" PREFIX ex: ASK { ex:apple_inc ex:founded_by ex:steve_jobs . } """) # UPDATE — insert or delete triples store.sparql_update(""" PREFIX ex: INSERT DATA { ex:apple_inc ex:listed_on ex:NASDAQ . } """) ``` ## SPARQL Result Pagination For large result sets, paginate with LIMIT and OFFSET: ```python page_size = 1000 offset = 0 while True: results = store.sparql(f""" SELECT ?s ?p ?o WHERE {{ ?s ?p ?o . }} ORDER BY ?s LIMIT {page_size} OFFSET {offset} """) if not results: break process_batch(results) offset += page_size ``` ## Named Graph Management ```python # Named graphs — store triples in isolated contexts store.add_triplet( subject="http://example.org/a", predicate="http://example.org/p", obj="http://example.org/b", graph="http://example.org/graph1" ) # Query a specific named graph results = store.sparql(""" SELECT ?s ?p ?o FROM WHERE { ?s ?p ?o . } """) # List all named graphs graphs = store.list_graphs() # Clear a named graph store.clear_graph("http://example.org/graph1") ``` ## Integration with Export Module The Export module can write RDF that the triplet store then imports: ```python from semantica.export import RDFExporter from semantica.triplet_store import TripletStore # Export KG to Turtle exporter = RDFExporter() exporter.export_to_file(kg, "output.ttl", format="turtle") # Load into triplet store store = TripletStore(backend="jena", endpoint="http://localhost:3030/dataset/sparql") store.import_file("output.ttl", format="turtle") # Now query with SPARQL results = store.sparql("SELECT * WHERE { ?s ?p ?o } LIMIT 10") ``` ## Tips and Common Pitfalls **Use Apache Jena (Fuseki) for development and Blazegraph for production.** Jena runs with a single Docker command, supports OWL reasoning natively, and requires no licence. Switch to Blazegraph for high-throughput workloads by changing the `backend=` parameter — no other code changes needed. **Paginate large SPARQL result sets.** A `SELECT * WHERE { ?s ?p ?o }` against a million-triple store can return gigabytes of data. Always include `LIMIT` and `OFFSET` in exploratory queries, and iterate with `page_size` when you need full coverage. Unbounded queries against large stores will OOM or timeout. **Use named graphs to isolate sources.** `store.add_triplet(..., graph="http://example.org/source_A")` puts triples into a named graph. You can then query just that source, merge selectively, or clear it without touching other data — far safer than mixing all triples into the default graph. **Register namespace prefixes before querying.** `NamespacePrefixManager` lets you write `?s ex:name ?o` instead of `?s ?o`. Without prefixes, SPARQL queries against domain ontologies become unreadable and error-prone. **Enable OWL reasoning only when you need it.** `reasoner="OWL"` significantly increases query planning overhead. For simple triple lookups or SPARQL SELECT queries, leave reasoning off (`reasoner=None`) and enable it only for queries that depend on class hierarchies or property chains. **Export to Turtle before migrating backends.** If you need to move from Jena to Blazegraph (or any other store), `store.export("dump.ttl", format="turtle")` produces a portable file that any SPARQL store can import. Don't rely on backend-specific dump formats. Export knowledge graphs to RDF formats. Load OWL ontologies into a triplet store. SPARQL-based property chain inference. Property graph alternative for Cypher queries.