redis

package module
v0.61.0 Latest Latest
Warning

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

Go to latest
Published: Nov 10, 2026 License: Apache-2.0 Imports: 21 Imported by: 0

Documentation

Overview

Package redis stores prepared vectors in host-owned Redis HASHes and performs native KNN search. NewStore and operations inspect the concrete RESP3 FT.INFO definition: one unfiltered HASH prefix ending with SpaceID.StorageKey()+":", one FLOAT32 embedding VECTOR (COSINE, L2 or IP), optional content TEXT and optional metadata_terms TAG with comma separator. The Host provisions the index and owns the client, topology, credentials and timeouts.

Upsert prepares every row before writing. Each HASH contains content, vector bytes, canonical metadata_json, and a derived metadata_terms projection. Lua replaces one HASH atomically. WriteBatchSize bounds the nontransactional pipeline; vectorstore.WriteError exposes confirmed, uncertain and unattempted IDs. Search index visibility can lag a confirmed write.

Query has no enumeration path. It ranks with FT.SEARCH; its native predicate subset is scalar equality on a top-level string when the TAG index exists. Field names and exact string values are encoded as lowercase hexadecimal TAG tokens. Response warnings, incomplete replies, damaged records and predicates outside the supported subset are errors.

QueryByScan and DeleteMatching explicitly accept a time, record and byte grant. SCAN COUNT is only a hint: each master bounds key-page output in Lua. Each distinct key is charged before its HASH payload is fetched; bytes count the key plus the four field names and values, excluding protocol framing. A second atomic size check rejects concurrent growth; vanished keys are charged for their names. The host binds ScanNodes to the complete authoritative keyspace; ClusterClient.ForEachMaster supports decorated clients without type discovery. Ring.ForEachShard is insufficient because it can skip unavailable shards. A slow scan may hit its deadline and has no snapshot isolation. No partial search result is returned. DeleteMatching finishes selection then compares current canonical metadata before deleting each record; earlier deletions may survive a later failure. DeleteIDs accepts explicit identities and uses single-key DEL.

Integration fixtures require SCOPE_REDIS_ADDR on an isolated Redis Search instance. They create disposable native indexes and remove them afterwards.

Index

Examples

Constants

View Source
const (
	Provider         = "Redis"
	DefaultIndexName = "scope-vector-index"

	DefaultWriteBatchSize = 256
)

Variables

View Source
var ErrIncompatibleIndex = errors.New("redis: native index is incompatible")

Functions

This section is empty.

Types

type RedisClient added in v0.43.0

type RedisClient interface {
	Do(context.Context, ...any) *goredis.Cmd
	Pipeline() goredis.Pipeliner
	// contains filtered or unexported methods
}

RedisClient supplies host-owned native commands. StoreConfig.ScanNodes owns complete keyspace traversal independently of command-client decorators.

type Store

type Store struct {
	// contains filtered or unexported fields
}

func NewStore

func NewStore(ctx context.Context, config StoreConfig) (*Store, error)
Example
package main

import (
	"context"
	"os"
	"time"

	goredis "github.com/redis/go-redis/v9"

	"github.com/Tangerg/scope/core/document"
	"github.com/Tangerg/scope/core/vectorstore"
	"github.com/Tangerg/scope/vectorstores/redis"
)

func main() {
	ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
	defer cancel()
	client := goredis.NewClient(&goredis.Options{Addr: os.Getenv("SCOPE_REDIS_ADDR"), Protocol: 3, Username: os.Getenv("SCOPE_REDIS_USERNAME"), Password: os.Getenv("SCOPE_REDIS_PASSWORD"), ContextTimeoutEnabled: true, ReadTimeout: 5 * time.Second, WriteTimeout: 5 * time.Second})
	defer client.Close()
	const space vectorstore.SpaceID = "paired-v1"
	// Provision once through the native host API, before constructing Store.
	if err := client.FTCreate(ctx, "documents", &goredis.FTCreateOptions{OnHash: true, Prefix: []any{"documents:" + space.StorageKey() + ":"}}, &goredis.FieldSchema{FieldName: "embedding", FieldType: goredis.SearchFieldTypeVector, VectorArgs: &goredis.FTVectorArgs{FlatOptions: &goredis.FTFlatOptions{Type: "FLOAT32", Dim: 2, DistanceMetric: "COSINE"}}}).Err(); err != nil {
		panic(err)
	}
	store, err := redis.NewStore(ctx, redis.StoreConfig{Client: client, ScanNodes: func(ctx context.Context, visit func(context.Context, *goredis.Client) error) error {
		return visit(ctx, client)
	}, IndexName: "documents", Space: space})
	if err != nil {
		panic(err)
	}
	if err = store.Upsert(ctx, &vectorstore.Batch{Space: space, Records: []vectorstore.Record{{Document: &document.Document{ID: "one", Text: "example"}, Values: []float64{1, 0}}}}); err != nil {
		panic(err)
	}
	if _, err = store.Query(ctx, &vectorstore.Query{Space: space, Values: []float64{1, 0}}); err != nil {
		panic(err)
	}
	if err = store.DeleteIDs(ctx, []string{"one"}); err != nil {
		panic(err)
	}
}

func (*Store) CheckDocuments added in v0.59.0

func (s *Store) CheckDocuments(ctx context.Context, space vectorstore.SpaceID, docs []*document.Document) error

func (*Store) CheckQuery added in v0.59.0

func (s *Store) CheckQuery(ctx context.Context, space vectorstore.SpaceID, opts vectorstore.SearchOptions) error

func (*Store) DeleteIDs

func (s *Store) DeleteIDs(ctx context.Context, ids []string) error

func (*Store) DeleteMatching added in v0.59.0

func (s *Store) DeleteMatching(ctx context.Context, predicate filter.Predicate, b vectorstore.ScanBudget) error

func (*Store) Query added in v0.59.0

func (*Store) QueryByScan added in v0.60.0

func (*Store) Upsert added in v0.59.0

func (s *Store) Upsert(ctx context.Context, b *vectorstore.Batch) error

type StoreConfig

type StoreConfig struct {
	Client    RedisClient
	IndexName string
	Space     vectorstore.SpaceID
	// ScanNodes visits every authoritative node in Client's keyspace and fails
	// if any node is unavailable. ClusterClient.ForEachMaster satisfies this
	// contract; Ring.ForEachShard does not, because it can skip failed shards.
	// The host binds commands and traversal to the same logical Redis store.
	ScanNodes func(context.Context, func(context.Context, *goredis.Client) error) error
	// WriteBatchSize bounds commands submitted in one nontransactional pipeline.
	WriteBatchSize int
}

func (StoreConfig) Validate

func (s StoreConfig) Validate() error

Jump to

Keyboard shortcuts

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