Files
zeekay f5aaeb712e Hanzo Graph — the engine, on zapdb, ZAP-native
Derived from Dgraph (github.com/dgraph-io/dgraph) at commit 64804bd2, Apache-2.0.
See NOTICE.

WHAT THIS IS. The graph engine as a Go library: posting lists, the DQL parser,
the type and tokenizer system, the index and schema layers, and the wire types.
39,170 lines of the upstream's 166,337.

THE STORE is github.com/luxfi/zapdb, a Badger fork that kept the package name,
the subpackages (options, pb, y) and the API — Open, OpenManaged, DB, Options —
so the 74 import sites are aliased rather than rewritten.

THE CODEC is ZAP. zapdb serializes with ZAP, not protobuf: its pb package builds
the ZAP types by default and the protobuf ones only under `-tags grpc`, a path
that does not compile (table/builder.go calls pb.Marshal, which that tag
removes). One call site in posting needed converting; every other type here is
Hanzo's own protobuf and is untouched.

NO TRANSPORT. An embedded engine dials nothing, so nothing here imports
google.golang.org/grpc. Removed: 20 transport functions in x, the generated
service stubs for Raft, Zero and Worker (1,657 lines), and the JWT helper —
identity belongs to IAM. The core called none of them.

NOT KEPT: worker, conn, raftwal, the cluster commands, the GraphQL layer and the
test harnesses. `query`, the DQL execution engine, went with them because it
depends on worker; parsing DQL is available here, executing it is not.

The history of the upstream project lives at github.com/dgraph-io/dgraph. This
repository begins at the derivation because three quarters of that history
describes code this fork does not carry.
2026-08-20 21:26:27 -07:00

186 lines
8.2 KiB
Go

/*
* SPDX-FileCopyrightText: © 2017-2026 Istari Digital, Inc.
* SPDX-License-Identifier: Apache-2.0
*/
package index
import (
"context"
c "github.com/hanzoai/graph/tok/constraints"
opts "github.com/hanzoai/graph/tok/options"
)
// IndexFactory is responsible for being able to create, find, and remove
// VectorIndexes. There is no "update" as of now; just remove and create.
//
// It is expected that the IndexFactory has some notion of persistence, but
// it is perfectly happy to support a total in-memory solution. To achieve
// persistence, it is the responsibility of the implementations of IndexFactory
// to reference the persistent storage.
type IndexFactory[T c.Float] interface {
// The Name returned represents the name of the factory rather than the
// name of any particular index.
Name() string
// Fetch the string of all the options being used
GetOptions(o opts.Options) string
// Specifies the set of allowed options and a corresponding means to
// parse a string version of those options.
AllowedOptions() opts.AllowedOptions
// Create is expected to create a VectorIndex, or generate an error
// if the name already has a corresponding VectorIndex or other problems.
// The name will be associated with with the generated VectorIndex
// such that if we Create an index with the name "foo", then later
// attempt to find the index with name "foo", it will refer to the
// same object.
// The set of vectors to use in the index process is defined by
// source.
Create(name string, o opts.Options, floatBits int) (VectorIndex[T], error)
// Find is expected to retrieve the VectorIndex corresponding with the
// name. If it attempts to find a name that does not exist, the VectorIndex
// will return as a nil value. It should throw an error in persistent storage
// issues when accessing information.
Find(name string) (VectorIndex[T], error)
// Remove is expected to delete the VectorIndex corresponding with the name.
// If removing a name that doesn't exist, nothing will happen and no errors
// are thrown. An error should only be thrown if there is issues accessing
// persistent storage information.
Remove(name string) error
// CreateOrReplace will create a new index -- as defined by the Create
// function -- if it does not yet exist, otherwise, it will replace any
// index with the given name.
CreateOrReplace(name string, o opts.Options, floatBits int) (VectorIndex[T], error)
}
// SearchFilter defines a predicate function that we will use to determine
// whether or not a given vector is "interesting". When used in the context
// of VectorIndex.Search, a true result means that we want to keep the result
// in the returned list, and a false result implies we should skip.
type SearchFilter[T c.Float] func(query, resultVal []T, resultUID uint64) bool
// AcceptAll implements SearchFilter by way of accepting all results.
func AcceptAll[T c.Float](_, _ []T, _ uint64) bool { return true }
// AcceptNone implements SearchFilter by way of rejecting all results.
func AcceptNone[T c.Float](_, _ []T, _ uint64) bool { return false }
// OptionalIndexSupport defines abilities that might not be universally
// supported by all VectorIndex types. A VectorIndex will technically
// define the functions required by OptionalIndexSupport, but may do so
// by way of simply returning an errors.ErrUnsupported result.
type OptionalIndexSupport[T c.Float] interface {
// SearchWithPath(ctx, c, query, maxResults, filter) is similar to
// Search(ctx, c, query, maxResults, filter), but returns an extended
// set of content in the search results.
// The full contents returned are indicated by the SearchPathResult.
// See the description there for more info.
SearchWithPath(
ctx context.Context,
c CacheType,
query []T,
maxResults int,
filter SearchFilter[T]) (*SearchPathResult, error)
}
// A VectorIndex can be used to Search for vectors and add vectors to an index.
type VectorIndex[T c.Float] interface {
OptionalIndexSupport[T]
// Search will find the uids for a given set of vectors based on the
// input query, limiting to the specified maximum number of results.
// The filter parameter indicates that we might discard certain parameters
// based on some input criteria. The maxResults count is counted *after*
// being filtered. In other words, we only count those results that had not
// been filtered out.
Search(ctx context.Context, c CacheType, query []T,
maxResults int,
filter SearchFilter[T]) ([]uint64, error)
// SearchWithUid will find the uids for a given set of vectors based on the
// input queryUid, limiting to the specified maximum number of results.
// The filter parameter indicates that we might discard certain parameters
// based on some input criteria. The maxResults count is counted *after*
// being filtered. In other words, we only count those results that had not
// been filtered out.
SearchWithUid(ctx context.Context, c CacheType, queryUid uint64,
maxResults int,
filter SearchFilter[T]) ([]uint64, error)
// Insert will add a vector and uuid into the existing VectorIndex. If
// uuid already exists, it should throw an error to not insert duplicate uuids
Insert(ctx context.Context, c CacheType, uuid uint64, vec []T) ([]*KeyValue, error)
}
// VectorIndexOptions carries optional, per-call search tuning parameters.
// Zero values mean "no override".
type VectorIndexOptions[T c.Float] struct {
// EfOverride, when > 0, overrides the search breadth (ef) for this call.
// Implementations should apply this to upper layers and use max(k, ef) for
// the bottom layer candidate size, then return the best k.
EfOverride int
// DistanceThreshold, when non-nil, filters out neighbors whose metric-domain
// distance exceeds the given threshold. Semantics depend on the index metric:
// - Euclidean: direct Euclidean distance (not squared)
// - Cosine: cosine distance in [0,2] (1 - cosine_similarity)
// - Dot product: undefined; implementations may ignore
DistanceThreshold *float64
// Filter allows callers to pass a SearchFilter; if nil, AcceptAll should be used.
Filter SearchFilter[T]
}
// OptionalSearchOptions adds per-call search controls without breaking existing APIs.
// Implementations that support these may choose to ignore unsupported fields.
type OptionalSearchOptions[T c.Float] interface {
SearchWithOptions(ctx context.Context, c CacheType, query []T,
maxResults int, opts VectorIndexOptions[T]) ([]uint64, error)
SearchWithUidAndOptions(ctx context.Context, c CacheType, queryUid uint64,
maxResults int, opts VectorIndexOptions[T]) ([]uint64, error)
}
// A Txn is an interface representation of a persistent storage transaction,
// where multiple operations are performed on a database
type Txn interface {
// StartTs gets the exact time that the transaction started, returned in uint64 format
StartTs() uint64
// Get uses a []byte key to return the Value corresponding to the key
Get(key []byte) (rval []byte, rerr error)
// GetWithLockHeld uses a []byte key to return the Value corresponding to the key with a mutex lock held
GetWithLockHeld(key []byte) (rval []byte, rerr error)
Find(prefix []byte, filter func(val []byte) bool) (uint64, error)
// Adds a mutation operation on a index.Txn interface, where the mutation
// is represented in the form of an index.DirectedEdge
AddMutation(ctx context.Context, key []byte, t *KeyValue) error
// Same as AddMutation but with a mutex lock held
AddMutationWithLockHeld(ctx context.Context, key []byte, t *KeyValue) error
// mutex lock
LockKey(key []byte)
// mutex unlock
UnlockKey(key []byte)
}
// Local cache is an interface representation of the local cache of a persistent storage system
type LocalCache interface {
// Get uses a []byte key to return the Value corresponding to the key
Get(key []byte) (rval []byte, rerr error)
// GetWithLockHeld uses a []byte key to return the Value corresponding to the key with a mutex lock held
GetWithLockHeld(key []byte) (rval []byte, rerr error)
Find(prefix []byte, filter func(val []byte) bool) (uint64, error)
}
// CacheType is an interface representation of the cache of a persistent storage system
type CacheType interface {
Get(key []byte) (rval []byte, rerr error)
Ts() uint64
Find(prefix []byte, filter func(val []byte) bool) (uint64, error)
}