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)
| Field | Required | Description |
|---|---|---|
ID | Yes | Unique identifier for the vector (non-empty string) |
Vector | Yes | Slice of float32 representing the embedding |
Meta | No | Map for storing additional information |
Filter | No | Key-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:
| Parameter | Description |
|---|---|
vector | Query vector (must match index dimension) |
sparseIndices | Sparse query positions for hybrid search (nil for dense-only) |
sparseValues | Sparse query weights for hybrid search (nil for dense-only) |
k | Number of results to return (default: 10, max: 512) |
filter | Optional filter criteria (map[string]interface{}) |
ef | Search quality parameter (default: 128, max: 1024) |
includeVectors | Include 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
| Operator | Description | Example |
|---|---|---|
$eq | Exact match | map[string]interface{}{"status": map[string]interface{}{"$eq": "published"}} |
$in | Match any in list | map[string]interface{}{"tags": map[string]interface{}{"$in": []string{"ai", "ml"}}} |
$range | Numeric 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 Search
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
nilforsparseIndicesandsparseValues - Sparse only: Pass
nilforvectorand 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 searchChoosing Precision:
| Precision | Constant | Memory Usage | Use Case |
|---|---|---|---|
| FP32 | PrecisionFloat32 | Highest | Maximum accuracy |
| FP16 | PrecisionFloat16 | ~50% less | Good accuracy, lower memory |
| INT16 | PrecisionInt16D | Optimized | Quantized accuracy |
| INT8 | PrecisionInt8D | ~75% less | Balanced performance (recommended) |
| Binary | PrecisionBinary | Minimum | Fast, 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
| Method | Description |
|---|---|
EndeeClient(token string) *Endee | Initialize client with optional API token |
CreateIndex(name, dimension, spaceType, M, efCon, precision, version, sparseDim) error | Create a new vector index |
CreateIndexWithContext(ctx, ...) error | Create index with context support |
ListIndexes() ([]interface{}, error) | List all indexes in workspace |
ListIndexesWithContext(ctx) ([]interface{}, error) | List indexes with context support |
DeleteIndex(name string) error | Delete a vector index |
DeleteIndexWithContext(ctx, name) error | Delete 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
| Method | Description |
|---|---|
Upsert(vectors []VectorItem) error | Insert or update vectors (max 1000 per batch) |
UpsertWithContext(ctx, vectors) error | Upsert 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() string | Get index statistics and configuration |
String() string | Get string representation of index |