Quick Start Guide
Building Trigo
# Clone or navigate to the repository
cd /path/to/trigo
# Build the CLI application
go build -o trigo ./cmd/trigo
# Verify the build
./trigo
Running the Demo
The demo creates a simple knowledge graph about people and their relationships:
./trigo demo
This will:
- Create a BadgerDB database in
./trigo_data - Insert sample triples about Alice, Bob, and Carol
- Execute a SPARQL SELECT query
- Display the results
Project Structure
trigo/
├── cmd/
│ ├── trigo/
│ │ └── main.go # CLI application entry point
│ └── test-runner/
│ └── main.go # W3C SPARQL test suite runner
├── internal/
│ ├── encoding/
│ │ ├── encoder.go # xxHash3 term encoding
│ │ └── decoder.go # Term decoding
│ ├── storage/
│ │ ├── storage.go # Storage interface
│ │ └── badger.go # BadgerDB implementation
│ └── testsuite/
│ ├── manifest.go # Test manifest parser
│ └── runner.go # Test execution engine
└── pkg/
├── rdf/
│ ├── term.go # RDF data model
│ └── turtle.go # Turtle/N-Triples parser
├── store/
│ ├── store.go # Triplestore with 11 indexes
│ └── query.go # Pattern matching queries
├── server/
│ ├── server.go # HTTP SPARQL endpoint
│ ├── handlers.go # HTTP request handlers
│ └── results/ # Result formatters
│ ├── json.go # SPARQL JSON results
│ ├── xml.go # SPARQL XML results
│ ├── csv.go # SPARQL CSV results
│ └── tsv.go # SPARQL TSV results
└── sparql/
├── parser/
│ ├── ast.go # Abstract Syntax Tree
│ └── parser.go # SPARQL parser
├── optimizer/
│ └── optimizer.go # Query optimizer
├── executor/
│ └── executor.go # Volcano iterator execution
└── evaluator/
└── evaluator.go # Expression evaluator
Using Trigo as a Library
Basic Example
package main
import (
"fmt"
"log"
"github.com/aleksaelezovic/trigo/internal/storage"
"github.com/aleksaelezovic/trigo/pkg/store"
"github.com/aleksaelezovic/trigo/pkg/rdf"
)
func main() {
// Create storage
storage, err := storage.NewBadgerStorage("./my_data")
if err != nil {
log.Fatal(err)
}
defer storage.Close()
// Create triplestore
ts := store.NewTripleStore(storage)
// Insert some triples
alice := rdf.NewNamedNode("http://example.org/alice")
name := rdf.NewNamedNode("http://xmlns.com/foaf/0.1/name")
triple := rdf.NewTriple(alice, name, rdf.NewLiteral("Alice"))
if err := ts.InsertTriple(triple); err != nil {
log.Fatal(err)
}
// Query data
pattern := &store.Pattern{
Subject: store.NewVariable("s"),
Predicate: store.NewVariable("p"),
Object: store.NewVariable("o"),
}
iter, err := ts.Query(pattern)
if err != nil {
log.Fatal(err)
}
defer iter.Close()
// Iterate results
for iter.Next() {
quad, err := iter.Quad()
if err != nil {
log.Fatal(err)
}
fmt.Println(quad)
}
}
SPARQL Query Example
package main
import (
"fmt"
"log"
"github.com/aleksaelezovic/trigo/pkg/sparql/executor"
"github.com/aleksaelezovic/trigo/pkg/sparql/optimizer"
"github.com/aleksaelezovic/trigo/pkg/sparql/parser"
"github.com/aleksaelezovic/trigo/internal/storage"
"github.com/aleksaelezovic/trigo/pkg/store"
)
func main() {
// Setup (storage, store)
storage, _ := storage.NewBadgerStorage("./my_data")
defer storage.Close()
ts := store.NewTripleStore(storage)
// Parse SPARQL query
query := `
SELECT ?person ?name
WHERE {
?person <http://xmlns.com/foaf/0.1/name> ?name .
}
`
p := parser.NewParser(query)
ast, err := p.Parse()
if err != nil {
log.Fatal(err)
}
// Optimize
count, _ := ts.Count()
stats := &optimizer.Statistics{TotalTriples: count}
opt := optimizer.NewOptimizer(stats)
optimized, err := opt.Optimize(ast)
if err != nil {
log.Fatal(err)
}
// Execute
exec := executor.NewExecutor(ts)
result, err := exec.Execute(optimized)
if err != nil {
log.Fatal(err)
}
// Process results
if selectResult, ok := result.(*executor.SelectResult); ok {
for _, binding := range selectResult.Bindings {
for varName, term := range binding.Vars {
fmt.Printf("%s = %s\n", varName, term)
}
}
}
}
Sample SPARQL Queries
Select All Triples
SELECT ?s ?p ?o
WHERE {
?s ?p ?o .
}
Find People and Their Names
SELECT ?person ?name
WHERE {
?person <http://xmlns.com/foaf/0.1/name> ?name .
}
Find People Alice Knows
SELECT ?friend ?friendName
WHERE {
<http://example.org/alice> <http://xmlns.com/foaf/0.1/knows> ?friend .
?friend <http://xmlns.com/foaf/0.1/name> ?friendName .
}
Ask if Bob Knows Anyone
ASK {
<http://example.org/bob> <http://xmlns.com/foaf/0.1/knows> ?someone .
}
Select with LIMIT and DISTINCT
SELECT DISTINCT ?person
WHERE {
?person <http://xmlns.com/foaf/0.1/name> ?name .
}
LIMIT 5
Working with Different RDF Terms
Named Nodes (IRIs)
node := rdf.NewNamedNode("http://example.org/resource")
Blank Nodes
blank := rdf.NewBlankNode("b1")
Literals
// Simple literal
lit1 := rdf.NewLiteral("Hello World")
// Language-tagged literal
lit2 := rdf.NewLiteralWithLanguage("Bonjour", "fr")
// Typed literal
lit3 := rdf.NewIntegerLiteral(42)
lit4 := rdf.NewDoubleLiteral(3.14)
lit5 := rdf.NewBooleanLiteral(true)
lit6 := rdf.NewDateTimeLiteral(time.Now())
Triples and Quads
// Triple (stored in default graph)
triple := rdf.NewTriple(subject, predicate, object)
ts.InsertTriple(triple)
// Quad (with explicit graph)
graph := rdf.NewNamedNode("http://example.org/graph1")
quad := rdf.NewQuad(subject, predicate, object, graph)
ts.InsertQuad(quad)
Performance Tips
- Batch Inserts: Use write transactions to insert multiple triples at once
- Index Selection: Bind as many terms as possible in patterns for efficient index usage
- Query Ordering: More selective patterns should appear first in WHERE clauses
- Memory: BadgerDB caches data in memory; adjust cache size based on dataset
Troubleshooting
Database Already Exists
If you get "database already exists" error:
rm -rf ./trigo_data
./trigo demo
Build Errors
Ensure you have Go 1.21+ installed:
go version
Update dependencies:
go mod tidy
Query Not Returning Expected Results
- Check that data was inserted correctly
- Verify IRI spelling (case-sensitive)
- Use
SELECT * WHERE { ?s ?p ?o }to see all triples - Check that the graph context matches (default vs named graphs)
Next Steps
- Read ARCHITECTURE for detailed design documentation
- Read README for feature overview and roadmap
- Explore the source code in
internal/andpkg/ - Try implementing support for additional SPARQL features
- Run the W3C SPARQL test suite (coming soon)
Using the Web UI
Trigo includes an interactive web interface powered by YASGUI:
# Start the server
./trigo serve
# Open your browser to:
# http://localhost:8080/
The web UI provides:
- Interactive SPARQL query editor with syntax highlighting
- Multiple result visualization formats (table, charts, raw)
- Query history and saved queries
- Real-time database statistics
Try this query in the web UI:
SELECT ?person ?name ?age
WHERE {
?person <http://xmlns.com/foaf/0.1/name> ?name .
?person <http://xmlns.com/foaf/0.1/age> ?age .
}
ORDER BY ?age
Getting Help
- Check existing documentation in this repository
- Review the source code (it's heavily commented)
- Compare with Oxigraph architecture: https://github.com/oxigraph/oxigraph/wiki/Architecture
- Refer to SPARQL 1.1 specification: https://www.w3.org/TR/sparql11-query/