Skip to content

Quick Start

Ready to start slinging vectors at lightning speed? Let's get you up and running with Quiver in just a few minutes! ⚡

The 30-Second Version

package main

import (
    "fmt"
    "github.com/TFMV/quiver"
    "go.uber.org/zap"
)

func main() {
    // Create a logger
    logger, _ := zap.NewDevelopment()

    // Initialize Quiver
    idx, _ := quiver.New(quiver.Config{
        Dimension: 128,
        StoragePath: "./quiver.db",
    }, logger)
    defer idx.Close()

    // Add a vector
    vector := []float32{0.1, 0.2, 0.3, /* ... */}
    idx.Add(1, vector, map[string]interface{}{
        "category": "example",
        "name": "first vector",
    })

    // Search for similar vectors
    results, _ := idx.Search(vector, 10, 1, 10)
    fmt.Println("Found:", results[0].ID, results[0].Distance)
}

Step-by-Step Guide

1. Initialize Quiver

First, you need to create a Quiver index. This is where all your vectors and metadata will be stored.

// Create a logger (Quiver uses zap for logging)
logger, _ := zap.NewDevelopment()

// Configure Quiver
config := quiver.Config{
    Dimension:       128,    // Dimension of your vectors
    StoragePath:     "./data/quiver.db", // Where to store the data
    Distance:        quiver.Cosine,      // Distance metric (Cosine or L2)
    MaxElements:     1000000, // Maximum number of vectors
    HNSWM:           16,      // HNSW hyperparameter M
    HNSWEfConstruct: 200,     // HNSW construction quality
    HNSWEfSearch:    100,     // HNSW search quality
    BatchSize:       1000,    // Batch size for insertions
}

// Create the index
idx, err := quiver.New(config, logger)
if err != nil {
    panic(err)
}
defer idx.Close() // Don't forget to close when done!

2. Add Vectors

Now let's add some vectors to the index. Each vector needs:

  • A unique ID
  • The vector data (a slice of float32)
  • Optional metadata (a map of string to interface{})
// Create a vector (this would typically come from your embedding model)
vector := []float32{0.1, 0.2, 0.3, /* ... and so on for your dimension */}

// Add it to the index with metadata
err = idx.Add(1, vector, map[string]interface{}{
    "category": "science",
    "name": "black hole",
    "tags": []string{"astronomy", "physics"},
})
if err != nil {
    panic(err)
}

// Add more vectors
idx.Add(2, []float32{0.2, 0.3, 0.4, /* ... */}, map[string]interface{}{
    "category": "science",
    "name": "quantum mechanics",
    "tags": []string{"physics", "quantum"},
})

3. Search for Similar Vectors

The moment you've been waiting for - searching for similar vectors!

// Create a query vector
queryVector := []float32{0.15, 0.25, 0.35, /* ... */}

// Search for the 5 most similar vectors
results, err := idx.Search(queryVector, 5, 1, 10)
if err != nil {
    panic(err)
}

// Print the results
for i, result := range results {
    fmt.Printf("%d. ID: %d, Distance: %.4f, Name: %s\n", 
        i+1, result.ID, result.Distance, result.Metadata["name"])
}

4. Hybrid Search (Vector + Metadata)

One of Quiver's superpowers is combining vector search with metadata filtering:

// Search for similar vectors that match a metadata filter
results, err := idx.SearchWithFilter(queryVector, 5, 
    "category = 'science' AND json_array_contains(tags, 'physics')")
if err != nil {
    panic(err)
}

5. Search with Negative Examples

Want to find vectors similar to A but dissimilar to B? Use negative examples:

// Define what we like and what we don't like
positiveVector := []float32{0.1, 0.2, 0.3, /* ... */}
negativeVector := []float32{0.9, 0.8, 0.7, /* ... */}

// Search with negative examples
results, err := idx.SearchWithNegatives(
    positiveVector,           // What we're looking for
    [][]float32{negativeVector}, // What we want to avoid
    5, 1, 10)                    // k, page, pageSize

What's Next?

Now that you've got the basics down, check out:

Happy vector searching! 🚀