search

package module
v1.13.5 Latest Latest
Warning

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

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

README

Forge Search, a full-text search extension for Go applications built on Forge, with filters, suggestions and autocomplete

Forge Search: full-text search for Go services

Forge Search is the search extension for Forge, the Go backend framework. You add it to your app and get one Search interface in the dependency injection container for index management, document indexing, full-text search with filters and field boosts, search suggestions and autocomplete. The in-memory backend is the one that works today. The config also accepts elasticsearch, meilisearch and typesense, but those drivers are placeholders that never contact a server, so read Backends before you plan around them.

Go CI Go Reference Apache 2.0

Documentation · Quick start · Features · Searching · Backends · Configuration · FAQ

Quick start

You need Go 1.26 or later and a Go module:

go get github.com/xraph/forge@latest
go get github.com/xraph/forge/extensions/search@latest

Save this as main.go. It creates a products index when the app starts, adds three documents, and serves a search endpoint:

package main

import (
	"context"
	"log"
	"net/http"

	"github.com/xraph/forge"
	"github.com/xraph/forge/extensions/search"
)

func main() {
	app := forge.NewApp(forge.AppConfig{
		Name:        "search-demo",
		HTTPAddress: ":8080",
		Extensions: []forge.Extension{
			search.NewExtension(search.WithDriver("inmemory")),
		},
	})

	// The search service connects when the extension starts, so seed the
	// index once the app is up.
	err := forge.OnStarted(app, "seed-products", func(ctx context.Context, a forge.App) error {
		s := search.MustGetSearchFromApp(a)

		if err := s.CreateIndex(ctx, "products", search.IndexSchema{
			Fields: []search.FieldSchema{
				{Name: "title", Type: "text", Searchable: true},
				{Name: "category", Type: "keyword", Filterable: true},
			},
		}); err != nil {
			return err
		}

		return s.BulkIndex(ctx, "products", []search.Document{
			{ID: "1", Fields: map[string]any{"title": "Mechanical keyboard", "category": "input"}},
			{ID: "2", Fields: map[string]any{"title": "Wireless mouse", "category": "input"}},
			{ID: "3", Fields: map[string]any{"title": "USB-C keyboard dock", "category": "hubs"}},
		})
	})
	if err != nil {
		log.Fatal(err)
	}

	err = app.Router().GET("/search", func(ctx forge.Context) error {
		s, err := search.GetSearchFromApp(app)
		if err != nil {
			return err
		}

		results, err := s.Search(ctx.Context(), search.SearchQuery{
			Index: "products",
			Query: ctx.Query("q"),
			Limit: 10,
		})
		if err != nil {
			return err
		}

		return ctx.JSON(http.StatusOK, results)
	})
	if err != nil {
		log.Fatal(err)
	}

	if err := app.Run(); err != nil {
		log.Fatal(err)
	}
}

Run it and search:

go mod tidy
go run .

# in another terminal
curl 'http://localhost:8080/search?q=keyboard'

You get the keyboard and the dock back, each with a score, plus total, offset and limit. Hits with equal scores can come back in either order. The index lives in process memory, so when you stop the app with Ctrl+C and run it again, you start from an empty index and the start hook seeds it for you.

Features

You need Forge Search gives you
One search API for your services The Search interface, registered in the container as *search.SearchService and as search.Search
Indexes with a schema CreateIndex, DeleteIndex, ListIndexes and GetIndexInfo, with field types, analyzers, synonyms and ranking settings in IndexSchema
Document writes Index, BulkIndex, Get, Update and Delete
Full-text search Case-insensitive matching across every field, with per-field boosts, a minimum score, an offset and a limit capped by MaxLimit
Filters =, !=, EXISTS and NOT EXISTS on any field
Search-as-you-type Suggest for substring matches on one field, Autocomplete for prefix matches
Lifecycle and health The backend connects on start, disconnects on stop, and reports health through Ping
Sentinel errors ErrIndexNotFound, ErrIndexAlreadyExists, ErrDocumentNotFound, ErrNotConnected and more, for errors.Is

Index and search documents

Resolve the service from the container once the app has started. search.GetSearch(container), search.GetSearchFromApp(app) and their Must... variants do it for you, and forge.Inject[*search.SearchService](container) works too.

s := search.MustGetSearchFromApp(app)

err := s.Index(ctx, "products", search.Document{
	ID:     "4",
	Fields: map[string]any{"title": "Laptop stand", "category": "desk", "brand": "Acme"},
})

results, err := s.Search(ctx, search.SearchQuery{
	Index:       "products",
	Query:       "stand",
	Filters:     []search.Filter{{Field: "category", Operator: "=", Value: "desk"}},
	BoostFields: map[string]float64{"title": 2},
	Offset:      0,
	Limit:       20,
})

Index writes or replaces the document with that ID. You have to create the index first, otherwise you get ErrIndexNotFound, and calling CreateIndex on a name you already used returns ErrIndexAlreadyExists, which you can check with errors.Is if your startup code might run twice.

Here is what the in-memory backend does with each field of a SearchQuery:

Field Behaviour
Query Lowercased substring match against the string form of every field. An empty query matches every document
Scoring Each matching field adds 1, multiplied by its BoostFields entry, and doubled when the whole field equals the query. Hits come back highest score first
MinScore Drops hits that score below it
Filters Supports = (or ==), !=, EXISTS and NOT EXISTS, compared as strings. Any other operator matches nothing
Limit 0 uses DefaultLimit (20). Anything above MaxLimit (100) is capped
Sort, Facets, Highlight, FuzzyLevel Accepted, not applied yet

One small trap. ProcessingTime in the results is a Go time.Duration, so when you return the results as JSON you get a nanosecond count, even though the key says processing_time_ms.

For search-as-you-type, ask one field for completions:

done, err := s.Autocomplete(ctx, search.AutocompleteQuery{
	Index: "products",
	Field: "title",
	Query: "wire",
	Limit: 5,
})
// done.Completions[0].Text == "Wireless mouse"

Suggest takes a SuggestQuery with the same fields and matches anywhere in the value. Both default to 10 results.

Backends

Driver Status Needs
inmemory Works. Indexes live in process memory and are lost on restart Nothing
elasticsearch Placeholder. It connects without contacting a server, writes are dropped, and Search returns no hits url or hosts to pass validation
meilisearch Placeholder, same as above url
typesense Placeholder, same as above url or hosts, and api_key

The placeholders are there so the config shape and the service wiring are settled before the client code lands. Do not point production traffic at them. An app you configure for Elasticsearch starts fine, logs that it connected, and silently indexes nothing.

Configuration

You can configure the extension in code with options, or in YAML under extensions.search (the extension also reads a top-level search key).

search.NewExtension(
	search.WithDriver("inmemory"),
	search.WithDefaultLimit(25),
	search.WithMaxLimit(200),
)
Option Sets
WithDriver(string) Driver: inmemory, elasticsearch, meilisearch or typesense
WithURL(string), WithHosts(...string) Server address, or several
WithAuth(user, pass), WithAPIKey(string) Credentials
WithMaxConnections(int), WithTimeout(time.Duration) Pool size and RequestTimeout
WithDefaultLimit(int), WithMaxLimit(int) Result limits
WithTLS(cert, key, ca) Turns on TLS with those files
WithMetrics(bool), WithTracing(bool) Observability flags
WithRequireConfig(bool) Fail at startup if no YAML config is found
WithConfig(search.Config) Replaces the whole config

NewExtensionWithConfig(cfg) is the same as NewExtension(WithConfig(cfg)). Validation runs at registration, so a bad combination (say max_limit below default_limit) stops the app before it serves anything.

The YAML keys are the snake_case names from the struct tags:

extensions:
  search:
    driver: inmemory
    default_limit: 25
    max_limit: 200
    request_timeout: 30s
Key Default
driver inmemory
url, hosts, username, password, api_key empty
max_connections, max_idle_connections 10, 5
connect_timeout, request_timeout, keep_alive 10s, 30s, 60s
max_retries, retry_backoff, retry_on_timeout 3, 100ms, true
default_limit, max_limit, default_min_score 20, 100, 0
enable_highlight, enable_facets true, true
bulk_size, flush_interval, enable_compression 100, 5s, false
enable_tls, tls_cert_file, tls_key_file, tls_ca_file, insecure_skip_verify off and empty
enable_metrics, enable_tracing true, true

Most of the connection, retry, bulk and TLS settings only matter to the network drivers, which are not implemented yet.

YAML overrides the defaults, and options you set in code override YAML. A driver or default_limit in the file takes effect with a plain search.NewExtension(), while search.WithDefaultLimit(70) still beats whatever the file says. Fields you leave out of the YAML keep their DefaultConfig() values.

Forge reads config.yaml only when EnableConfigAutoDiscovery is on. forge.DefaultAppConfig() turns it on, but an AppConfig literal like the one in the quick start leaves it off, so set it yourself or pass your own ConfigManager.

Documentation

Topic Where
Overview Search docs
Features and usage Search features
Configuration reference Search configuration
Function reference Search functions
Go API pkg.go.dev
How extensions load config and register services Forge extension system

The docs pages were written before this README. Where they disagree about backends, filter operators or YAML key names, the tables above match the code.

FAQ

How do I add full-text search to a Go app built on Forge?

Add search.NewExtension() to Extensions in forge.AppConfig, create an index once the app has started, and call Search on the service from your handlers. The quick start is a complete program.

Does Forge Search work with Elasticsearch, Meilisearch or Typesense?

Not yet. The drivers exist and pass config validation, but they never talk to a server: writes are dropped and searches return nothing. Use inmemory until a real client lands, or wrap your own client behind the search.Search interface.

Is the in-memory search index persistent?

No. It is a map in process memory, so it suits development, tests and small data sets you can rebuild on startup. Every restart starts empty.

Does Forge Search support fuzzy matching, facets and sorting?

The query types carry those fields (FuzzyLevel, Facets, Sort, Highlight), but the in-memory backend ignores them today. It does case-insensitive substring matching with boosts, a minimum score and simple filters.

Is the in-memory backend safe for concurrent use?

Yes. The index map and each index's documents sit behind sync.RWMutex locks, so concurrent handlers can index and search at the same time.

Contributing

Search is its own Go module inside the Forge repository. Build, vet and test it from its directory the way CI does:

cd extensions/search
GOWORK=off go build ./...
GOWORK=off go vet ./...
GOWORK=off go test -short -count=1 ./...
golangci-lint run ./...

Forge's AGENTS.md has the pinned lint version and the rest of the repository conventions. Commits follow Conventional Commits, for example feat(search): ....

License

Forge Search is part of Forge and is available under the Apache License 2.0.

Documentation

Index

Constants

View Source
const (
	// ServiceKey is the DI key for the search service.
	ServiceKey = "search"
)

DI container keys for search extension services.

Variables

View Source
var (
	ErrNotConnected       = errors.New("search: not connected")
	ErrAlreadyConnected   = errors.New("search: already connected")
	ErrIndexNotFound      = errors.New("search: index not found")
	ErrIndexAlreadyExists = errors.New("search: index already exists")
	ErrDocumentNotFound   = errors.New("search: document not found")
	ErrInvalidQuery       = errors.New("search: invalid query")
	ErrInvalidSchema      = errors.New("search: invalid schema")
	ErrConnectionFailed   = errors.New("search: connection failed")
	ErrTimeout            = errors.New("search: operation timeout")
	ErrInvalidConfig      = errors.New("search: invalid configuration")
	ErrUnsupportedDriver  = errors.New("search: unsupported driver")
	ErrOperationFailed    = errors.New("search: operation failed")
)

Common search errors.

Functions

func NewExtension

func NewExtension(opts ...ConfigOption) forge.Extension

NewExtension creates a new search extension with functional options. Config is loaded from ConfigManager by default, with options providing overrides.

Example:

// Load from ConfigManager (tries "extensions.search", then "search")
search.NewExtension()

// Override specific fields
search.NewExtension(
    search.WithDriver("elasticsearch"),
    search.WithURL("http://localhost:9200"),
)

// Require config from ConfigManager
search.NewExtension(search.WithRequireConfig(true))

func NewExtensionWithConfig

func NewExtensionWithConfig(config Config) forge.Extension

NewExtensionWithConfig creates a new search extension with a complete config. This is for backward compatibility or when config is fully known at initialization.

Types

type Analyzer

type Analyzer struct {
	Type        string   `json:"type"` // standard, simple, whitespace, keyword, pattern
	Tokenizer   string   `json:"tokenizer,omitempty"`
	Filters     []string `json:"filters,omitempty"`
	CharFilters []string `json:"char_filters,omitempty"`
}

Analyzer defines text analysis configuration.

type AutocompleteQuery

type AutocompleteQuery struct {
	Index string `json:"index"`
	Query string `json:"query"`
	Field string `json:"field"`
	Limit int    `json:"limit,omitempty"`
}

AutocompleteQuery represents an autocomplete request.

type AutocompleteResults

type AutocompleteResults struct {
	Completions    []Completion  `json:"completions"`
	ProcessingTime time.Duration `json:"processing_time_ms"`
}

AutocompleteResults contains autocomplete response.

type Completion

type Completion struct {
	Text  string  `json:"text"`
	Score float64 `json:"score"`
}

Completion represents a single completion.

type Config

type Config struct {
	// Driver specifies the search backend: "inmemory", "elasticsearch", "meilisearch", "typesense"
	Driver string `json:"driver" mapstructure:"driver" yaml:"driver"`

	// Connection settings
	URL      string   `json:"url,omitempty"      mapstructure:"url"      yaml:"url,omitempty"`
	Hosts    []string `json:"hosts,omitempty"    mapstructure:"hosts"    yaml:"hosts,omitempty"`
	Username string   `json:"username,omitempty" mapstructure:"username" yaml:"username,omitempty"`
	Password string   `json:"password,omitempty" mapstructure:"password" yaml:"password,omitempty"`
	APIKey   string   `json:"api_key,omitempty"  mapstructure:"api_key"  yaml:"api_key,omitempty"`

	// Connection pool
	MaxConnections     int           `json:"max_connections"      mapstructure:"max_connections"      yaml:"max_connections"`
	MaxIdleConnections int           `json:"max_idle_connections" mapstructure:"max_idle_connections" yaml:"max_idle_connections"`
	ConnectTimeout     time.Duration `json:"connect_timeout"      mapstructure:"connect_timeout"      yaml:"connect_timeout"`
	RequestTimeout     time.Duration `json:"request_timeout"      mapstructure:"request_timeout"      yaml:"request_timeout"`
	KeepAlive          time.Duration `json:"keep_alive"           mapstructure:"keep_alive"           yaml:"keep_alive"`

	// Retry policy
	MaxRetries     int           `json:"max_retries"      mapstructure:"max_retries"      yaml:"max_retries"`
	RetryBackoff   time.Duration `json:"retry_backoff"    mapstructure:"retry_backoff"    yaml:"retry_backoff"`
	RetryOnTimeout bool          `json:"retry_on_timeout" mapstructure:"retry_on_timeout" yaml:"retry_on_timeout"`

	// Default search settings
	DefaultLimit    int     `json:"default_limit"     mapstructure:"default_limit"     yaml:"default_limit"`
	MaxLimit        int     `json:"max_limit"         mapstructure:"max_limit"         yaml:"max_limit"`
	DefaultMinScore float64 `json:"default_min_score" mapstructure:"default_min_score" yaml:"default_min_score"`
	EnableHighlight bool    `json:"enable_highlight"  mapstructure:"enable_highlight"  yaml:"enable_highlight"`
	EnableFacets    bool    `json:"enable_facets"     mapstructure:"enable_facets"     yaml:"enable_facets"`

	// Performance
	BulkSize          int           `json:"bulk_size"          mapstructure:"bulk_size"          yaml:"bulk_size"`
	FlushInterval     time.Duration `json:"flush_interval"     mapstructure:"flush_interval"     yaml:"flush_interval"`
	EnableCompression bool          `json:"enable_compression" mapstructure:"enable_compression" yaml:"enable_compression"`

	// Security
	EnableTLS          bool   `json:"enable_tls"              mapstructure:"enable_tls"           yaml:"enable_tls"`
	TLSCertFile        string `json:"tls_cert_file,omitempty" mapstructure:"tls_cert_file"        yaml:"tls_cert_file,omitempty"`
	TLSKeyFile         string `json:"tls_key_file,omitempty"  mapstructure:"tls_key_file"         yaml:"tls_key_file,omitempty"`
	TLSCAFile          string `json:"tls_ca_file,omitempty"   mapstructure:"tls_ca_file"          yaml:"tls_ca_file,omitempty"`
	InsecureSkipVerify bool   `json:"insecure_skip_verify"    mapstructure:"insecure_skip_verify" yaml:"insecure_skip_verify"`

	// Monitoring
	EnableMetrics bool `json:"enable_metrics" mapstructure:"enable_metrics" yaml:"enable_metrics"`
	EnableTracing bool `json:"enable_tracing" mapstructure:"enable_tracing" yaml:"enable_tracing"`

	// Config loading flags (not serialized)
	RequireConfig bool `json:"-" mapstructure:"-" yaml:"-"`
}

Config contains configuration for the search extension.

func DefaultConfig

func DefaultConfig() Config

DefaultConfig returns default search configuration.

func (*Config) Validate

func (c *Config) Validate() error

Validate validates the configuration.

type ConfigOption

type ConfigOption func(*Config)

ConfigOption is a functional option for Config.

func WithAPIKey

func WithAPIKey(apiKey string) ConfigOption

WithAPIKey sets the API key.

func WithAuth

func WithAuth(username, password string) ConfigOption

WithAuth sets authentication credentials.

func WithConfig

func WithConfig(config Config) ConfigOption

WithConfig sets the complete config.

func WithDefaultLimit

func WithDefaultLimit(limit int) ConfigOption

WithDefaultLimit sets default result limit.

func WithDriver

func WithDriver(driver string) ConfigOption

WithDriver sets the driver.

func WithHosts

func WithHosts(hosts ...string) ConfigOption

WithHosts sets the hosts.

func WithMaxConnections

func WithMaxConnections(maxConns int) ConfigOption

WithMaxConnections sets max connections.

func WithMaxLimit

func WithMaxLimit(limit int) ConfigOption

WithMaxLimit sets maximum result limit.

func WithMetrics

func WithMetrics(enable bool) ConfigOption

WithMetrics enables metrics.

func WithRequireConfig

func WithRequireConfig(require bool) ConfigOption

WithRequireConfig requires config from ConfigManager.

func WithTLS

func WithTLS(certFile, keyFile, caFile string) ConfigOption

WithTLS enables TLS.

func WithTimeout

func WithTimeout(timeout time.Duration) ConfigOption

WithTimeout sets request timeout.

func WithTracing

func WithTracing(enable bool) ConfigOption

WithTracing enables tracing.

func WithURL

func WithURL(url string) ConfigOption

WithURL sets the URL.

type Document

type Document struct {
	ID     string         `json:"id"`
	Fields map[string]any `json:"fields"`
}

Document represents a searchable document.

type ElasticsearchSearch

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

ElasticsearchSearch implements Search interface for Elasticsearch.

func NewElasticsearchSearch

func NewElasticsearchSearch(config Config, logger forge.Logger, metrics forge.Metrics) (*ElasticsearchSearch, error)

NewElasticsearchSearch creates a new Elasticsearch search instance.

func (*ElasticsearchSearch) Autocomplete

Autocomplete returns Elasticsearch autocomplete results.

func (*ElasticsearchSearch) BulkIndex

func (s *ElasticsearchSearch) BulkIndex(ctx context.Context, index string, docs []Document) error

BulkIndex bulk indexes documents in Elasticsearch.

func (*ElasticsearchSearch) Connect

func (s *ElasticsearchSearch) Connect(ctx context.Context) error

Connect establishes connection to Elasticsearch.

func (*ElasticsearchSearch) CreateIndex

func (s *ElasticsearchSearch) CreateIndex(ctx context.Context, name string, schema IndexSchema) error

CreateIndex creates an Elasticsearch index.

func (*ElasticsearchSearch) Delete

func (s *ElasticsearchSearch) Delete(ctx context.Context, index string, id string) error

Delete deletes a document from Elasticsearch.

func (*ElasticsearchSearch) DeleteIndex

func (s *ElasticsearchSearch) DeleteIndex(ctx context.Context, name string) error

DeleteIndex deletes an Elasticsearch index.

func (*ElasticsearchSearch) Disconnect

func (s *ElasticsearchSearch) Disconnect(ctx context.Context) error

Disconnect closes the Elasticsearch connection.

func (*ElasticsearchSearch) Get

func (s *ElasticsearchSearch) Get(ctx context.Context, index string, id string) (*Document, error)

Get retrieves a document from Elasticsearch.

func (*ElasticsearchSearch) GetIndexInfo

func (s *ElasticsearchSearch) GetIndexInfo(ctx context.Context, name string) (*IndexInfo, error)

GetIndexInfo returns Elasticsearch index information.

func (*ElasticsearchSearch) Index

func (s *ElasticsearchSearch) Index(ctx context.Context, index string, doc Document) error

Index indexes a document in Elasticsearch.

func (*ElasticsearchSearch) ListIndexes

func (s *ElasticsearchSearch) ListIndexes(ctx context.Context) ([]string, error)

ListIndexes lists all Elasticsearch indexes.

func (*ElasticsearchSearch) Ping

Ping checks Elasticsearch health.

func (*ElasticsearchSearch) Search

Search performs an Elasticsearch search.

func (*ElasticsearchSearch) Stats

Stats returns Elasticsearch statistics.

func (*ElasticsearchSearch) Suggest

Suggest returns Elasticsearch suggestions.

func (*ElasticsearchSearch) Update

func (s *ElasticsearchSearch) Update(ctx context.Context, index string, id string, doc Document) error

Update updates a document in Elasticsearch.

type Extension

type Extension struct {
	*forge.BaseExtension
	// contains filtered or unexported fields
}

Extension implements forge.Extension for search functionality. The extension is now a lightweight facade that loads config and registers services. Service lifecycle is managed by Vessel, not by the extension.

func (*Extension) Health

func (e *Extension) Health(ctx context.Context) error

Health checks the extension health.

func (*Extension) Register

func (e *Extension) Register(app forge.App) error

Register registers the search extension with the app. This method now only loads configuration and registers service constructors. Service lifecycle (Start/Stop) is managed by Vessel.

func (*Extension) Start

func (e *Extension) Start(ctx context.Context) error

Start resolves and starts the search service, then marks the extension as started.

func (*Extension) Stop

func (e *Extension) Stop(ctx context.Context) error

Stop stops the search service and marks the extension as stopped.

type Facet

type Facet struct {
	Value string `json:"value"`
	Count int64  `json:"count"`
}

Facet represents a facet value.

type FacetingConfig

type FacetingConfig struct {
	MaxValues int    `json:"max_values"`
	Sort      string `json:"sort"` // count, name
}

FacetingConfig defines faceting options.

type FieldSchema

type FieldSchema struct {
	Name         string  `json:"name"`
	Type         string  `json:"type"` // text, keyword, integer, float, boolean, date, geo_point
	Required     bool    `json:"required"`
	Searchable   bool    `json:"searchable"`
	Filterable   bool    `json:"filterable"`
	Sortable     bool    `json:"sortable"`
	Faceted      bool    `json:"faceted"`
	Stored       bool    `json:"stored"`
	Index        bool    `json:"index"`
	Boost        float64 `json:"boost,omitempty"`
	Analyzer     string  `json:"analyzer,omitempty"`
	Format       string  `json:"format,omitempty"` // For dates
	Locale       string  `json:"locale,omitempty"`
	DefaultValue any     `json:"default_value,omitempty"`
}

FieldSchema defines a single field in the index.

type Filter

type Filter struct {
	Field    string `json:"field"`
	Operator string `json:"operator"` // =, !=, >, >=, <, <=, IN, NOT IN, BETWEEN, EXISTS
	Value    any    `json:"value"`
}

Filter represents a search filter.

type HighlightConfig

type HighlightConfig struct {
	PreTag  string `json:"pre_tag"`
	PostTag string `json:"post_tag"`
}

HighlightConfig defines highlighting options.

type Hit

type Hit struct {
	ID         string              `json:"id"`
	Score      float64             `json:"score"`
	Document   map[string]any      `json:"document"`
	Highlights map[string][]string `json:"highlights,omitempty"`
}

Hit represents a single search result.

type InMemorySearch

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

InMemorySearch implements Search interface with an in-memory store.

func NewInMemorySearch

func NewInMemorySearch(config Config, logger forge.Logger, metrics forge.Metrics) *InMemorySearch

NewInMemorySearch creates a new in-memory search instance.

func (*InMemorySearch) Autocomplete

func (s *InMemorySearch) Autocomplete(ctx context.Context, query AutocompleteQuery) (*AutocompleteResults, error)

Autocomplete returns autocomplete results.

func (*InMemorySearch) BulkIndex

func (s *InMemorySearch) BulkIndex(ctx context.Context, indexName string, docs []Document) error

BulkIndex adds or updates multiple documents.

func (*InMemorySearch) Connect

func (s *InMemorySearch) Connect(ctx context.Context) error

Connect establishes connection to the search backend. Connect is idempotent — calling it on an already-connected instance is a no-op.

func (*InMemorySearch) CreateIndex

func (s *InMemorySearch) CreateIndex(ctx context.Context, name string, schema IndexSchema) error

CreateIndex creates a new search index.

func (*InMemorySearch) Delete

func (s *InMemorySearch) Delete(ctx context.Context, indexName string, id string) error

Delete removes a document from the index.

func (*InMemorySearch) DeleteIndex

func (s *InMemorySearch) DeleteIndex(ctx context.Context, name string) error

DeleteIndex deletes a search index.

func (*InMemorySearch) Disconnect

func (s *InMemorySearch) Disconnect(ctx context.Context) error

Disconnect closes the connection to the search backend.

func (*InMemorySearch) Get

func (s *InMemorySearch) Get(ctx context.Context, indexName string, id string) (*Document, error)

Get retrieves a document by ID.

func (*InMemorySearch) GetIndexInfo

func (s *InMemorySearch) GetIndexInfo(ctx context.Context, name string) (*IndexInfo, error)

GetIndexInfo returns information about an index.

func (*InMemorySearch) Index

func (s *InMemorySearch) Index(ctx context.Context, indexName string, doc Document) error

Index adds or updates a document in the index.

func (*InMemorySearch) ListIndexes

func (s *InMemorySearch) ListIndexes(ctx context.Context) ([]string, error)

ListIndexes returns a list of all indexes.

func (*InMemorySearch) Ping

func (s *InMemorySearch) Ping(ctx context.Context) error

Ping checks if the search backend is responsive.

func (*InMemorySearch) Search

func (s *InMemorySearch) Search(ctx context.Context, query SearchQuery) (*SearchResults, error)

Search performs a search query.

func (*InMemorySearch) Stats

func (s *InMemorySearch) Stats(ctx context.Context) (*SearchStats, error)

Stats returns search engine statistics.

func (*InMemorySearch) Suggest

func (s *InMemorySearch) Suggest(ctx context.Context, query SuggestQuery) (*SuggestResults, error)

Suggest returns search suggestions.

func (*InMemorySearch) Update

func (s *InMemorySearch) Update(ctx context.Context, indexName string, id string, doc Document) error

Update updates a document in the index.

type IndexInfo

type IndexInfo struct {
	Name          string      `json:"name"`
	DocumentCount int64       `json:"document_count"`
	IndexSize     int64       `json:"index_size"`
	CreatedAt     time.Time   `json:"created_at"`
	UpdatedAt     time.Time   `json:"updated_at"`
	Schema        IndexSchema `json:"schema"`
}

IndexInfo contains metadata about an index.

type IndexSchema

type IndexSchema struct {
	Fields       []FieldSchema       `json:"fields"`
	Settings     map[string]any      `json:"settings,omitempty"`
	Synonyms     []Synonym           `json:"synonyms,omitempty"`
	StopWords    []string            `json:"stop_words,omitempty"`
	Analyzers    map[string]Analyzer `json:"analyzers,omitempty"`
	Ranking      *RankingConfig      `json:"ranking,omitempty"`
	Faceting     *FacetingConfig     `json:"faceting,omitempty"`
	Highlighting *HighlightConfig    `json:"highlighting,omitempty"`
}

IndexSchema defines the structure of a search index.

type MeilisearchSearch

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

MeilisearchSearch implements Search interface for Meilisearch.

func NewMeilisearchSearch

func NewMeilisearchSearch(config Config, logger forge.Logger, metrics forge.Metrics) (*MeilisearchSearch, error)

NewMeilisearchSearch creates a new Meilisearch search instance.

func (*MeilisearchSearch) Autocomplete

Autocomplete returns Meilisearch autocomplete results.

func (*MeilisearchSearch) BulkIndex

func (s *MeilisearchSearch) BulkIndex(ctx context.Context, index string, docs []Document) error

BulkIndex bulk indexes documents in Meilisearch.

func (*MeilisearchSearch) Connect

func (s *MeilisearchSearch) Connect(ctx context.Context) error

Connect establishes connection to Meilisearch.

func (*MeilisearchSearch) CreateIndex

func (s *MeilisearchSearch) CreateIndex(ctx context.Context, name string, schema IndexSchema) error

CreateIndex creates a Meilisearch index.

func (*MeilisearchSearch) Delete

func (s *MeilisearchSearch) Delete(ctx context.Context, index string, id string) error

Delete deletes a document from Meilisearch.

func (*MeilisearchSearch) DeleteIndex

func (s *MeilisearchSearch) DeleteIndex(ctx context.Context, name string) error

DeleteIndex deletes a Meilisearch index.

func (*MeilisearchSearch) Disconnect

func (s *MeilisearchSearch) Disconnect(ctx context.Context) error

Disconnect closes the Meilisearch connection.

func (*MeilisearchSearch) Get

func (s *MeilisearchSearch) Get(ctx context.Context, index string, id string) (*Document, error)

Get retrieves a document from Meilisearch.

func (*MeilisearchSearch) GetIndexInfo

func (s *MeilisearchSearch) GetIndexInfo(ctx context.Context, name string) (*IndexInfo, error)

GetIndexInfo returns Meilisearch index information.

func (*MeilisearchSearch) Index

func (s *MeilisearchSearch) Index(ctx context.Context, index string, doc Document) error

Index indexes a document in Meilisearch.

func (*MeilisearchSearch) ListIndexes

func (s *MeilisearchSearch) ListIndexes(ctx context.Context) ([]string, error)

ListIndexes lists all Meilisearch indexes.

func (*MeilisearchSearch) Ping

func (s *MeilisearchSearch) Ping(ctx context.Context) error

Ping checks Meilisearch health.

func (*MeilisearchSearch) Search

func (s *MeilisearchSearch) Search(ctx context.Context, query SearchQuery) (*SearchResults, error)

Search performs a Meilisearch search.

func (*MeilisearchSearch) Stats

Stats returns Meilisearch statistics.

func (*MeilisearchSearch) Suggest

Suggest returns Meilisearch suggestions.

func (*MeilisearchSearch) Update

func (s *MeilisearchSearch) Update(ctx context.Context, index string, id string, doc Document) error

Update updates a document in Meilisearch.

type RankingConfig

type RankingConfig struct {
	Rules   []string           `json:"rules"`
	Weights map[string]float64 `json:"weights,omitempty"`
}

RankingConfig defines ranking rules.

type Search interface {
	// Connection management
	Connect(ctx context.Context) error
	Disconnect(ctx context.Context) error
	Ping(ctx context.Context) error

	// Index management
	CreateIndex(ctx context.Context, name string, schema IndexSchema) error
	DeleteIndex(ctx context.Context, name string) error
	ListIndexes(ctx context.Context) ([]string, error)
	GetIndexInfo(ctx context.Context, name string) (*IndexInfo, error)

	// Document operations
	Index(ctx context.Context, index string, doc Document) error
	BulkIndex(ctx context.Context, index string, docs []Document) error
	Get(ctx context.Context, index string, id string) (*Document, error)
	Delete(ctx context.Context, index string, id string) error
	Update(ctx context.Context, index string, id string, doc Document) error

	// Search operations
	Search(ctx context.Context, query SearchQuery) (*SearchResults, error)
	Suggest(ctx context.Context, query SuggestQuery) (*SuggestResults, error)
	Autocomplete(ctx context.Context, query AutocompleteQuery) (*AutocompleteResults, error)

	// Analytics
	Stats(ctx context.Context) (*SearchStats, error)
}

Search represents a unified search interface supporting multiple backends.

func GetSearch

func GetSearch(c forge.Container) (Search, error)

GetSearch retrieves the Search service from the container. Returns error if not found or type assertion fails.

func GetSearchFromApp

func GetSearchFromApp(app forge.App) (Search, error)

GetSearchFromApp retrieves the Search service from the app. Returns error if not found or type assertion fails.

func MustGetSearch

func MustGetSearch(c forge.Container) Search

MustGetSearch retrieves the Search service from the container. Panics if not found or type assertion fails.

func MustGetSearchFromApp

func MustGetSearchFromApp(app forge.App) Search

MustGetSearchFromApp retrieves the Search service from the app. Panics if not found or type assertion fails.

type SearchQuery

type SearchQuery struct {
	Index           string             `json:"index"`
	Query           string             `json:"query"`
	Filters         []Filter           `json:"filters,omitempty"`
	Sort            []SortField        `json:"sort,omitempty"`
	Facets          []string           `json:"facets,omitempty"`
	Offset          int                `json:"offset,omitempty"`
	Limit           int                `json:"limit,omitempty"`
	Highlight       bool               `json:"highlight,omitempty"`
	HighlightFields []string           `json:"highlight_fields,omitempty"`
	Fields          []string           `json:"fields,omitempty"` // Fields to return
	MinScore        float64            `json:"min_score,omitempty"`
	BoostFields     map[string]float64 `json:"boost_fields,omitempty"`
	FuzzyLevel      int                `json:"fuzzy_level,omitempty"` // 0=exact, 1-2=fuzzy
	Options         map[string]any     `json:"options,omitempty"`
}

SearchQuery represents a search request.

type SearchResults

type SearchResults struct {
	Hits           []Hit              `json:"hits"`
	Total          int64              `json:"total"`
	Offset         int                `json:"offset"`
	Limit          int                `json:"limit"`
	ProcessingTime time.Duration      `json:"processing_time_ms"`
	Facets         map[string][]Facet `json:"facets,omitempty"`
	Query          string             `json:"query"`
	Exhaustive     bool               `json:"exhaustive"`
}

SearchResults contains search response.

type SearchService

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

SearchService wraps a Search implementation and provides lifecycle management. It implements vessel's di.Service interface so Vessel can manage its lifecycle.

func NewSearchService

func NewSearchService(config Config, logger forge.Logger, metrics forge.Metrics) (*SearchService, error)

NewSearchService creates a new search service with the given configuration. This is the constructor that will be registered with the DI container.

func (*SearchService) Autocomplete

func (s *SearchService) Autocomplete(ctx context.Context, query AutocompleteQuery) (*AutocompleteResults, error)

func (*SearchService) Backend

func (s *SearchService) Backend() Search

Backend returns the underlying search implementation. This allows other services to use the search directly.

func (*SearchService) BulkIndex

func (s *SearchService) BulkIndex(ctx context.Context, index string, docs []Document) error

func (*SearchService) Connect

func (s *SearchService) Connect(ctx context.Context) error

func (*SearchService) CreateIndex

func (s *SearchService) CreateIndex(ctx context.Context, name string, schema IndexSchema) error

func (*SearchService) Delete

func (s *SearchService) Delete(ctx context.Context, index string, id string) error

func (*SearchService) DeleteIndex

func (s *SearchService) DeleteIndex(ctx context.Context, name string) error

func (*SearchService) Disconnect

func (s *SearchService) Disconnect(ctx context.Context) error

func (*SearchService) Get

func (s *SearchService) Get(ctx context.Context, index string, id string) (*Document, error)

func (*SearchService) GetIndexInfo

func (s *SearchService) GetIndexInfo(ctx context.Context, name string) (*IndexInfo, error)

func (*SearchService) Health

func (s *SearchService) Health(ctx context.Context) error

Health checks if the search service is healthy. This is called by the health check system.

func (*SearchService) Index

func (s *SearchService) Index(ctx context.Context, index string, doc Document) error

func (*SearchService) ListIndexes

func (s *SearchService) ListIndexes(ctx context.Context) ([]string, error)

func (*SearchService) Name

func (s *SearchService) Name() string

Name returns the service name for Vessel's lifecycle management.

func (*SearchService) Ping

func (s *SearchService) Ping(ctx context.Context) error

func (*SearchService) Search

func (s *SearchService) Search(ctx context.Context, query SearchQuery) (*SearchResults, error)

func (*SearchService) Start

func (s *SearchService) Start(ctx context.Context) error

Start starts the search service by connecting to the backend. This is called automatically by Vessel during container.Start().

func (*SearchService) Stats

func (s *SearchService) Stats(ctx context.Context) (*SearchStats, error)

func (*SearchService) Stop

func (s *SearchService) Stop(ctx context.Context) error

Stop stops the search service by disconnecting from the backend. This is called automatically by Vessel during container.Stop().

func (*SearchService) Suggest

func (s *SearchService) Suggest(ctx context.Context, query SuggestQuery) (*SuggestResults, error)

func (*SearchService) Update

func (s *SearchService) Update(ctx context.Context, index string, id string, doc Document) error

type SearchStats

type SearchStats struct {
	IndexCount    int64          `json:"index_count"`
	DocumentCount int64          `json:"document_count"`
	TotalSize     int64          `json:"total_size"`
	Queries       int64          `json:"queries"`
	AvgLatency    time.Duration  `json:"avg_latency_ms"`
	Uptime        time.Duration  `json:"uptime"`
	Version       string         `json:"version"`
	Extra         map[string]any `json:"extra,omitempty"`
}

SearchStats contains search engine statistics.

type SortField

type SortField struct {
	Field string `json:"field"`
	Order string `json:"order"` // asc, desc
}

SortField defines sorting.

type SuggestQuery

type SuggestQuery struct {
	Index string `json:"index"`
	Query string `json:"query"`
	Field string `json:"field"`
	Limit int    `json:"limit,omitempty"`
	Fuzzy bool   `json:"fuzzy,omitempty"`
}

SuggestQuery represents a suggestion request.

type SuggestResults

type SuggestResults struct {
	Suggestions    []Suggestion  `json:"suggestions"`
	ProcessingTime time.Duration `json:"processing_time_ms"`
}

SuggestResults contains suggestion response.

type Suggestion

type Suggestion struct {
	Text  string  `json:"text"`
	Score float64 `json:"score"`
}

Suggestion represents a single suggestion.

type Synonym

type Synonym struct {
	Terms []string `json:"terms"`
}

Synonym defines term synonyms.

type TypesenseSearch

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

TypesenseSearch implements Search interface for Typesense.

func NewTypesenseSearch

func NewTypesenseSearch(config Config, logger forge.Logger, metrics forge.Metrics) (*TypesenseSearch, error)

NewTypesenseSearch creates a new Typesense search instance.

func (*TypesenseSearch) Autocomplete

Autocomplete returns Typesense autocomplete results.

func (*TypesenseSearch) BulkIndex

func (s *TypesenseSearch) BulkIndex(ctx context.Context, index string, docs []Document) error

BulkIndex bulk indexes documents in Typesense.

func (*TypesenseSearch) Connect

func (s *TypesenseSearch) Connect(ctx context.Context) error

Connect establishes connection to Typesense.

func (*TypesenseSearch) CreateIndex

func (s *TypesenseSearch) CreateIndex(ctx context.Context, name string, schema IndexSchema) error

CreateIndex creates a Typesense collection.

func (*TypesenseSearch) Delete

func (s *TypesenseSearch) Delete(ctx context.Context, index string, id string) error

Delete deletes a document from Typesense.

func (*TypesenseSearch) DeleteIndex

func (s *TypesenseSearch) DeleteIndex(ctx context.Context, name string) error

DeleteIndex deletes a Typesense collection.

func (*TypesenseSearch) Disconnect

func (s *TypesenseSearch) Disconnect(ctx context.Context) error

Disconnect closes the Typesense connection.

func (*TypesenseSearch) Get

func (s *TypesenseSearch) Get(ctx context.Context, index string, id string) (*Document, error)

Get retrieves a document from Typesense.

func (*TypesenseSearch) GetIndexInfo

func (s *TypesenseSearch) GetIndexInfo(ctx context.Context, name string) (*IndexInfo, error)

GetIndexInfo returns Typesense collection information.

func (*TypesenseSearch) Index

func (s *TypesenseSearch) Index(ctx context.Context, index string, doc Document) error

Index indexes a document in Typesense.

func (*TypesenseSearch) ListIndexes

func (s *TypesenseSearch) ListIndexes(ctx context.Context) ([]string, error)

ListIndexes lists all Typesense collections.

func (*TypesenseSearch) Ping

func (s *TypesenseSearch) Ping(ctx context.Context) error

Ping checks Typesense health.

func (*TypesenseSearch) Search

func (s *TypesenseSearch) Search(ctx context.Context, query SearchQuery) (*SearchResults, error)

Search performs a Typesense search.

func (*TypesenseSearch) Stats

func (s *TypesenseSearch) Stats(ctx context.Context) (*SearchStats, error)

Stats returns Typesense statistics.

func (*TypesenseSearch) Suggest

func (s *TypesenseSearch) Suggest(ctx context.Context, query SuggestQuery) (*SuggestResults, error)

Suggest returns Typesense suggestions.

func (*TypesenseSearch) Update

func (s *TypesenseSearch) Update(ctx context.Context, index string, id string, doc Document) error

Update updates a document in Typesense.

Jump to

Keyboard shortcuts

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