Trigo Documentation

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:

  1. Create a BadgerDB database in ./trigo_data
  2. Insert sample triples about Alice, Bob, and Carol
  3. Execute a SPARQL SELECT query
  4. 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

  1. Batch Inserts: Use write transactions to insert multiple triples at once
  2. Index Selection: Bind as many terms as possible in patterns for efficient index usage
  3. Query Ordering: More selective patterns should appear first in WHERE clauses
  4. 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

Next Steps

  1. Read ARCHITECTURE for detailed design documentation
  2. Read README for feature overview and roadmap
  3. Explore the source code in internal/ and pkg/
  4. Try implementing support for additional SPARQL features
  5. 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:

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