Documentation
¶
Overview ¶
Package core provides the fundamental data structures and logic for the KektorDB engine.
This file defines the main DB struct, which orchestrates all data storage, including the KV store, vector indexes, and secondary indexes for metadata (inverted, B-Tree, and text). It also implements core functionalities like snapshotting, filtering, full-text search, and index management.
Package core provides the fundamental data structures and logic for the KektorDB engine.
File: pkg/core/graph.go
Index ¶
- Constants
- func GetShardIndex(id string) uint32
- type BTreeItem
- type BruteForceIndex
- func (idx *BruteForceIndex) Add(id string, vector []float32) (uint32, error)
- func (idx *BruteForceIndex) Close() error
- func (idx *BruteForceIndex) Delete(id string)
- func (idx *BruteForceIndex) GetArenaDir() string
- func (idx *BruteForceIndex) SearchWithScores(query []float32, k int, allowList *roaring.Bitmap, efSearch int) []types.SearchResult
- type DB
- func (db *DB) AddEdge(sourceID, targetID, relationType string, weight float32, props []byte, ...)
- func (s *DB) AddMetadata(indexName string, nodeID uint32, metadata map[string]any) error
- func (s *DB) AddMetadataUnlocked(indexName string, nodeID uint32, metadata map[string]any) error
- func (s *DB) Close() error
- func (s *DB) Compress(indexName string, newPrecision distance.PrecisionType) error
- func (s *DB) CreateVectorIndex(name string, metric distance.DistanceMetric, m, efConstruction int, ...) error
- func (s *DB) DeleteMetadata(indexName string, nodeID uint32) error
- func (s *DB) DeleteVectorIndex(name string) error
- func (s *DB) FindIDsByFilter(indexName string, filter string) (*roaring.Bitmap, error)
- func (db *DB) FindIDsByTextSearch(indexName, fieldName, queryText string) ([]types.SearchResult, error)
- func (db *DB) GetAllRelations(nodeID string, direction string) map[string][]string
- func (s *DB) GetAllValidNodeIDs(indexName string) (*roaring.Bitmap, error)
- func (db *DB) GetGraphShard(id string) *GraphShard
- func (db *DB) GetInEdges(targetID, relationType string, atTime int64) ([]string, bool)
- func (s *DB) GetKVStore() *KVStore
- func (s *DB) GetMetadataForNode(indexName string, nodeID uint32) map[string]any
- func (s *DB) GetMetadataForNodeUnlocked(indexName string, nodeID uint32) map[string]any
- func (db *DB) GetOutEdges(sourceID, relationType string, atTime int64) ([]GraphEdge, bool)
- func (s *DB) GetSingleVectorIndexInfoAPI(name string) (IndexInfo, error)
- func (s *DB) GetTextIndexMap(indexName string) (map[string]map[string]PostingList, bool)
- func (s *DB) GetVector(indexName, vectorID string) (VectorData, error)
- func (s *DB) GetVectorIndex(name string) (VectorIndex, bool)
- func (s *DB) GetVectorIndexInfo() ([]IndexInfo, error)
- func (s *DB) GetVectorIndexInfoAPI() ([]IndexInfo, error)
- func (s *DB) GetVectorIndexInfoUnlocked() ([]IndexInfo, error)
- func (s *DB) GetVectorIndexUnlocked(name string) (VectorIndex, bool)
- func (s *DB) GetVectors(indexName string, vectorIDs []string) ([]VectorData, error)
- func (s *DB) IterateGraphEdges(...)
- func (s *DB) IterateKV(callback func(pair KVPair))
- func (s *DB) IterateKVUnlocked(callback func(pair KVPair))
- func (s *DB) IterateVectorIndexes(callback func(indexName string, index *hnsw.Index, data VectorData))
- func (s *DB) IterateVectorIndexesUnlocked(callback func(indexName string, index *hnsw.Index, data VectorData))
- func (s *DB) LoadFromSnapshot(reader io.Reader, basePath string) error
- func (s *DB) Lock()
- func (db *DB) LockTwoShards(id1, id2 string) (*GraphShard, *GraphShard)
- func (s *DB) RLock()
- func (s *DB) RUnlock()
- func (db *DB) RemoveEdge(sourceID, targetID, relationType string, hardDelete bool, timestamp int64)
- func (s *DB) RunMaintenance() bool
- func (s *DB) Snapshot(writer io.Writer) error
- func (s *DB) Unlock()
- func (db *DB) UnlockTwoShards(id1, id2 string)
- func (db *DB) VacuumGraph(cutoffTime int64) int
- type GraphEdge
- type GraphNode
- type GraphShard
- type GraphSnapshot
- type IndexConfig
- type IndexInfo
- type IndexSnapshot
- type InvertedIndex
- type KVPair
- type KVStore
- type NodeSnapshot
- type PostingEntry
- type PostingList
- type ReverseEdge
- type Snapshot
- type TextIndexStats
- type VectorData
- type VectorIndex
Constants ¶
const NumGraphShards = 128
NumGraphShards defines the number of independent partitions for the graph. 128 is a good power-of-two number that provides high concurrency with low memory footprint.
Variables ¶
This section is empty.
Functions ¶
func GetShardIndex ¶ added in v0.5.1
GetShardIndex calculates a deterministic shard ID for a given string key. It uses FNV-1a which is very fast and has excellent distribution properties.
Types ¶
type BTreeItem ¶
BTreeItem is a struct used by the B-Tree to associate a numerical metadata value with a node ID.
type BruteForceIndex ¶
type BruteForceIndex struct {
// contains filtered or unexported fields
}
BruteForceIndex is a simple implementation of VectorIndex that stores all vectors and calculates the distance to every one of them during a search. It is not optimized for performance but is useful for testing and small datasets.
func NewBruteForceIndex ¶
func NewBruteForceIndex() *BruteForceIndex
NewBruteForceIndex creates and returns a new, empty BruteForceIndex.
func (*BruteForceIndex) Add ¶
func (idx *BruteForceIndex) Add(id string, vector []float32) (uint32, error)
Add adds a vector to the index
func (*BruteForceIndex) Close ¶ added in v0.5.1
func (idx *BruteForceIndex) Close() error
Close for BruteForceIndex is a no-op since it only uses GC RAM.
func (*BruteForceIndex) Delete ¶
func (idx *BruteForceIndex) Delete(id string)
Delete removes a vector by its ID.
func (*BruteForceIndex) GetArenaDir ¶ added in v0.5.1
func (idx *BruteForceIndex) GetArenaDir() string
GetArenaDir for BruteForceIndex returns empty string since it doesn't use mmap.
func (*BruteForceIndex) SearchWithScores ¶
func (idx *BruteForceIndex) SearchWithScores(query []float32, k int, allowList *roaring.Bitmap, efSearch int) []types.SearchResult
SearchWithScores finds the K nearest vectors to the query vector.
type DB ¶
type DB struct {
// contains filtered or unexported fields
}
DB is the main container for all KektorDB data types. It orchestrates the KV store, vector indexes, and all secondary indexes for metadata.
func (*DB) AddEdge ¶ added in v0.5.1
func (db *DB) AddEdge(sourceID, targetID, relationType string, weight float32, props []byte, timestamp int64)
AddEdge creates or updates a directed edge from sourceID to targetID. It automatically updates the reverse index (InEdges) on the target node.
func (*DB) AddMetadata ¶
AddMetadata associates metadata with a node ID and updates the secondary indexes.
func (*DB) AddMetadataUnlocked ¶
AddMetadataUnlocked adds metadata without acquiring a lock. The caller must ensure thread safety.
func (*DB) Close ¶ added in v0.5.1
Close gracefully shuts down all vector indexes, releasing OS resources like mmap.
func (*DB) Compress ¶
func (s *DB) Compress(indexName string, newPrecision distance.PrecisionType) error
Compress converts an existing index to a new precision
func (*DB) CreateVectorIndex ¶
func (s *DB) CreateVectorIndex(name string, metric distance.DistanceMetric, m, efConstruction int, precision distance.PrecisionType, textLang string, arenaDir string) error
CreateVectorIndex creates a new vector index with the specified configuration.
func (*DB) DeleteMetadata ¶ added in v0.5.1
DeleteMetadata removes all metadata and index entries associated with a node. This should be called when a node is deleted to prevent memory leaks.
func (*DB) DeleteVectorIndex ¶
DeleteVectorIndex removes an entire vector index and all of its associated data.
func (*DB) FindIDsByFilter ¶
FindIDsByFilter acts as a query planner for metadata filters. It supports AND and OR logic. OR has lower precedence (the filter is first split by OR, and each resulting block is evaluated as an AND of its sub-filters). FindIDsByFilter acts as a query planner for metadata filters.
Grammar: `expr := term (OR term)*`, `term := atom (AND atom)*`, `atom := '(' expr ')' | comparison`. AND binds tighter than OR (standard).
Parentheses are supported. They matter because callers routinely append a global condition to a user-supplied expression, e.g. building `layer='a' OR layer='b'` and then appending ` AND _is_historical!='true'`. Without parentheses the AND binds only to the last OR branch (standard precedence), silently returning hidden records from the other branches.
func (*DB) FindIDsByTextSearch ¶
func (db *DB) FindIDsByTextSearch(indexName, fieldName, queryText string) ([]types.SearchResult, error)
FindIDsByTextSearch performs a search on the text index for a given query. It uses the BM25 ranking algorithm to score and sort documents based on relevance.
func (*DB) GetAllRelations ¶ added in v0.5.1
GetAllRelations returns a map of all active relationships for a node. direction can be "out" or "in". Complexity: O(1) shard lock + slice iteration. Massively faster than prefix scan.
func (*DB) GetAllValidNodeIDs ¶ added in v0.6.3
GetAllValidNodeIDs returns a bitmap of every live (non-deleted) node in an index. Caller-visible counterpart of getAllValidNodeIDsLocked; used by the memory-visibility guard to build a starting set when no caller filter is present.
func (*DB) GetGraphShard ¶ added in v0.5.1
func (db *DB) GetGraphShard(id string) *GraphShard
GetGraphShard returns a specific shard for read-only or single-node operations.
func (*DB) GetInEdges ¶ added in v0.5.1
GetInEdges returns all incoming source IDs for a target node. Resolves the Reverse Index instantly.
func (*DB) GetKVStore ¶
GetKVStore returns the underlying key-value store
func (*DB) GetMetadataForNode ¶ added in v0.5.1
GetMetadataForNode exposes the internal metadata lookup.
func (*DB) GetMetadataForNodeUnlocked ¶ added in v0.4.7
GetMetadataForNodeUnlocked exposes the internal metadata lookup. Warning: Caller must hold RLock on DB or ensure safety.
func (*DB) GetOutEdges ¶ added in v0.5.1
GetOutEdges returns all outgoing edges for a node of a specific type. It applies Time Travel filtering if atTime > 0. Returns a COPY of the active edges to prevent race conditions during iteration.
func (*DB) GetSingleVectorIndexInfoAPI ¶
GetSingleVectorIndexInfoAPI returns information for a single index by name.
func (*DB) GetTextIndexMap ¶ added in v0.4.0
GetTextIndexMap returns a copy of the available fields in the text index for a given index name. It returns map[fieldName]map[token]PostingList (though usually we just need keys). This is used for auto-detecting which field contains text.
func (*DB) GetVector ¶
func (s *DB) GetVector(indexName, vectorID string) (VectorData, error)
GetVector retrieves the complete data for a single vector given its external ID.
func (*DB) GetVectorIndex ¶
func (s *DB) GetVectorIndex(name string) (VectorIndex, bool)
GetVectorIndex retrieves a vector index by its name.
func (*DB) GetVectorIndexInfo ¶
GetVectorIndexInfo returns a slice containing the configuration and status of all existing vector indexes.
func (*DB) GetVectorIndexInfoAPI ¶
GetVectorIndexInfoAPI returns configuration and status information for all vector indexes, suitable for an API response.
func (*DB) GetVectorIndexInfoUnlocked ¶
GetVectorIndexInfoUnlocked returns index information without acquiring a lock. The caller is responsible for ensuring thread safety.
func (*DB) GetVectorIndexUnlocked ¶ added in v0.4.7
func (s *DB) GetVectorIndexUnlocked(name string) (VectorIndex, bool)
GetVectorIndexUnlocked retrieves a vector index without acquiring a lock. The caller is responsible for ensuring thread safety.
func (*DB) GetVectors ¶
func (s *DB) GetVectors(indexName string, vectorIDs []string) ([]VectorData, error)
GetVectors retrieves the complete data for a slice of vector IDs in parallel. If an ID is not found, it is simply omitted from the returned slice.
func (*DB) IterateGraphEdges ¶ added in v0.5.1
func (s *DB) IterateGraphEdges(cb func(source, target, rel string, weight float32, props []byte, cTime, dTime int64))
IterateGraphEdges iterates over all active and soft-deleted edges safely.
func (*DB) IterateKV ¶
IterateKV iterates over all key-value pairs in the store, passing each to a callback function. The iteration is performed under a read lock. CONTRACT: the callback must NOT write to the KVStore (the RLock is held for the whole iteration — a write would deadlock) and must NOT retain or mutate the value slice (it is a defensive copy).
func (*DB) IterateKVUnlocked ¶
iterateKVUnlocked performs the iteration without acquiring locks. The caller is responsible for ensuring thread safety.
func (*DB) IterateVectorIndexes ¶
func (s *DB) IterateVectorIndexes(callback func(indexName string, index *hnsw.Index, data VectorData))
IterateVectorIndexes iterates over all vector indexes and their contents. The caller is responsible for locking.
func (*DB) IterateVectorIndexesUnlocked ¶
func (s *DB) IterateVectorIndexesUnlocked(callback func(indexName string, index *hnsw.Index, data VectorData))
iterateVectorIndexesUnlocked performs the iteration without acquiring locks. The caller is responsible for ensuring thread safety.
func (*DB) LoadFromSnapshot ¶
LoadFromSnapshot deserializes a gob snapshot from an io.Reader and restores the store's state. It clears the current store state before loading.
func (*DB) LockTwoShards ¶ added in v0.5.1
func (db *DB) LockTwoShards(id1, id2 string) (*GraphShard, *GraphShard)
LockTwoShards safely acquires exclusive write locks for two potentially different shards. It implements a Strict Lock Ordering (always lock the lower shard index first) to mathematically guarantee that Deadlocks cannot happen during cross-shard operations.
func (*DB) RemoveEdge ¶ added in v0.5.1
RemoveEdge removes a directed edge. If hardDelete is true, it physically filters the slice (O(N)). If hardDelete is false, it uses Soft Delete (O(1) in-place update) for Time Travel support.
func (*DB) RunMaintenance ¶ added in v0.3.0
RunMaintenance triggers background tasks (Vacuum/Refine) on all vector indexes. It should be called periodically by the Engine.
func (*DB) Snapshot ¶
Snapshot serializes the current state of the store in gob format to an io.Writer. This function expects the caller to handle locking.
func (*DB) UnlockTwoShards ¶ added in v0.5.1
UnlockTwoShards releases the locks acquired by LockTwoShards. The order of unlocking does not affect deadlock prevention, but we keep it clean.
func (*DB) VacuumGraph ¶ added in v0.5.1
VacuumGraph physically removes edges that have been soft-deleted for longer than the cutoff time. It returns the number of edges physically deleted. It cleans up empty nodes to prevent memory leaks over time.
type GraphEdge ¶ added in v0.5.1
type GraphEdge struct {
TargetID string `json:"t"`
CreatedAt int64 `json:"c"`
DeletedAt int64 `json:"d,omitempty"`
Weight float32 `json:"w,omitempty"`
Props json.RawMessage `json:"p,omitempty"` // json.RawMessage, shares underlying array
}
GraphEdge represents the full, outgoing edge. It acts as the Single Source of Truth (SSOT) for relationship data (weight, properties). Size: ~64 bytes.
type GraphNode ¶ added in v0.5.1
type GraphNode struct {
ID string
OutEdges map[string][]GraphEdge // RelationType -> List of outgoing edges
InEdges map[string][]ReverseEdge // RelationType -> List of incoming edges
}
GraphNode holds the adjacency lists for a single entity in RAM. We use slices instead of maps for the inner collections to avoid pointer-chasing and GC overhead. Soft deletes will be handled by updating 'DeletedAt' in place.
func NewGraphNode ¶ added in v0.5.1
NewGraphNode initializes a node with empty maps to prevent panics.
type GraphShard ¶ added in v0.5.1
type GraphShard struct {
// contains filtered or unexported fields
}
GraphShard represents an independent, lockable partition of the graph.
type GraphSnapshot ¶ added in v0.5.1
GraphSnapshot represents the state of a single graph shard for serialization.
type IndexConfig ¶
type IndexConfig struct {
Metric distance.DistanceMetric
Precision distance.PrecisionType
M int
EfConstruction int
TextLanguage string // e.g., "english", "italian", or "" to disable
AutoLinks []hnsw.AutoLinkRule
MemoryConfig hnsw.MemoryConfig `json:"memory_config,omitempty"`
}
IndexConfig holds the configuration parameters for a vector index.
type IndexInfo ¶
type IndexInfo struct {
Name string `json:"name"`
Metric distance.DistanceMetric `json:"metric"`
Precision distance.PrecisionType `json:"precision"`
M int `json:"m"`
EfConstruction int `json:"ef_construction"`
VectorCount int `json:"vector_count"`
TextLanguage string `json:"text_language"`
}
IndexInfo models the public-facing information about a vector index, intended for serialization in API responses.
type IndexSnapshot ¶
type IndexSnapshot struct {
Config IndexConfig
VectorDim int
Nodes map[uint32]*NodeSnapshot // Using a map for simpler serialization/deserialization.
ExternalToInternal map[string]uint32
InternalCounter uint32
EntrypointID uint32
MaxLevel int
QuantizerState *distance.Quantizer // Saves the quantizer's state.
QuantizedNorms []float32
MaintenanceConfig hnsw.AutoMaintenanceConfig
ArenaState mmap.ArenaState `json:"arena_state,omitempty"`
}
IndexSnapshot represents the serializable state of a single vector index. It includes the index configuration and all its node data.
type InvertedIndex ¶
type InvertedIndex map[string]map[string]map[string]PostingList
InvertedIndex is the data structure for full-text search. It maps a token (word) to a list of documents containing it. Structure: map[vector_index_name] -> map[metadata_key] -> map[token] -> PostingList
type KVStore ¶
type KVStore struct {
// contains filtered or unexported fields
}
KVStore is a thread-safe, in-memory key-value store. It uses a sync.RWMutex to manage concurrent access, allowing for multiple concurrent readers or a single exclusive writer.
func NewKVStore ¶
func NewKVStore() *KVStore
NewKVStore creates and returns a new, empty KVStore instance.
func (*KVStore) Delete ¶
Delete removes a key and its associated value from the store. This is a write operation and is fully thread-safe
func (*KVStore) Get ¶
Get retrieves the value for a given key. It returns the value and a boolean indicating whether the key was found. This is a read operation and is safe for concurrent use. The returned slice is a copy: mutating it never affects the stored state.
func (*KVStore) GetKeysWithPrefix ¶ added in v0.5.1
GetKeysWithPrefix returns a slice of keys that start with the given prefix. It limits the number of returned keys to 'limit' to prevent memory spikes. If limit <= 0, returns all matching keys.
func (*KVStore) Keys ¶ added in v0.4.7
Keys returns a snapshot of all keys currently in the store. This operation holds a read lock while copying keys, so it's relatively fast but linear to the number of keys.
func (*KVStore) RLock ¶
func (s *KVStore) RLock()
RLock locks the store for reading. It should be used in conjunction with RUnlock for operations that require a consistent read-only view across multiple steps at a higher level.
func (*KVStore) RUnlock ¶
func (s *KVStore) RUnlock()
RUnlock unlocks the store after a read lock. It must be called once for every call to RLock.
type NodeSnapshot ¶
type NodeSnapshot struct {
NodeData *hnsw.Node // The graph data (ID, connections, etc.)
Metadata map[string]interface{} // The associated metadata
}
NodeSnapshot contains all the necessary data to restore a single node.
func (*NodeSnapshot) GobDecode ¶ added in v0.5.1
func (ns *NodeSnapshot) GobDecode(data []byte) error
GobDecode implements custom gob decoding to restore metadata from JSON.
func (NodeSnapshot) GobEncode ¶ added in v0.5.1
func (ns NodeSnapshot) GobEncode() ([]byte, error)
GobEncode implements custom gob encoding to handle interface{} metadata. Converts metadata to JSON to avoid gob serialization issues with []interface{}.
type PostingEntry ¶
PostingEntry contains the document ID and term frequency for an entry in a posting list.
type ReverseEdge ¶ added in v0.5.1
type ReverseEdge struct {
SourceID string `json:"s"`
CreatedAt int64 `json:"c"`
DeletedAt int64 `json:"d,omitempty"`
}
ReverseEdge represents a lightweight incoming edge. It is used exclusively for topology navigation and time-travel filtering. Size: ~32 bytes (saves 50% RAM compared to full GraphEdge).
type Snapshot ¶
type Snapshot struct {
KVData map[string][]byte
VectorData map[string]*IndexSnapshot
GraphData [NumGraphShards]GraphSnapshot
}
Snapshot represents the complete serializable state of the database.
type TextIndexStats ¶
type TextIndexStats struct {
// Total number of documents in an indexed field
TotalDocs int
// Average length of a field across all documents
AvgFieldLength float64
// TotalDocLength is the sum of all DocLengths — an incremental counter
// that keeps AvgFieldLength computable in O(1) on every add/remove
// (bulk ingestion previously recomputed it with an O(N) scan per call).
TotalDocLength int64
// Map of DocID -> field length
DocLengths map[uint32]int
}
TextIndexStats holds statistics for a text index, used by ranking algorithms like BM25.
type VectorData ¶
type VectorData struct {
ID string `json:"id"`
Vector []float32 `json:"vector"`
Metadata map[string]any `json:"metadata"`
}
VectorData is a struct for returning the complete data of a single vector.
type VectorIndex ¶
type VectorIndex interface {
// Add inserts a new vector with a unique external ID into the index.
// It returns an internal ID used for efficient lookups.
Add(id string, vector []float32) (uint32, error)
// Delete removes a vector from the index using its external ID.
Delete(id string)
// SearchWithScores finds the K nearest neighbors to a query vector,
// returning their internal IDs and scores (distances).
// It supports pre-filtering with an allowList and index-specific search parameters like efSearch.
SearchWithScores(query []float32, k int, allowList *roaring.Bitmap, efSearch int) []types.SearchResult
// Metric returns the distance metric used by the index (e.g., Euclidean, Cosine).
Metric() distance.DistanceMetric
// Precision returns the data type precision used for storing vectors (e.g., float32, int8).
Precision() distance.PrecisionType
// GetArenaDir returns the directory path for the vector arena (mmap files).
// Returns empty string if no arena is used.
GetArenaDir() string
Close() error
}
VectorIndex defines the operations that a vector index must support. This interface allows for different index implementations (e.g., Brute Force, HNSW) to be used interchangeably within the database.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package distance provides functions for calculating vector distances.
|
Package distance provides functions for calculating vector distances. |
|
gen
command
File: internal/store/distance/gen/main.go
|
File: internal/store/distance/gen/main.go |
|
Package hnsw provides the implementation of the Hierarchical Navigable Small World graph algorithm for efficient approximate nearest neighbor search.
|
Package hnsw provides the implementation of the Hierarchical Navigable Small World graph algorithm for efficient approximate nearest neighbor search. |
|
Package text provides utilities for text processing, such as document chunking.
|
Package text provides utilities for text processing, such as document chunking. |