query

package
v0.1.0-rc.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 31, 2026 License: MIT Imports: 14 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrParsingFailed is returned when a raw query string cannot be parsed into
	// an executable query. It wraps the underlying *parser.Error (with its
	// position), so callers can errors.As it out at the boundary.
	ErrParsingFailed = errors.New("query: parsing error")
	// ErrMissingParameter is returned when a query references a placeholder
	// (e.g. vec:$v) that has no matching entry in the supplied parameters.
	ErrMissingParameter = errors.New("query: missing parameter")
	// ErrLimitExceeded is returned when a query asks for more than a configured
	// ceiling allows (top:, depth:, or the length of a bound vector). It is a
	// client error: the request is rejected rather than clamped, so the caller
	// learns their bound was too high.
	ErrLimitExceeded = errors.New("query: request limit exceeded")
)

Functions

This section is empty.

Types

type Hit

type Hit[K comparable, P float32 | float64] struct {
	Node  *graph.Node[K]
	Score P

	// Contributions is the hit's per-source breakdown, populated only when
	// the stream ran in explain mode; nil otherwise. nil doubles as the
	// serialization switch — a recall hit always has at least one
	// contribution, so nil unambiguously means "not asked for", never
	// "asked for and empty". The entries are wire-shaped (anchor identities
	// already resolved to their values) because resolution needs the graph,
	// which only the commit site holds.
	Contributions []HitContribution[P]
}

func (Hit[K, P]) MarshalJSON

func (h Hit[K, P]) MarshalJSON() ([]byte, error)

MarshalJSON flattens the node into the hit so the response carries only the value, timestamp and score, with no nested Node object. The contribution breakdown appears only when the hit carries one (explain mode), keeping the ordinary query response byte-compatible with what it was before explain existed.

type HitContribution

type HitContribution[P float32 | float64] struct {
	Source string `json:"source"`
	Score  P      `json:"score"`
	Rank   uint16 `json:"rank"`
	Via    string `json:"via,omitempty"`
	Degree uint32 `json:"degree,omitempty"`
	Count  uint16 `json:"count"`
}

HitContribution is the wire form of one contribution: the source is serialized by name, not by its Go constant, because the payload documents ranking to clients that never see the enum. A text or vector entry carries its raw mass and list position; a graph entry — one per funding anchor — carries the anchor's full observed mass, the anchor's value under via, its degree, and how many seeds funded it. With the query-level background rate, these are exactly the inputs of the scoring fold, so a client can recompute the hit's score from its own payload.

type Query

type Query[K comparable, P float32 | float64] interface {
	Plan(config *config.ConfigSet) (*Stream[K, P], error)
	GetGraphID() uint8
	hash.Hashable[K, string]
	IsWrite() bool
	SetGraphID(id uint8)
}

func Parse

func Parse[K comparable, P float32 | float64](q string, params map[string][]P, c *config.ConfigSet) (Query[K, P], []parser.Warning, error)

Parse turns a raw query string into an executable Query. Vector arguments are passed out-of-band in params, keyed by the placeholder name used in the query (e.g. `vec:$v` binds to params["v"]). This keeps the parser lightweight: it only records the placeholder, and the real vector is injected here.

Warnings accompany a query that parsed and will run: they flag a reading the client may not have meant (see parser.Warning) and must travel to the client alongside the results, never attached to the query itself — the plan cache substitutes query objects on a hash hit, so state on the query would leak between requests.

type QueryContext

type QueryContext struct {
	GraphID uint8
}

type QueryParameters

type QueryParameters[K comparable] struct {
	Top   int
	Depth int
	Since containers.TimeValue[K]
	Until containers.TimeValue[K]
}

type QueryResult

type QueryResult[K comparable, P float32 | float64] struct {
	Count int         `json:"count"`
	Hits  []Hit[K, P] `json:"hits"`

	// Background is the query's background rate ρ₀ — the average seed mass
	// per unit of anchor degree the traversal observed — attached only in
	// explain mode. Together with each hit's contribution breakdown it lets a
	// client recompute every score: S = m + α²·Σ max(0, M_A − m − d_A·ρ₀).
	// omitempty doubles as the mode switch: a plain query never carries it.
	Background P `json:"background,omitempty"`
}

type Recall

type Recall[K comparable, P float32 | float64] struct {
	Keywords []string
	Vector   containers.Vector[K, P]
	Entities []string
	Topics   []string

	Parameters QueryParameters[K]
	// contains filtered or unexported fields
}

func (Recall[K, P]) GetGraphID

func (r Recall[K, P]) GetGraphID() uint8

func (Recall[K, P]) Hash

func (r Recall[K, P]) Hash(h hash.Hasher[K, string]) K

Hash keys the query for the plan cache. It must fold in everything that changes the result set: two recalls that differ only in graph, depth, top, time bounds or the bound vector must not collide, or the cache would hand back a stale plan. The lists are delimited so ["ab"] and ["a","b"] do not hash alike.

func (Recall[K, P]) IsWrite

func (r Recall[K, P]) IsWrite() bool

func (*Recall[K, P]) Plan

func (r *Recall[K, P]) Plan(config *config.ConfigSet) (*Stream[K, P], error)

func (*Recall[K, P]) SetGraphID

func (r *Recall[K, P]) SetGraphID(id uint8)

func (Recall[K, P]) Since

func (r Recall[K, P]) Since(now time.Time) time.Time

Since resolves the query's lower time bound; the zero time (no bound) is returned when the query has no since clause.

func (Recall[K, P]) Until

func (r Recall[K, P]) Until(now time.Time) time.Time

Until resolves the query's upper time bound; the zero time (no bound) is returned when the query has no until clause.

type Remember

type Remember[K comparable, P float32 | float64] struct {
	Value    string
	Entities []string
	Topics   []string
	Vector   containers.Vector[K, P]
	// contains filtered or unexported fields
}

func (Remember[K, P]) GetGraphID

func (r Remember[K, P]) GetGraphID() uint8

func (Remember[K, P]) Hash

func (r Remember[K, P]) Hash(h hash.Hasher[K, string]) K

Hash keys the query for the plan cache. Like Recall it must fold in the graph selector and every field that changes what gets written — including the bound vector: hashing only Value would make `remember@3 'x' topic:a` and `remember@5 'x' topic:b` collide, so the second would reuse the first's plan and write to the wrong graph.

func (Remember[K, P]) IsWrite

func (r Remember[K, P]) IsWrite() bool

func (*Remember[K, P]) Plan

func (r *Remember[K, P]) Plan(config *config.ConfigSet) (*Stream[K, P], error)

func (*Remember[K, P]) SetGraphID

func (r *Remember[K, P]) SetGraphID(id uint8)

type Stream

type Stream[K comparable, P float32 | float64] struct {
	Query  Query[K, P]
	Result *QueryResult[K, P]
	Err    error

	// Explain asks the read path to attach each hit's contribution records to
	// the result. It lives on the stream, not the query, on purpose: the
	// engine caches query objects by hash and substitutes them on a hit, so a
	// flag on the query would either leak one request's explain choice into
	// another's or have to widen the cache key for a bit that never changes
	// the plan. The stream is built per request and never cached.
	Explain bool
	// contains filtered or unexported fields
}

data structure representing a stream: language of the scheduler A stream is the language for the engine to the worker Streams can be read-only or read and write.

func NewStream

func NewStream[K comparable, P float32 | float64](q Query[K, P]) *Stream[K, P]

NewStream returns a stream ready to be scheduled for q: Done() blocks until the scheduler commits or rolls the stream back.

func (*Stream[K, P]) Acquire

func (s *Stream[K, P]) Acquire(g graph.Graph[K, P])

func (*Stream[K, P]) Commit

func (s *Stream[K, P]) Commit(g graph.Graph[K, P]) error

Commit executes the stream's query against g directly. The caller must hold the appropriate lock (the write lock for writes, a read lock for reads — see Acquire): the lock is already exclusive for writes, so mutating g in place exposes no intermediate state, and the write costs O(fact + incremental index updates) regardless of graph size. Copying the graph here (as staging once did) would make every single-fact write O(total graph) and lock readers out for the duration — that is the failure mode, not the safety mechanism.

Failure ordering: the vector insert runs before any graph mutation, so the one realistic commit failure (a vector-dimension mismatch) rejects the write with g untouched. Later index errors are pathological; they surface in the returned error with the write partially applied.

func (*Stream[K, P]) Done

func (s *Stream[K, P]) Done() <-chan struct{}

func (*Stream[K, P]) Finish

func (s *Stream[K, P]) Finish()

func (*Stream[K, P]) GraphID

func (s *Stream[K, P]) GraphID() uint8

func (*Stream[K, P]) Release

func (s *Stream[K, P]) Release(g graph.Graph[K, P])

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL