Search

Features

Search extension capabilities and backend details

Unified Search Interface

All backends implement the same Search interface, making application code backend-agnostic:

type Search interface {
    Connect(ctx context.Context) error
    Disconnect(ctx context.Context) error
    Ping(ctx context.Context) error
    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)
    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(ctx context.Context, query SearchQuery) (*SearchResults, error)
    Suggest(ctx context.Context, query SuggestQuery) (*SuggestResults, error)
    Autocomplete(ctx context.Context, query AutocompleteQuery) (*AutocompleteResults, error)
    Stats(ctx context.Context) (*SearchStats, error)
}

Multiple Backends

DriverStatusBacking StoreBest For
inmemoryImplementedGo maps + in-process matchingDevelopment, testing, small datasets
elasticsearchStubElasticsearch clusterProduction full-text search at scale
meilisearchStubMeilisearch serverFast typo-tolerant search
typesenseStubTypesense serverLow-latency search with API key auth

Index Management

Create indexes with rich schema definitions that include field types, searchable/filterable/sortable flags, analyzers, synonyms, stop words, and ranking rules:

s.CreateIndex(ctx, "articles", search.IndexSchema{
    Fields: []search.FieldSchema{
        {Name: "title", Type: "text", Searchable: true, Sortable: true, Boost: 2.0},
        {Name: "body", Type: "text", Searchable: true},
        {Name: "author", Type: "keyword", Filterable: true, Faceted: true},
        {Name: "published_at", Type: "date", Sortable: true, Format: "2006-01-02"},
        {Name: "views", Type: "integer", Sortable: true},
    },
    Synonyms: []search.Synonym{
        {Terms: []string{"laptop", "notebook", "portable computer"}},
    },
    StopWords: []string{"the", "a", "an", "is"},
    Ranking: &search.RankingConfig{
        Rules:   []string{"typo", "words", "proximity", "attribute", "sort", "exactness"},
        Weights: map[string]float64{"title": 2.0, "body": 1.0},
    },
})

Supported field types: text, keyword, integer, float, boolean, date, geo_point.

Document Operations

Documents are represented as ID + Fields map[string]any:

// Single document
s.Index(ctx, "articles", search.Document{
    ID:     "article-1",
    Fields: map[string]any{"title": "Getting Started", "body": "...", "author": "Alice"},
})

// Bulk indexing (configurable batch size via BulkSize config)
s.BulkIndex(ctx, "articles", []search.Document{doc1, doc2, doc3})

// Retrieve by ID
doc, _ := s.Get(ctx, "articles", "article-1")

// Update
s.Update(ctx, "articles", "article-1", search.Document{
    ID:     "article-1",
    Fields: map[string]any{"title": "Updated Title", "body": "...", "author": "Alice"},
})

// Delete
s.Delete(ctx, "articles", "article-1")

Query with filters, sorting, facets, highlighting, minimum score thresholds, field boosting, and fuzzy matching:

results, _ := s.Search(ctx, search.SearchQuery{
    Index:           "articles",
    Query:           "distributed systems",
    Filters:         []search.Filter{
        {Field: "author", Operator: "=", Value: "Alice"},
        {Field: "views", Operator: ">=", Value: 100},
    },
    Sort:            []search.SortField{{Field: "published_at", Order: "desc"}},
    Facets:          []string{"author"},
    Highlight:       true,
    HighlightFields: []string{"title", "body"},
    BoostFields:     map[string]float64{"title": 3.0},
    FuzzyLevel:      1,
    MinScore:        0.5,
    Offset:          0,
    Limit:           20,
})

Supported filter operators: =, !=, >, >=, <, <=, IN, NOT IN, BETWEEN, EXISTS.

Search Results

Results include total count, processing time, exhaustiveness flag, per-hit scores, highlight fragments, and facet counts:

fmt.Printf("Found %d results in %v\n", results.Total, results.ProcessingTime)
for _, hit := range results.Hits {
    fmt.Printf("  %s (score: %.2f) %v\n", hit.ID, hit.Score, hit.Document)
    for field, fragments := range hit.Highlights {
        fmt.Printf("    %s: %v\n", field, fragments)
    }
}
for facet, values := range results.Facets {
    for _, v := range values {
        fmt.Printf("  %s: %s (%d)\n", facet, v.Value, v.Count)
    }
}

Suggestions and Autocomplete

Dedicated query types for search-as-you-type experiences:

// Suggestions with fuzzy matching
suggestions, _ := s.Suggest(ctx, search.SuggestQuery{
    Index: "articles",
    Query: "distrbuited",  // typo
    Field: "title",
    Limit: 5,
    Fuzzy: true,
})

// Autocomplete
completions, _ := s.Autocomplete(ctx, search.AutocompleteQuery{
    Index: "articles",
    Query: "dist",
    Field: "title",
    Limit: 10,
})

Connection Resilience

  • Connection pooling -- configurable MaxConnections, MaxIdleConnections, and KeepAlive for backend connections.
  • Retry with backoff -- MaxRetries with RetryBackoff and optional RetryOnTimeout for transient failures.
  • Timeouts -- separate ConnectTimeout and RequestTimeout values.

Security

  • TLS -- connect to backends over TLS with EnableTLS, custom TLSCertFile, TLSKeyFile, TLSCAFile, or InsecureSkipVerify.
  • Authentication -- Username/Password for Elasticsearch, APIKey for Meilisearch/Typesense.

Observability

  • Metrics -- EnableMetrics integrates with the Forge metrics system.
  • Tracing -- EnableTracing for distributed tracing integration.
  • Stats -- Stats() returns index count, document count, total size, query count, average latency, and uptime.

Sentinel Errors

ErrorMeaning
ErrNotConnectedBackend is not connected
ErrAlreadyConnectedAttempted to connect when already connected
ErrIndexNotFoundRequested index does not exist
ErrIndexAlreadyExistsIndex with that name already exists
ErrDocumentNotFoundDocument ID not found in the index
ErrInvalidQueryMalformed or invalid search query
ErrInvalidSchemaInvalid index schema definition
ErrConnectionFailedFailed to establish connection to backend
ErrTimeoutOperation exceeded timeout
ErrInvalidConfigInvalid configuration values
ErrUnsupportedDriverConfigured driver is not recognized
ErrOperationFailedGeneric operation failure

How is this guide?

On this page