Skip to Content
Go SDKUsage

Go SDK Usage

This guide covers the core operations for working with vectors in Endee: upserting, querying, and deleting data.

Setting Up Your Domain

The Endee client allows you to configure a custom domain URL and port (default port is 8080):

import "github.com/endee-io/endee-go-client" // Initialize client client := endee.EndeeClient("") // Set custom base URL for non-default port client.BaseUrl = "http://0.0.0.0:8081/api/v1"

Set BaseUrl when running on a non-default port.

Upserting Vectors

The index.Upsert() method adds or updates vectors in an existing index.

import "github.com/endee-io/endee-go-client" client := endee.EndeeClient("") index, err := client.GetIndex("my_index") if err != nil { log.Fatal(err) } vectors := []endee.VectorItem{ { ID: "vec1", Vector: []float32{0.1, 0.2, 0.3 /* ... */}, Meta: map[string]interface{}{ "title": "First document", "group": 10, }, Filter: map[string]interface{}{ "category": "tech", "group": 10, }, }, { ID: "vec2", Vector: []float32{0.3, 0.4, 0.5 /* ... */}, Meta: map[string]interface{}{ "title": "Second document", }, Filter: map[string]interface{}{ "category": "science", }, }, } err = index.Upsert(vectors) if err != nil { log.Fatal(err) }

VectorItem Fields: (see VectorItem)

FieldRequiredDescription
IDYesUnique identifier for the vector (non-empty string)
VectorYesSlice of float32 representing the embedding
MetaNoMap for storing additional information
FilterNoKey-value pairs for filtering during queries

Maximum 1,000 vectors per upsert call. Vector dimension must match the index dimension. IDs must be unique within a single upsert batch.

Querying the Index

The index.Query() method performs a similarity search using a query vector.

queryVector := []float32{0.15, 0.25 /* ... */} results, err := index.Query( queryVector, // query vector nil, // sparse indices (nil for dense-only) nil, // sparse values (nil for dense-only) 5, // top_k - number of results (max 512) nil, // filter (optional) 128, // ef - runtime parameter (max 1024) true, // include_vectors ) if err != nil { log.Fatal(err) } for _, result := range results { fmt.Printf("ID: %s, Similarity: %.3f\n", result.ID, result.Similarity) fmt.Printf("Distance: %.3f\n", result.Distance) fmt.Printf("Meta: %+v\n", result.Meta) }

Query Parameters:

ParameterDescription
vectorQuery vector (must match index dimension)
sparseIndicesSparse query positions for hybrid search (nil for dense-only)
sparseValuesSparse query weights for hybrid search (nil for dense-only)
kNumber of results to return (default: 10, max: 512)
filterOptional filter criteria (map[string]interface{})
efSearch quality parameter (default: 128, max: 1024)
includeVectorsInclude vector data in results (default: false)

Results are returned as a slice of QueryResult structs.

Filtered Querying

Use the filter parameter to restrict results based on filter conditions. All filters are combined with logical AND.

filter := map[string]interface{}{ "category": map[string]interface{}{ "$eq": "tech", }, "score": map[string]interface{}{ "$range": []int{80, 100}, }, } results, err := index.Query(queryVector, nil, nil, 5, filter, 128, true) if err != nil { log.Fatal(err) }

Filtering Operators

OperatorDescriptionExample
$eqExact matchmap[string]interface{}{"status": map[string]interface{}{"$eq": "published"}}
$inMatch any in listmap[string]interface{}{"tags": map[string]interface{}{"$in": []string{"ai", "ml"}}}
$rangeNumeric range (inclusive)map[string]interface{}{"score": map[string]interface{}{"$range": []int{70, 95}}}

The $range operator supports values within [0 – 999]. Normalize larger values before upserting.

Filter Examples

// Equal operator - exact match filter := map[string]interface{}{ "status": map[string]interface{}{ "$eq": "published", }, } // In operator - match any value in list filter = map[string]interface{}{ "tags": map[string]interface{}{ "$in": []string{"ai", "ml", "data-science"}, }, } // Range operator - numeric range (inclusive) filter = map[string]interface{}{ "score": map[string]interface{}{ "$range": []int{70, 95}, }, } // Combined filters (AND logic) filter = map[string]interface{}{ "status": map[string]interface{}{ "$eq": "published", }, "tags": map[string]interface{}{ "$in": []string{"ai", "ml"}, }, "score": map[string]interface{}{ "$range": []int{80, 100}, }, }

Hybrid indexes combine dense and sparse vector search. Create a hybrid index by specifying sparseDim:

err := client.CreateIndex( "hybrid_index", 384, "cosine", 16, 128, endee.PrecisionInt8D, nil, 30000, )

Upserting Hybrid Vectors

The Go client does not have separate sparse fields on the VectorItem struct. To upsert hybrid vectors, include your sparse data alongside the dense vector in the upsert call.

Querying Hybrid Index

Provide both dense and sparse query vectors:

queryVector := []float32{0.15, 0.25 /* ... */} sparseIndices := []int{10, 100, 300} sparseValues := []float64{0.7, 0.5, 0.4} results, err := index.Query( queryVector, // dense query vector sparseIndices, // sparse query positions sparseValues, // sparse query weights 5, // top_k nil, // filter 128, // ef false, // include_vectors ) if err != nil { log.Fatal(err) } for _, item := range results { fmt.Printf("ID: %s, Similarity: %.3f\n", item.ID, item.Similarity) }

You can also query with:

  • Dense only: Pass nil for sparseIndices and sparseValues
  • Sparse only: Pass nil for vector and provide sparse parameters
  • Hybrid: Provide all three for combined results

Deletion Methods

Delete Vector by ID

result, err := index.DeleteVector("vec1") if err != nil { log.Fatal(err) } fmt.Println(result)

Delete Vector by Filter

Delete all vectors matching specific filters:

filter := map[string]interface{}{ "category": map[string]interface{}{ "$eq": "tech", }, } result, err := index.DeleteVectorByFilter(filter) if err != nil { log.Fatal(err) }

Delete Hybrid Vectors

For hybrid indexes, use the dedicated hybrid deletion methods:

// Delete hybrid vector by ID result, err := index.DeleteHybridVectorById("vec1") // Delete hybrid vectors by filter result, err = index.DeleteHybridVectorByFilter(filter)

Delete Index

err := client.DeleteIndex("my_index") if err != nil { log.Fatal(err) }

Deletion operations are irreversible.

Additional Operations

Get Vector by ID

vector, err := index.GetVector("vec1") if err != nil { log.Fatal(err) } fmt.Printf("ID: %s\n", vector.ID) fmt.Printf("Meta: %+v\n", vector.Meta) fmt.Printf("Vector: %v\n", vector.Vector)

Get Index Info

info := index.GetInfo() fmt.Println(info)

Context Support

All operations support Go’s context.Context for cancellation and timeouts:

import ( "context" "time" ) // Create context with timeout ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() // Use context with operations err := client.CreateIndexWithContext(ctx, "my_index", 768, "cosine", 16, 128, endee.PrecisionFloat32, nil, 0) indexes, err := client.ListIndexesWithContext(ctx) index, err := client.GetIndexWithContext(ctx, "my_index") err = index.UpsertWithContext(ctx, vectors) results, err := index.QueryWithContext(ctx, queryVector, nil, nil, 10, nil, 128, false) err = client.DeleteIndexWithContext(ctx, "my_index")

Use context-aware methods when you need request cancellation, deadlines, or timeout control.

Precision Options

Endee supports different quantization precision levels via precision constants:

endee.PrecisionFloat32 // 32-bit float - highest precision endee.PrecisionFloat16 // 16-bit float - good balance endee.PrecisionInt16D // 16-bit integer quantization endee.PrecisionInt8D // 8-bit integer quantization - balanced performance endee.PrecisionBinary // 1-bit binary - smallest storage, fastest search

Choosing Precision:

PrecisionConstantMemory UsageUse Case
FP32PrecisionFloat32HighestMaximum accuracy
FP16PrecisionFloat16~50% lessGood accuracy, lower memory
INT16PrecisionInt16DOptimizedQuantized accuracy
INT8PrecisionInt8D~75% lessBalanced performance (recommended)
BinaryPrecisionBinaryMinimumFast, low-memory keyword-like search

See the Types Reference for complete details.

Error Handling

The Go SDK returns standard Go errors. Handle them using pattern matching:

import "strings" err := client.CreateIndex("test", 768, "cosine", 16, 128, endee.PrecisionFloat32, nil, 0) if err != nil { switch { case strings.Contains(err.Error(), "already exists"): fmt.Println("Index already exists, continuing...") case strings.Contains(err.Error(), "invalid index name"): fmt.Println("Invalid index name format") case strings.Contains(err.Error(), "dimension cannot be greater"): fmt.Println("Dimension too large") default: log.Fatal("Unexpected error:", err) } }

API Reference

Endee Client

MethodDescription
EndeeClient(token string) *EndeeInitialize client with optional API token
CreateIndex(name, dimension, spaceType, M, efCon, precision, version, sparseDim) errorCreate a new vector index
CreateIndexWithContext(ctx, ...) errorCreate index with context support
ListIndexes() ([]interface{}, error)List all indexes in workspace
ListIndexesWithContext(ctx) ([]interface{}, error)List indexes with context support
DeleteIndex(name string) errorDelete a vector index
DeleteIndexWithContext(ctx, name) errorDelete index with context support
GetIndex(name string) (*Index, error)Get reference to a vector index
GetIndexWithContext(ctx, name) (*Index, error)Get index with context support

Index Operations

MethodDescription
Upsert(vectors []VectorItem) errorInsert or update vectors (max 1000 per batch)
UpsertWithContext(ctx, vectors) errorUpsert with context support
Query(vector, sparseIndices, sparseValues, k, filter, ef, includeVectors) ([]QueryResult, error)Search for similar vectors
QueryWithContext(ctx, ...) ([]QueryResult, error)Query with context support
DeleteVectorById(id string) (string, error)Delete a vector by ID
DeleteVectorByIdWithContext(ctx, id) (string, error)Delete vector with context support
DeleteVectorByFilter(filter) (string, error)Delete vectors matching a filter
DeleteVectorByFilterWithContext(ctx, filter) (string, error)Delete by filter with context support
DeleteHybridVectorById(id string) (string, error)Delete a hybrid vector by ID
DeleteHybridVectorByIdWithContext(ctx, id) (string, error)Delete hybrid vector with context support
DeleteHybridVectorByFilter(filter) (string, error)Delete hybrid vectors matching a filter
DeleteHybridVectorByFilterWithContext(ctx, filter) (string, error)Delete hybrid by filter with context support
GetVector(id string) (VectorItem, error)Get a specific vector by ID
GetVectorWithContext(ctx, id) (VectorItem, error)Get vector with context support
GetInfo() stringGet index statistics and configuration
String() stringGet string representation of index