Documentation
¶
Overview ¶
Package levelgraph provides a graph database built on top of LevelDB.
LevelGraph uses the Hexastore approach with six indexes for every triple, enabling fast pattern matching queries on subject, predicate, and object.
Basic usage:
db, err := levelgraph.Open("/path/to/db")
if err != nil {
log.Fatal(err)
}
defer db.Close()
// Insert a triple
err = db.Put(levelgraph.NewTripleFromStrings("alice", "knows", "bob"))
// Query triples
triples, err := db.Get(&levelgraph.Pattern{
Subject: []byte("alice"),
})
With features enabled:
db, err := levelgraph.Open("/path/to/db",
levelgraph.WithJournal(),
levelgraph.WithFacets(),
)
For WebAssembly builds, use OpenWithStore with NewMemStore:
store := levelgraph.NewMemStore() db := levelgraph.OpenWithStore(store)
Example ¶
Example demonstrates basic LevelGraph usage: opening a database, storing triples, and querying them.
package main
import (
"context"
"fmt"
"os"
"path/filepath"
"github.com/benbenbenbenbenben/levelgraph"
"github.com/benbenbenbenbenben/levelgraph/pkg/graph"
)
func main() {
// Create a temporary directory for the database
dir, err := os.MkdirTemp("", "levelgraph-example")
if err != nil {
fmt.Println("Error:", err)
return
}
defer os.RemoveAll(dir)
// Open the database
db, err := levelgraph.Open(filepath.Join(dir, "example.db"))
if err != nil {
fmt.Println("Error:", err)
return
}
defer db.Close()
// Insert triples
err = db.Put(context.Background(),
graph.NewTripleFromStrings("alice", "knows", "bob"),
graph.NewTripleFromStrings("bob", "knows", "charlie"),
)
if err != nil {
fmt.Println("Error:", err)
return
}
// Query by subject
triples, err := db.Get(context.Background(), &graph.Pattern{Subject: graph.ExactString("alice")})
if err != nil {
fmt.Println("Error:", err)
return
}
for _, t := range triples {
fmt.Printf("%s %s %s\n", t.Subject, t.Predicate, t.Object)
}
}
Output: alice knows bob
Example (Facets) ¶
Example_facets demonstrates attaching metadata to triples and their components.
package main
import (
"context"
"fmt"
"os"
"path/filepath"
"github.com/benbenbenbenbenben/levelgraph"
"github.com/benbenbenbenbenben/levelgraph/pkg/graph"
)
func main() {
dir, err := os.MkdirTemp("", "levelgraph-facets")
if err != nil {
fmt.Println("Error:", err)
return
}
defer os.RemoveAll(dir)
// Open with facets enabled
db, err := levelgraph.Open(filepath.Join(dir, "facets.db"), levelgraph.WithFacets())
if err != nil {
fmt.Println("Error:", err)
return
}
defer db.Close()
ctx := context.Background()
// Add a triple
triple := graph.NewTripleFromStrings("alice", "knows", "bob")
db.Put(ctx, triple)
// Add facet to the triple itself (relationship metadata)
err = db.SetTripleFacet(ctx, triple, []byte("since"), []byte("2020"))
if err != nil {
fmt.Println("Error:", err)
return
}
// Add facet to a subject (entity metadata)
err = db.SetFacet(ctx, levelgraph.FacetSubject, []byte("alice"), []byte("age"), []byte("30"))
if err != nil {
fmt.Println("Error:", err)
return
}
// Retrieve the facets
since, err := db.GetTripleFacet(ctx, triple, []byte("since"))
if err != nil {
fmt.Println("Error:", err)
return
}
age, err := db.GetFacet(ctx, levelgraph.FacetSubject, []byte("alice"), []byte("age"))
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Printf("Alice (age %s) knows Bob since %s\n", age, since)
}
Output: Alice (age 30) knows Bob since 2020
Example (HybridSearch) ¶
Example_hybridSearch demonstrates combining graph pattern matching with vector similarity search (hybrid search). This enables finding related graph entities based on semantic similarity.
package main
import (
"context"
"fmt"
"os"
"path/filepath"
"github.com/benbenbenbenbenben/levelgraph"
"github.com/benbenbenbenbenben/levelgraph/pkg/graph"
"github.com/benbenbenbenbenben/levelgraph/vector"
)
func main() {
dir, err := os.MkdirTemp("", "levelgraph-example-hybrid")
if err != nil {
fmt.Println("Error:", err)
return
}
defer os.RemoveAll(dir)
// Create a vector index (3 dimensions for this simple example)
vectorIndex := vector.NewFlatIndex(3)
db, err := levelgraph.Open(filepath.Join(dir, "hybrid.db"),
levelgraph.WithVectors(vectorIndex),
)
if err != nil {
fmt.Println("Error:", err)
return
}
defer db.Close()
ctx := context.Background()
// Build a graph of people and their favorite sports
db.Put(ctx,
graph.NewTripleFromStrings("alice", "likes", "tennis"),
graph.NewTripleFromStrings("alice", "likes", "badminton"),
graph.NewTripleFromStrings("bob", "likes", "football"),
graph.NewTripleFromStrings("charlie", "likes", "tennis"),
)
// Associate vectors with sports (simulated embeddings)
// Racket sports (tennis, badminton) are similar
db.SetObjectVector(ctx, []byte("tennis"), []float32{0.9, 0.1, 0.0})
db.SetObjectVector(ctx, []byte("badminton"), []float32{0.85, 0.15, 0.0})
db.SetObjectVector(ctx, []byte("football"), []float32{0.1, 0.9, 0.0})
// Hybrid search: Find people who like sports similar to tennis
// Combines graph pattern matching with vector similarity
results, err := db.Search(ctx, []*graph.Pattern{
{
Subject: graph.Binding("person"),
Predicate: graph.ExactString("likes"),
Object: graph.Binding("sport"),
},
}, &levelgraph.SearchOptions{
VectorFilter: &levelgraph.VectorFilter{
Variable: "sport",
Query: []float32{0.9, 0.1, 0.0}, // Query vector for "tennis-like"
TopK: 10,
MinScore: 0.8, // Only high similarity matches
IDType: vector.IDTypeObject,
},
})
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("People who like tennis-like sports:")
for _, sol := range results {
score := levelgraph.GetVectorScore(sol)
fmt.Printf(" %s likes %s (similarity: %.2f)\n",
sol["person"], sol["sport"], score)
}
}
Output: People who like tennis-like sports: alice likes tennis (similarity: 1.00) charlie likes tennis (similarity: 1.00) alice likes badminton (similarity: 1.00)
Example (Iterator) ¶
Example_iterator demonstrates using iterators for memory-efficient streaming of large result sets instead of loading all results into memory.
package main
import (
"context"
"fmt"
"os"
"path/filepath"
"github.com/benbenbenbenbenben/levelgraph"
"github.com/benbenbenbenbenben/levelgraph/pkg/graph"
)
func main() {
dir, err := os.MkdirTemp("", "levelgraph-example-iter")
if err != nil {
fmt.Println("Error:", err)
return
}
defer os.RemoveAll(dir)
db, err := levelgraph.Open(filepath.Join(dir, "iter.db"))
if err != nil {
fmt.Println("Error:", err)
return
}
defer db.Close()
ctx := context.Background()
// Add some triples
db.Put(ctx,
graph.NewTripleFromStrings("alice", "knows", "bob"),
graph.NewTripleFromStrings("alice", "knows", "charlie"),
graph.NewTripleFromStrings("alice", "knows", "david"),
)
// Use iterator instead of Get() for large result sets
// This streams results one at a time instead of loading all into memory
pattern := &graph.Pattern{
Subject: graph.ExactString("alice"),
Predicate: graph.ExactString("knows"),
Object: graph.Wildcard(),
}
iter, err := db.GetIterator(ctx, pattern)
if err != nil {
fmt.Println("Error:", err)
return
}
defer iter.Release()
fmt.Println("Alice knows:")
for iter.Next() {
triple, err := iter.Triple()
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Printf(" %s\n", triple.Object)
}
if err := iter.Error(); err != nil {
fmt.Println("Error:", err)
}
}
Output: Alice knows: bob charlie david
Example (Journal) ¶
Example_journal demonstrates journaling for audit trails.
package main
import (
"context"
"fmt"
"os"
"path/filepath"
"time"
"github.com/benbenbenbenbenben/levelgraph"
"github.com/benbenbenbenbenben/levelgraph/pkg/graph"
)
func main() {
dir, err := os.MkdirTemp("", "levelgraph-journal")
if err != nil {
fmt.Println("Error:", err)
return
}
defer os.RemoveAll(dir)
// Open with journaling enabled
db, err := levelgraph.Open(filepath.Join(dir, "journal.db"), levelgraph.WithJournal())
if err != nil {
fmt.Println("Error:", err)
return
}
defer db.Close()
ctx := context.Background()
// Perform some operations
db.Put(ctx, graph.NewTripleFromStrings("alice", "knows", "bob"))
db.Put(ctx, graph.NewTripleFromStrings("bob", "knows", "charlie"))
db.Del(ctx, graph.NewTripleFromStrings("alice", "knows", "bob"))
// Get all journal entries (use zero time to get all)
count, err := db.JournalCount(ctx, time.Time{})
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Printf("Journal has %d entries\n", count)
}
Output: Journal has 3 entries
Example (Search) ¶
Example_search demonstrates using Search with variables to find patterns.
package main
import (
"context"
"fmt"
"os"
"path/filepath"
"github.com/benbenbenbenbenben/levelgraph"
"github.com/benbenbenbenbenben/levelgraph/pkg/graph"
)
func main() {
dir, err := os.MkdirTemp("", "levelgraph-search")
if err != nil {
fmt.Println("Error:", err)
return
}
defer os.RemoveAll(dir)
db, err := levelgraph.Open(filepath.Join(dir, "search.db"))
if err != nil {
fmt.Println("Error:", err)
return
}
defer db.Close()
// Build a social graph
db.Put(context.Background(),
graph.NewTripleFromStrings("alice", "knows", "bob"),
graph.NewTripleFromStrings("bob", "knows", "charlie"),
graph.NewTripleFromStrings("alice", "knows", "dave"),
)
// Find everyone alice knows
results, err := db.Search(context.Background(), []*graph.Pattern{
{
Subject: graph.ExactString("alice"),
Predicate: graph.ExactString("knows"),
Object: graph.Binding("friend"),
},
}, nil)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Printf("Alice knows %d people\n", len(results))
}
Output: Alice knows 2 people
Example (SearchJoin) ¶
Example_searchJoin demonstrates multi-pattern joins to find complex relationships.
package main
import (
"context"
"fmt"
"os"
"path/filepath"
"github.com/benbenbenbenbenben/levelgraph"
"github.com/benbenbenbenbenben/levelgraph/pkg/graph"
)
func main() {
dir, err := os.MkdirTemp("", "levelgraph-join")
if err != nil {
fmt.Println("Error:", err)
return
}
defer os.RemoveAll(dir)
db, err := levelgraph.Open(filepath.Join(dir, "join.db"))
if err != nil {
fmt.Println("Error:", err)
return
}
defer db.Close()
ctx := context.Background()
// Build a graph of people and their interests
db.Put(ctx,
graph.NewTripleFromStrings("alice", "likes", "tennis"),
graph.NewTripleFromStrings("alice", "likes", "programming"),
graph.NewTripleFromStrings("bob", "likes", "tennis"),
graph.NewTripleFromStrings("bob", "likes", "chess"),
graph.NewTripleFromStrings("charlie", "likes", "programming"),
)
// Find what alice and bob have in common (join on shared interest)
results, err := db.Search(ctx, []*graph.Pattern{
{
Subject: graph.ExactString("alice"),
Predicate: graph.ExactString("likes"),
Object: graph.Binding("interest"),
},
{
Subject: graph.ExactString("bob"),
Predicate: graph.ExactString("likes"),
Object: graph.Binding("interest"), // Same variable binds shared value
},
}, nil)
if err != nil {
fmt.Println("Error:", err)
return
}
if len(results) > 0 {
fmt.Printf("Alice and Bob both like: %s\n", results[0]["interest"])
}
}
Output: Alice and Bob both like: tennis
Example (VectorSearch) ¶
Example_vectorSearch demonstrates semantic similarity search using vector embeddings. This enables "fuzzy" queries that find results based on meaning rather than exact matches.
package main
import (
"context"
"fmt"
"os"
"path/filepath"
"github.com/benbenbenbenbenben/levelgraph"
"github.com/benbenbenbenbenben/levelgraph/pkg/graph"
"github.com/benbenbenbenbenben/levelgraph/vector"
)
func main() {
dir, err := os.MkdirTemp("", "levelgraph-example-vector")
if err != nil {
fmt.Println("Error:", err)
return
}
defer os.RemoveAll(dir)
// Create a vector index (3 dimensions for this simple example)
vectorIndex := vector.NewFlatIndex(3)
db, err := levelgraph.Open(filepath.Join(dir, "vector.db"),
levelgraph.WithVectors(vectorIndex),
)
if err != nil {
fmt.Println("Error:", err)
return
}
defer db.Close()
ctx := context.Background()
// Add triples about sports
db.Put(ctx,
graph.NewTripleFromStrings("alice", "likes", "tennis"),
graph.NewTripleFromStrings("bob", "likes", "badminton"),
graph.NewTripleFromStrings("charlie", "likes", "football"),
)
// Associate vectors with sport objects (simulated embeddings)
// In practice, these would come from an embedding model
// Tennis and badminton are similar (both racket sports)
db.SetObjectVector(ctx, []byte("tennis"), []float32{0.9, 0.1, 0.0})
db.SetObjectVector(ctx, []byte("badminton"), []float32{0.85, 0.15, 0.0})
db.SetObjectVector(ctx, []byte("football"), []float32{0.1, 0.9, 0.0})
// Search for sports similar to tennis
results, err := db.SearchSimilarObjects(ctx, []float32{0.9, 0.1, 0.0}, 3)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("Sports similar to tennis:")
for _, match := range results {
fmt.Printf(" %s (score: %.2f)\n", match.Parts[0], match.Score)
}
}
Output: Sports similar to tennis: tennis (score: 1.00) badminton (score: 1.00) football (score: 0.61)
Index ¶
- Variables
- func GetVectorScore(sol graph.Solution) float32
- type AutoEmbedTarget
- type Batch
- type BatchOp
- type DB
- func (db *DB) Close() error
- func (db *DB) CloseGracefully(ctx context.Context) error
- func (db *DB) Del(ctx context.Context, triples ...*graph.Triple) error
- func (db *DB) DelAllTripleFacets(ctx context.Context, triple *graph.Triple) error
- func (db *DB) DelFacet(ctx context.Context, facetType FacetType, value []byte, key []byte) error
- func (db *DB) DelTripleFacet(ctx context.Context, triple *graph.Triple, key []byte) error
- func (db *DB) DeleteVector(ctx context.Context, id []byte) error
- func (db *DB) EmbedAndSetVector(ctx context.Context, id []byte, text string) error
- func (db *DB) GenerateBatch(triple *graph.Triple, action string) ([]BatchOp, error)
- func (db *DB) Get(ctx context.Context, pattern *graph.Pattern) ([]*graph.Triple, error)
- func (db *DB) GetFacet(ctx context.Context, facetType FacetType, value []byte, key []byte) ([]byte, error)
- func (db *DB) GetFacetIterator(ctx context.Context, facetType FacetType, value []byte) (*FacetIterator, error)
- func (db *DB) GetFacets(ctx context.Context, facetType FacetType, value []byte) (map[string][]byte, error)
- func (db *DB) GetIterator(ctx context.Context, pattern *graph.Pattern) (*TripleIterator, error)
- func (db *DB) GetJournalEntries(ctx context.Context, before time.Time) ([]*JournalEntry, error)
- func (db *DB) GetJournalIterator(ctx context.Context, before time.Time) (*JournalIterator, error)
- func (db *DB) GetTripleFacet(ctx context.Context, triple *graph.Triple, key []byte) ([]byte, error)
- func (db *DB) GetTripleFacetIterator(ctx context.Context, triple *graph.Triple) (*FacetIterator, error)
- func (db *DB) GetTripleFacets(ctx context.Context, triple *graph.Triple) (map[string][]byte, error)
- func (db *DB) GetVector(ctx context.Context, id []byte) ([]float32, error)
- func (db *DB) IsOpen() bool
- func (db *DB) JournalCount(ctx context.Context, before time.Time) (int, error)
- func (db *DB) LoadVectors(ctx context.Context) error
- func (db *DB) Nav(ctx context.Context, start any) *Navigator
- func (db *DB) PendingEmbeddings() int
- func (db *DB) Put(ctx context.Context, triples ...*graph.Triple) error
- func (db *DB) ReplayJournal(ctx context.Context, after time.Time, targetDB *DB) (int, error)
- func (db *DB) Search(ctx context.Context, patterns []*Pattern, opts *SearchOptions) ([]Solution, error)
- func (db *DB) SearchIterator(ctx context.Context, patterns []*graph.Pattern, opts *SearchOptions) (*SolutionIterator, error)
- func (db *DB) SearchSimilarObjects(ctx context.Context, query []float32, k int) ([]VectorMatch, error)
- func (db *DB) SearchSimilarSubjects(ctx context.Context, query []float32, k int) ([]VectorMatch, error)
- func (db *DB) SearchVectors(ctx context.Context, query []float32, k int) ([]VectorMatch, error)
- func (db *DB) SearchVectorsByText(ctx context.Context, text string, k int) ([]VectorMatch, error)
- func (db *DB) SetFacet(ctx context.Context, facetType FacetType, value []byte, key []byte, ...) error
- func (db *DB) SetObjectVector(ctx context.Context, object []byte, vec []float32) error
- func (db *DB) SetSubjectVector(ctx context.Context, subject []byte, vec []float32) error
- func (db *DB) SetTripleFacet(ctx context.Context, triple *graph.Triple, key []byte, value []byte) error
- func (db *DB) SetTripleVector(ctx context.Context, triple *graph.Triple, vec []float32) error
- func (db *DB) SetVector(ctx context.Context, id []byte, vec []float32) error
- func (db *DB) Trim(ctx context.Context, before time.Time) (int, error)
- func (db *DB) TrimAndExport(ctx context.Context, before time.Time, targetDB *DB) (int, error)
- func (db *DB) V(name string) *graph.Variable
- func (db *DB) VectorCount() int
- func (db *DB) VectorDimensions() int
- func (db *DB) VectorsEnabled() bool
- func (db *DB) WaitForEmbeddings(ctx context.Context) error
- type Embedder
- type FacetIterator
- type FacetType
- type Iterator
- type JoinAlgorithm
- type JournalEntry
- type JournalIterator
- type KVStore
- type Navigator
- func (nav *Navigator) ArchIn(predicate any) *Navigator
- func (nav *Navigator) ArchOut(predicate any) *Navigator
- func (nav *Navigator) As(name string) *Navigator
- func (nav *Navigator) Bind(value any) *Navigator
- func (nav *Navigator) Clone() *Navigator
- func (nav *Navigator) Count() (int, error)
- func (nav *Navigator) Exists() (bool, error)
- func (nav *Navigator) Filter(fn func(*graph.Triple) bool) *Navigator
- func (nav *Navigator) First() (graph.Solution, error)
- func (nav *Navigator) Go(vertex any) *Navigator
- func (nav *Navigator) Solutions() ([]graph.Solution, error)
- func (nav *Navigator) Triples(pattern *graph.Pattern) ([]*graph.Triple, error)
- func (nav *Navigator) Values() ([][]byte, error)
- func (nav *Navigator) Where(pattern *graph.Pattern) *Navigator
- type Option
- func WithAsyncAutoEmbed(bufferSize int) Option
- func WithAutoEmbed(embedder Embedder, targets AutoEmbedTarget) Option
- func WithBasicJoin() Option
- func WithDefaultLimit(limit int) Option
- func WithFacets() Option
- func WithJoinAlgorithm(algo JoinAlgorithm) Option
- func WithJournal() Option
- func WithLogger(l *slog.Logger) Option
- func WithSortJoin() Option
- func WithVectors(index vector.Index) Option
- type Options
- type Pattern
- type Range
- type ReadOptions
- type SearchOptions
- type Solution
- type SolutionIterator
- type Triple
- type TripleIterator
- type Variable
- type VectorFilter
- type VectorMatch
- type WriteOptions
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // NewTriple refers to graph.NewTriple NewTriple = graph.NewTriple // NewTripleFromStrings refers to graph.NewTripleFromStrings NewTripleFromStrings = graph.NewTripleFromStrings // NewPattern refers to graph.NewPattern NewPattern = graph.NewPattern // V refers to graph.V V = graph.V // Wildcard refers to graph.Wildcard Wildcard = graph.Wildcard // Exact refers to graph.Exact Exact = graph.Exact // ExactString refers to graph.ExactString ExactString = graph.ExactString // Binding refers to graph.Binding Binding = graph.Binding )
var ( // ErrClosed is returned when operating on a closed database. ErrClosed = errors.New("levelgraph: database is closed") // ErrInvalidTriple is returned when a triple is invalid. ErrInvalidTriple = errors.New("levelgraph: invalid triple - subject, predicate, and object are required") // ErrDimensionMismatch is returned when Embedder and VectorIndex have different dimensions. ErrDimensionMismatch = errors.New("levelgraph: embedder and vector index dimension mismatch") )
var ( // ErrVectorsDisabled is returned when vector operations are called without // a configured vector index. ErrVectorsDisabled = errors.New("levelgraph: vectors not enabled - use WithVectors option") // ErrEmbedderRequired is returned when auto-embedding requires an embedder // but none was configured. ErrEmbedderRequired = errors.New("levelgraph: embedder required for this operation") // ErrVectorDimensionMismatch is returned when loading a persisted vector // whose dimensions don't match the configured index dimensions. ErrVectorDimensionMismatch = errors.New("levelgraph: persisted vector dimensions do not match index dimensions") )
var ( // ErrFacetsDisabled is returned when facets operations are called but facets are not enabled. ErrFacetsDisabled = errors.New("levelgraph: facets are not enabled") )
var ErrNotFound = leveldb.ErrNotFound
ErrNotFound is returned when a key is not found.
Functions ¶
func GetVectorScore ¶
GetVectorScore extracts the vector similarity score from a solution. Returns 0 if no score was set (e.g., if VectorFilter wasn't used).
Types ¶
type AutoEmbedTarget ¶
type AutoEmbedTarget int
AutoEmbedTarget specifies which parts of triples should be automatically embedded.
const ( // AutoEmbedNone disables automatic embedding. AutoEmbedNone AutoEmbedTarget = 0 // AutoEmbedSubjects enables automatic embedding of subject values. AutoEmbedSubjects AutoEmbedTarget = 1 << iota // AutoEmbedPredicates enables automatic embedding of predicate values. AutoEmbedPredicates // AutoEmbedObjects enables automatic embedding of object values. AutoEmbedObjects // AutoEmbedAll enables automatic embedding of all triple components. AutoEmbedAll = AutoEmbedSubjects | AutoEmbedPredicates | AutoEmbedObjects )
type BatchOp ¶
type BatchOp struct {
Type string `json:"type"` // "put" or "del"
Key []byte `json:"key"`
Value []byte `json:"value"`
}
BatchOp represents a single batch operation.
type DB ¶
type DB struct {
// contains filtered or unexported fields
}
DB represents a LevelGraph database.
func Open ¶
Open opens or creates a LevelGraph database at the specified path. For WebAssembly builds, use OpenWithStore with NewMemStore instead.
func OpenWithDB ¶
OpenWithDB wraps an existing KVStore instance with LevelGraph. This is useful for using custom configurations or in-memory databases.
func (*DB) Close ¶
Close closes the database. If async embedding is enabled, Close waits for all pending embeddings to complete.
func (*DB) CloseGracefully ¶
CloseGracefully closes the database gracefully, waiting for the context to be cancelled or for a clean shutdown. This allows pending read operations and async embeddings to complete before closing.
func (*DB) DelAllTripleFacets ¶
DelAllTripleFacets deletes all facets from a triple.
func (*DB) DelTripleFacet ¶
DelTripleFacet deletes a facet from a triple.
func (*DB) DeleteVector ¶
DeleteVector removes a vector embedding by ID.
func (*DB) EmbedAndSetVector ¶
EmbedAndSetVector embeds text and stores the resulting vector. Requires an Embedder to be configured.
Example:
id := vector.MakeID(vector.IDTypeObject, []byte("tennis"))
db.EmbedAndSetVector(ctx, id, "tennis is a racket sport")
func (*DB) GenerateBatch ¶
GenerateBatch generates batch operations for a triple. This is useful for external batch management.
func (*DB) GetFacet ¶
func (db *DB) GetFacet(ctx context.Context, facetType FacetType, value []byte, key []byte) ([]byte, error)
GetFacet retrieves a facet from a component.
func (*DB) GetFacetIterator ¶
func (db *DB) GetFacetIterator(ctx context.Context, facetType FacetType, value []byte) (*FacetIterator, error)
GetFacetIterator returns an iterator over facets on a component.
func (*DB) GetFacets ¶
func (db *DB) GetFacets(ctx context.Context, facetType FacetType, value []byte) (map[string][]byte, error)
GetFacets retrieves all facets from a component. Returns a map of facet keys to values.
func (*DB) GetIterator ¶
GetIterator returns an iterator for triples matching the pattern.
func (*DB) GetJournalEntries ¶
GetJournalEntries returns all journal entries, optionally filtered by time.
func (*DB) GetJournalIterator ¶
GetJournalIterator returns an iterator over all journal entries. If before is non-zero, only entries before that time are returned.
func (*DB) GetTripleFacet ¶
GetTripleFacet retrieves a facet from a triple.
func (*DB) GetTripleFacetIterator ¶
func (db *DB) GetTripleFacetIterator(ctx context.Context, triple *graph.Triple) (*FacetIterator, error)
GetTripleFacetIterator returns an iterator over facets on a triple.
func (*DB) GetTripleFacets ¶
GetTripleFacets retrieves all facets from a triple.
func (*DB) JournalCount ¶
JournalCount returns the number of journal entries, optionally filtered by time.
func (*DB) LoadVectors ¶
LoadVectors loads all persisted vectors from KVStore into the index. This should be called after opening a database with vectors enabled to restore the index state.
func (*DB) Nav ¶
Nav creates a new Navigator starting from the given vertex. If start is nil, a new variable is created as the starting point.
func (*DB) PendingEmbeddings ¶
PendingEmbeddings returns the number of pending async embedding operations. Returns 0 if async embedding is not enabled.
func (*DB) Put ¶
Put inserts one or more triples into the database. If auto-embedding is enabled (via WithAutoEmbed), vectors will be automatically generated for the configured triple components.
func (*DB) ReplayJournal ¶
ReplayJournal replays all journal entries from a given time onwards. If after is zero, replays all entries from the beginning. This can be used to restore the database state or replay operations.
func (*DB) Search ¶
func (db *DB) Search(ctx context.Context, patterns []*Pattern, opts *SearchOptions) ([]Solution, error)
Search executes a search query with one or more patterns. It performs joins across patterns, binding variables as it matches triples.
func (*DB) SearchIterator ¶
func (db *DB) SearchIterator(ctx context.Context, patterns []*graph.Pattern, opts *SearchOptions) (*SolutionIterator, error)
SearchIterator returns an iterator for search results.
Note: VectorFilter is not supported with SearchIterator. If you need vector-filtered search results, use Search() instead which returns all results at once after applying vector filtering and sorting.
func (*DB) SearchSimilarObjects ¶
func (db *DB) SearchSimilarObjects(ctx context.Context, query []float32, k int) ([]VectorMatch, error)
SearchSimilarObjects searches for objects similar to a query vector. Only returns matches with IDTypeObject.
func (*DB) SearchSimilarSubjects ¶
func (db *DB) SearchSimilarSubjects(ctx context.Context, query []float32, k int) ([]VectorMatch, error)
SearchSimilarSubjects searches for subjects similar to a query vector. Only returns matches with IDTypeSubject.
func (*DB) SearchVectors ¶
SearchVectors finds the k most similar vectors to the query. Results are sorted by similarity (highest first).
Example:
// Find objects similar to "racket sports"
queryVec, _ := embedder.Embed("racket sports")
results, _ := db.SearchVectors(ctx, queryVec, 10)
for _, r := range results {
fmt.Printf("%s: %.3f\n", r.Parts[0], r.Score)
}
func (*DB) SearchVectorsByText ¶
SearchVectorsByText searches for similar vectors using text input. Requires an Embedder to be configured (via WithAutoEmbed).
Example:
results, _ := db.SearchVectorsByText(ctx, "racket sports", 10)
func (*DB) SetFacet ¶
func (db *DB) SetFacet(ctx context.Context, facetType FacetType, value []byte, key []byte, facetValue []byte) error
SetFacet sets a facet on a component (subject, predicate, or object value). The facet is a key-value pair attached to the component.
func (*DB) SetObjectVector ¶
SetObjectVector is a convenience method to set a vector for an object value.
func (*DB) SetSubjectVector ¶
SetSubjectVector is a convenience method to set a vector for a subject value.
func (*DB) SetTripleFacet ¶
func (db *DB) SetTripleFacet(ctx context.Context, triple *graph.Triple, key []byte, value []byte) error
SetTripleFacet sets a facet on an entire triple relationship.
func (*DB) SetTripleVector ¶
SetTripleVector is a convenience method to set a vector for a triple.
func (*DB) SetVector ¶
SetVector associates a vector embedding with an ID. The ID can be created using vector.MakeID to associate vectors with graph elements (subjects, objects, predicates, triples, or facets).
Example:
// Associate a vector with an object value
id := vector.MakeID(vector.IDTypeObject, []byte("tennis"))
db.SetVector(ctx, id, tennisEmbedding)
// Associate a vector with a custom ID
db.SetVector(ctx, []byte("doc:123"), docEmbedding)
func (*DB) TrimAndExport ¶
TrimAndExport removes journal entries before the given time and exports them to another database. This is useful for archiving old journal entries while keeping the main database lean.
func (*DB) V ¶
V creates a new Variable for use in queries. This is a convenience method that calls the package-level V function.
func (*DB) VectorCount ¶
VectorCount returns the number of vectors in the index.
func (*DB) VectorDimensions ¶
VectorDimensions returns the dimensionality of the vector index. Returns 0 if vectors are not enabled.
func (*DB) VectorsEnabled ¶
VectorsEnabled returns true if vector operations are available.
func (*DB) WaitForEmbeddings ¶
WaitForEmbeddings blocks until all pending async embedding operations are complete. Returns immediately if async embedding is not enabled. Returns an error if the context is cancelled before all embeddings complete.
Use this method after a batch of Put operations to ensure all vectors are indexed before performing searches:
// Add triples with async embedding
for _, triple := range triples {
db.Put(ctx, triple)
}
// Wait for all embeddings to complete before searching
if err := db.WaitForEmbeddings(ctx); err != nil {
log.Printf("embedding error: %v", err)
}
// Now search will include all vectors
results, _ := db.SearchVectorsByText(ctx, "query", 10)
type Embedder ¶
type Embedder interface {
// Embed converts a single text string to a vector embedding.
Embed(text string) ([]float32, error)
// EmbedBatch converts multiple texts to vector embeddings.
// Implementations may optimize batch processing.
EmbedBatch(texts []string) ([][]float32, error)
// Dimensions returns the dimensionality of the embeddings.
Dimensions() int
}
Embedder is an interface for text embedding models. Implementations convert text to vector representations for semantic search.
type FacetIterator ¶
type FacetIterator struct {
// contains filtered or unexported fields
}
FacetIterator iterates over facets on a component or triple.
func (*FacetIterator) Error ¶
func (fi *FacetIterator) Error() error
Error returns any error from the iterator.
func (*FacetIterator) Key ¶
func (fi *FacetIterator) Key() []byte
Key returns the current facet key.
func (*FacetIterator) Value ¶
func (fi *FacetIterator) Value() []byte
Value returns the current facet value.
type FacetType ¶
type FacetType string
FacetType represents the type of component a facet is attached to.
type JoinAlgorithm ¶
type JoinAlgorithm string
JoinAlgorithm represents the algorithm used for joining patterns in searches.
const ( // JoinAlgorithmBasic uses nested loop join. JoinAlgorithmBasic JoinAlgorithm = "basic" // JoinAlgorithmSort uses sort-merge join for better performance. JoinAlgorithmSort JoinAlgorithm = "sort" )
type JournalEntry ¶
type JournalEntry struct {
// Operation is either "put" or "del"
Operation string `json:"op"`
// Triple is the triple that was written or deleted
Triple *Triple `json:"triple"`
// Timestamp is when the operation occurred
Timestamp time.Time `json:"ts"`
}
JournalEntry represents a recorded operation in the journal.
func (*JournalEntry) MarshalBinary ¶
func (e *JournalEntry) MarshalBinary() ([]byte, error)
MarshalBinary implements encoding.BinaryMarshaler for JournalEntry. Format: [OpByte][Timestamp (8 bytes)][Triple Binary]
func (*JournalEntry) UnmarshalBinary ¶
func (e *JournalEntry) UnmarshalBinary(data []byte) error
UnmarshalBinary implements encoding.BinaryUnmarshaler for JournalEntry.
type JournalIterator ¶
type JournalIterator struct {
// contains filtered or unexported fields
}
JournalIterator iterates over journal entries.
func (*JournalIterator) Entry ¶
func (ji *JournalIterator) Entry() (*JournalEntry, error)
Entry returns the current journal entry.
func (*JournalIterator) Error ¶
func (ji *JournalIterator) Error() error
Error returns any error from the iterator.
func (*JournalIterator) Next ¶
func (ji *JournalIterator) Next() bool
Next advances to the next journal entry.
type KVStore ¶
type KVStore interface {
Get(key []byte, ro *ReadOptions) (value []byte, err error)
Put(key, value []byte, wo *WriteOptions) error
Delete(key []byte, wo *WriteOptions) error
Write(batch *Batch, wo *WriteOptions) error
NewIterator(slice *Range, ro *ReadOptions) Iterator
Close() error
}
KVStore defines the interface for the underlying key-value store.
type Navigator ¶
type Navigator struct {
// contains filtered or unexported fields
}
Navigator provides a fluent API for traversing the graph. It allows building queries by following edges in and out.
Example usage:
nav := db.Nav(ctx, []byte("alice"))
solutions, err := nav.ArchOut("knows").ArchOut("likes").Solutions()
This finds all things liked by people that alice knows.
func (*Navigator) ArchIn ¶
ArchIn follows an incoming edge with the given predicate. The current position becomes the object, and navigates to the subject.
func (*Navigator) ArchOut ¶
ArchOut follows an outgoing edge with the given predicate. The current position becomes the subject, and navigates to the object.
func (*Navigator) As ¶
As names the current position with the given variable name. This allows referencing the position later in the query.
func (*Navigator) Bind ¶
Bind binds the current position's variable to a concrete value. This is used to constrain the search.
func (*Navigator) Clone ¶
Clone creates a copy of this navigator that can be modified independently.
func (*Navigator) Filter ¶
Filter adds a filter function to the last condition. The filter is applied to each matching triple.
func (*Navigator) Go ¶
Go moves the navigator to a new vertex. If vertex is nil, a new variable is created. vertex can be []byte, string (converted to []byte), or *graph.Variable.
func (*Navigator) Solutions ¶
Solutions executes the navigation query and returns all solutions. Each solution is a map of variable names to their bound values.
func (*Navigator) Triples ¶
Triples executes the query and materializes results into triples. The pattern specifies how to construct the result triples from solutions.
type Option ¶
type Option func(*Options)
Option is a function that configures Options.
func WithAsyncAutoEmbed ¶
WithAsyncAutoEmbed enables non-blocking auto-embedding with the specified buffer size. When enabled, embedding is performed in a background goroutine instead of blocking the Put() call. This is useful when using real embedding models that have latency.
Use WaitForEmbeddings() to block until all pending embeddings are complete. The buffer size determines how many embedding requests can be queued before Put() blocks waiting for the queue to drain.
Example:
db, err := levelgraph.Open("/path/to/db",
levelgraph.WithVectors(vector.NewHNSWIndex(192)),
levelgraph.WithAutoEmbed(myEmbedder, levelgraph.AutoEmbedObjects),
levelgraph.WithAsyncAutoEmbed(100),
)
// ... add triples ...
db.WaitForEmbeddings(ctx) // Wait for all embeddings to complete
func WithAutoEmbed ¶
func WithAutoEmbed(embedder Embedder, targets AutoEmbedTarget) Option
WithAutoEmbed enables automatic vector embedding when triples are added. Requires both an Embedder and a VectorIndex to be configured.
Example:
db, err := levelgraph.Open("/path/to/db",
levelgraph.WithVectors(vector.NewHNSWIndex(192)),
levelgraph.WithAutoEmbed(myEmbedder, levelgraph.AutoEmbedObjects),
)
func WithBasicJoin ¶
func WithBasicJoin() Option
WithBasicJoin is a convenience option for using the basic (nested loop) join algorithm.
func WithDefaultLimit ¶
WithDefaultLimit sets the default maximum result limit for Get/Search operations. When set to a positive value, this limit is applied if no explicit limit is provided in the query. This is useful for preventing unbounded result sets that could exhaust memory or cause performance issues. 0 means no default limit (the default for backward compatibility).
func WithFacets ¶
func WithFacets() Option
WithFacets enables the facets/properties feature. When enabled, additional properties can be attached to triple components or entire triples.
func WithJoinAlgorithm ¶
func WithJoinAlgorithm(algo JoinAlgorithm) Option
WithJoinAlgorithm sets the join algorithm for searches.
func WithJournal ¶
func WithJournal() Option
WithJournal enables the journalling feature. When enabled, all Put and Del operations are recorded in a journal that can be trimmed or exported.
func WithLogger ¶
WithLogger sets an optional structured logger for debug output. Pass nil to disable logging (the default).
func WithSortJoin ¶
func WithSortJoin() Option
WithSortJoin is a convenience option for using the sort-merge join algorithm.
func WithVectors ¶
WithVectors enables vector similarity search with the provided index. Use vector.NewFlatIndex for exact search or vector.NewHNSWIndex for approximate nearest neighbor search.
Example:
db, err := levelgraph.Open("/path/to/db",
levelgraph.WithVectors(vector.NewHNSWIndex(192)),
)
type Options ¶
type Options struct {
// JournalEnabled enables the journalling feature for write operations.
JournalEnabled bool
// FacetsEnabled enables the facets/properties feature.
FacetsEnabled bool
// VectorIndex is an optional vector similarity index for semantic search.
// When set, vector operations (SetVector, GetVector, SearchVectors) are enabled.
VectorIndex vector.Index
// JoinAlgorithm specifies which join algorithm to use for searches.
// Defaults to JoinAlgorithmSort.
JoinAlgorithm JoinAlgorithm
// Logger is an optional structured logger for debug output.
// When nil, no logging is performed.
Logger *slog.Logger
// DefaultLimit is the default maximum number of results for Get/Search operations.
// When set to a positive value, this limit is applied if no explicit limit is provided.
// 0 means no default limit (unbounded, the default for backward compatibility).
DefaultLimit int
// Embedder is an optional text embedder for automatic vector generation.
// When set along with AutoEmbedTargets, vectors are automatically created
// when triples are added.
Embedder Embedder
// AutoEmbedTargets specifies which triple components should be auto-embedded.
// Only used when Embedder is set.
AutoEmbedTargets AutoEmbedTarget
// AsyncAutoEmbed enables non-blocking auto-embedding.
// When enabled, embedding is performed in a background goroutine instead of
// blocking the Put() call. Use WaitForEmbeddings() to wait for pending work.
AsyncAutoEmbed bool
// AsyncEmbedBufferSize sets the buffer size for the async embed queue.
// Defaults to 100 if not set. Only used when AsyncAutoEmbed is true.
AsyncEmbedBufferSize int
}
Options configures a LevelGraph database.
type SearchOptions ¶
type SearchOptions struct {
// Limit restricts the number of results (0 means no limit)
Limit int
// Offset skips the first N results
Offset int
// Filter is an optional function to filter solutions
Filter func(Solution) bool
// AsyncFilter is an optional async filter (returns solution or nil)
AsyncFilter func(Solution, func(Solution, error))
// Materialized is a pattern to transform solutions into triples
Materialized *Pattern
// InitialSolution is an optional starting solution with pre-bound variables
InitialSolution Solution
// VectorFilter enables hybrid search by filtering/ranking solutions based
// on vector similarity of a bound variable.
VectorFilter *VectorFilter
}
SearchOptions configures search behavior.
type SolutionIterator ¶
type SolutionIterator struct {
// contains filtered or unexported fields
}
SolutionIterator iterates over search solutions.
func (*SolutionIterator) Close ¶
func (si *SolutionIterator) Close()
Close releases iterator resources.
func (*SolutionIterator) Error ¶
func (si *SolutionIterator) Error() error
Error returns any error encountered during iteration.
func (*SolutionIterator) Next ¶
func (si *SolutionIterator) Next() bool
Next advances to the next solution.
func (*SolutionIterator) Solution ¶
func (si *SolutionIterator) Solution() graph.Solution
Solution returns the current solution.
type TripleIterator ¶
type TripleIterator struct {
// contains filtered or unexported fields
}
TripleIterator iterates over triples from a query.
func (*TripleIterator) Error ¶
func (ti *TripleIterator) Error() error
Error returns any error from the iterator.
func (*TripleIterator) Next ¶
func (ti *TripleIterator) Next() bool
Next advances the iterator to the next triple.
func (*TripleIterator) Release ¶
func (ti *TripleIterator) Release()
Release releases the iterator resources.
type Variable ¶
Variable is an alias for graph.Variable representing a variable binding in patterns.
type VectorFilter ¶
type VectorFilter struct {
// Variable is the name of the variable to filter by vector similarity.
// The variable's value will be used to look up vectors in the index.
Variable string
// Query is the query vector to compare against.
Query []float32
// QueryText is an optional text query that will be embedded using the
// configured Embedder. Either Query or QueryText should be set, not both.
QueryText string
// TopK limits results to the K most similar values for the variable.
// If 0, all solutions are kept but scored/sorted.
TopK int
// MinScore filters out solutions where the similarity score is below this threshold.
// Score is in range [0, 1] for cosine similarity (after normalization).
MinScore float32
// IDType specifies the type of vector ID to look up (e.g., IDTypeObject).
// If empty, defaults to IDTypeObject.
IDType vector.IDType
}
VectorFilter specifies how to filter search results using vector similarity. It allows hybrid queries that combine graph traversal with semantic search.
How Hybrid Search Works ¶
Hybrid search executes in two phases:
- Graph phase: Executes patterns to find matching solutions (like regular Search)
- Vector phase: Scores and filters solutions based on vector similarity
The Variable field specifies which solution variable to look up in the vector index. For example, if your pattern binds ?topic, and you have vectors stored for topics, set Variable: "topic" to score solutions by topic similarity.
Score Interpretation ¶
Scores are normalized to [0, 1] range:
- 1.0: Identical vectors (perfect match)
- 0.7-0.9: Highly similar (typically good matches)
- 0.5-0.7: Moderately similar
- 0.0-0.5: Dissimilar
Use MinScore to filter out low-quality matches.
Example: Find People Who Like Similar Topics ¶
solutions, err := db.Search(ctx, []*Pattern{
{Subject: V("person"), Predicate: []byte("likes"), Object: V("topic")},
}, &SearchOptions{
VectorFilter: &VectorFilter{
Variable: "topic",
QueryText: "machine learning", // Requires configured Embedder
TopK: 10, // Limit to top 10 similar topics
MinScore: 0.7, // Filter out scores below 0.7
IDType: vector.IDTypeObject, // Look up topic as object vector
},
})
Example: Vector Search with Precomputed Query ¶
queryVec := embedder.Embed("artificial intelligence")
solutions, err := db.Search(ctx, patterns, &SearchOptions{
VectorFilter: &VectorFilter{
Variable: "topic",
Query: queryVec, // Use precomputed vector
TopK: 10,
},
})
type VectorMatch ¶
type VectorMatch struct {
// ID is the vector identifier (e.g., "object:tennis").
ID []byte
// Score is the similarity score (higher is more similar).
Score float32
// Distance is the distance metric (lower is more similar).
Distance float32
// IDType indicates what kind of graph element this ID refers to.
IDType vector.IDType
// Parts contains the parsed ID components.
Parts [][]byte
}
VectorMatch represents a vector search result with graph context.
type WriteOptions ¶
type WriteOptions = opt.WriteOptions
WriteOptions is an alias for opt.WriteOptions.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
levelgraph
command
|
|
|
wasm
command
|
|
|
example
|
|
|
nolij
command
Package main implements nolij, a knowledge graph CLI built on LevelGraph.
|
Package main implements nolij, a knowledge graph CLI built on LevelGraph. |
|
simple
command
Package main demonstrates basic LevelGraph features.
|
Package main demonstrates basic LevelGraph features. |
|
Package memstore provides an in-memory key-value store implementation that is compatible with the levelgraph KVStore interface.
|
Package memstore provides an in-memory key-value store implementation that is compatible with the levelgraph KVStore interface. |
|
pkg
|
|
|
graph
Package graph provides core types for graph database operations including triples, patterns, variables, and solutions for pattern matching queries.
|
Package graph provides core types for graph database operations including triples, patterns, variables, and solutions for pattern matching queries. |
|
index
Package index provides hexastore index key generation and management for efficient triple pattern matching using six different key orderings.
|
Package index provides hexastore index key generation and management for efficient triple pattern matching using six different key orderings. |
|
playground
|
|
|
wasm
command
|
|
|
Package vector provides vector similarity search capabilities for LevelGraph.
|
Package vector provides vector similarity search capabilities for LevelGraph. |
|
luxical
Package luxical provides an adapter for the Luxical text embedding model to work with LevelGraph's vector search capabilities.
|
Package luxical provides an adapter for the Luxical text embedding model to work with LevelGraph's vector search capabilities. |
