Skip to content

Examples

Let's explore some real-world examples of how to use Quiver in different scenarios. These examples will help you understand how to integrate Quiver into your applications and get the most out of its features. 🚀

Semantic Search Engine

This example shows how to build a simple semantic search engine for documents:

package main

import (
    "fmt"
    "io/ioutil"
    "path/filepath"
    "strings"

    "github.com/TFMV/quiver"
    "github.com/sashabaranov/go-openai"
    "go.uber.org/zap"
)

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

    // Initialize Quiver
    idx, _ := quiver.New(quiver.Config{
        Dimension:   1536,  // OpenAI embeddings dimension
        StoragePath: "./data/documents.db",
        Distance:    quiver.Cosine,
    }, logger)
    defer idx.Close()

    // Initialize OpenAI client
    openaiClient := openai.NewClient("your-api-key")

    // Index documents
    docs, _ := loadDocuments("./documents")
    for i, doc := range docs {
        // Get embedding from OpenAI
        resp, _ := openaiClient.CreateEmbeddings(
            context.Background(),
            openai.EmbeddingRequest{
                Input: []string{doc.Content},
                Model: openai.AdaEmbeddingV2,
            },
        )

        // Convert to float32
        vector := make([]float32, len(resp.Data[0].Embedding))
        for i, v := range resp.Data[0].Embedding {
            vector[i] = float32(v)
        }

        // Add to Quiver
        idx.Add(uint64(i), vector, map[string]interface{}{
            "category": "document",
            "title":    doc.Title,
            "path":     doc.Path,
            "tags":     doc.Tags,
        })
    }

    // Search function
    searchDocuments := func(query string) {
        // Get embedding for query
        resp, _ := openaiClient.CreateEmbeddings(
            context.Background(),
            openai.EmbeddingRequest{
                Input: []string{query},
                Model: openai.AdaEmbeddingV2,
            },
        )

        // Convert to float32
        queryVector := make([]float32, len(resp.Data[0].Embedding))
        for i, v := range resp.Data[0].Embedding {
            queryVector[i] = float32(v)
        }

        // Search
        results, _ := idx.Search(queryVector, 5, 1, 5)

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

    // Example searches
    searchDocuments("How does quantum computing work?")
    searchDocuments("Latest developments in AI")
}

type Document struct {
    Title   string
    Content string
    Path    string
    Tags    []string
}

func loadDocuments(dir string) ([]Document, error) {
    // Implementation omitted for brevity
    // This would load documents from files in the specified directory
    return []Document{}, nil
}

Product Recommendation System

This example demonstrates how to build a product recommendation system:

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: "./data/products.db",
        Distance:    quiver.Cosine,
    }, logger)
    defer idx.Close()

    // Load product embeddings
    // In a real system, these would come from a model trained on product features
    products := loadProductEmbeddings("./data/product_embeddings.json")

    // Add products to the index
    for _, product := range products {
        idx.Add(product.ID, product.Embedding, map[string]interface{}{
            "category":    "product",
            "name":        product.Name,
            "description": product.Description,
            "price":       product.Price,
            "brand":       product.Brand,
            "tags":        product.Tags,
        })
    }

    // Get recommendations for a user
    userID := uint64(12345)
    userProfile := getUserProfile(userID)

    // Get products the user has viewed or purchased
    viewedProducts := getViewedProducts(userID)

    // Create a positive query from the user profile
    positiveQuery := userProfile.Embedding

    // Create negative queries from products the user has already seen
    negativeQueries := make([][]float32, len(viewedProducts))
    for i, product := range viewedProducts {
        negativeQueries[i] = product.Embedding
    }

    // Search with negative examples to avoid recommending products the user has already seen
    results, _ := idx.SearchWithNegatives(positiveQuery, negativeQueries, 10, 1, 10)

    // Filter by price range
    results, _ = idx.SearchWithFilter(positiveQuery, 10, 
        fmt.Sprintf("price >= %f AND price <= %f", userProfile.MinPrice, userProfile.MaxPrice))

    // Print recommendations
    fmt.Printf("Recommendations for user %d:\n", userID)
    for i, result := range results {
        fmt.Printf("%d. %s - $%.2f\n", 
            i+1, 
            result.Metadata["name"], 
            result.Metadata["price"])
    }
}

// Placeholder functions and types
type Product struct {
    ID          uint64
    Name        string
    Description string
    Price       float64
    Brand       string
    Tags        []string
    Embedding   []float32
}

type UserProfile struct {
    Embedding []float32
    MinPrice  float64
    MaxPrice  float64
}

func loadProductEmbeddings(path string) []Product {
    // Implementation omitted for brevity
    return []Product{}
}

func getUserProfile(userID uint64) UserProfile {
    // Implementation omitted for brevity
    return UserProfile{}
}

func getViewedProducts(userID uint64) []Product {
    // Implementation omitted for brevity
    return []Product{}
}

This example shows how to use Quiver for image similarity search:

package main

import (
    "fmt"
    "image"
    _ "image/jpeg"
    _ "image/png"
    "os"
    "path/filepath"

    "github.com/TFMV/quiver"
    "github.com/nfnt/resize"
    "go.uber.org/zap"
    "gorgonia.org/tensor"
)

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

    // Initialize Quiver
    idx, _ := quiver.New(quiver.Config{
        Dimension:   512,  // ResNet feature dimension
        StoragePath: "./data/images.db",
        Distance:    quiver.L2,  // L2 is better for image features
    }, logger)
    defer idx.Close()

    // Load pre-trained model (placeholder)
    model := loadResNetModel()

    // Index images
    imageDir := "./images"
    files, _ := filepath.Glob(filepath.Join(imageDir, "*.jpg"))

    for i, file := range files {
        // Load and preprocess image
        img, _ := loadImage(file)
        resized := resize.Resize(224, 224, img, resize.Lanczos3)

        // Extract features using the model
        features := extractFeatures(model, resized)

        // Add to Quiver
        idx.Add(uint64(i), features, map[string]interface{}{
            "category": "image",
            "path":     file,
            "filename": filepath.Base(file),
        })
    }

    // Search for similar images
    queryImage, _ := loadImage("./query.jpg")
    queryResized := resize.Resize(224, 224, queryImage, resize.Lanczos3)
    queryFeatures := extractFeatures(model, queryResized)

    results, _ := idx.Search(queryFeatures, 10, 1, 10)

    // Print results
    fmt.Println("Similar images:")
    for i, result := range results {
        fmt.Printf("%d. %s (Distance: %.4f)\n", 
            i+1, 
            result.Metadata["filename"], 
            result.Distance)
    }
}

// Placeholder functions
func loadResNetModel() interface{} {
    // Implementation omitted for brevity
    return nil
}

func loadImage(path string) (image.Image, error) {
    file, err := os.Open(path)
    if err != nil {
        return nil, err
    }
    defer file.Close()

    img, _, err := image.Decode(file)
    return img, err
}

func extractFeatures(model interface{}, img image.Image) []float32 {
    // Implementation omitted for brevity
    // This would convert the image to a tensor, run it through the model,
    // and return the feature vector
    return make([]float32, 512)
}

Real-time Anomaly Detection

This example demonstrates using Quiver for real-time anomaly detection:

package main

import (
    "fmt"
    "time"

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

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

    // Initialize Quiver
    idx, _ := quiver.New(quiver.Config{
        Dimension:   64,
        StoragePath: "./data/anomalies.db",
        Distance:    quiver.L2,
    }, logger)
    defer idx.Close()

    // Load historical normal patterns
    patterns := loadHistoricalPatterns()

    // Add normal patterns to the index
    for i, pattern := range patterns {
        idx.Add(uint64(i), pattern.Features, map[string]interface{}{
            "category":    "pattern",
            "timestamp":   pattern.Timestamp,
            "source":      pattern.Source,
            "is_anomaly":  false,
        })
    }

    // Anomaly detection function
    detectAnomaly := func(newPattern Pattern) bool {
        // Search for similar patterns
        results, _ := idx.Search(newPattern.Features, 5, 1, 5)

        // Calculate average distance to k nearest neighbors
        var totalDistance float32
        for _, result := range results {
            totalDistance += result.Distance
        }
        avgDistance := totalDistance / float32(len(results))

        // If average distance is above threshold, it's an anomaly
        threshold := float32(0.8)
        isAnomaly := avgDistance > threshold

        // Log the result
        if isAnomaly {
            fmt.Printf("ANOMALY DETECTED! Source: %s, Time: %s, Score: %.4f\n",
                newPattern.Source, newPattern.Timestamp.Format(time.RFC3339), avgDistance)
        }

        // Add the new pattern to the index
        idx.Add(uint64(time.Now().UnixNano()), newPattern.Features, map[string]interface{}{
            "category":    "pattern",
            "timestamp":   newPattern.Timestamp.Unix(),
            "source":      newPattern.Source,
            "is_anomaly":  isAnomaly,
            "score":       avgDistance,
        })

        return isAnomaly
    }

    // Simulate real-time data stream
    go func() {
        for {
            // Get new pattern from data source
            newPattern := getNewPattern()

            // Detect anomaly
            detectAnomaly(newPattern)

            // Wait for next data point
            time.Sleep(1 * time.Second)
        }
    }()

    // Keep the main thread alive
    select {}
}

// Placeholder types and functions
type Pattern struct {
    Features  []float32
    Timestamp time.Time
    Source    string
}

func loadHistoricalPatterns() []Pattern {
    // Implementation omitted for brevity
    return []Pattern{}
}

func getNewPattern() Pattern {
    // Implementation omitted for brevity
    return Pattern{
        Features:  make([]float32, 64),
        Timestamp: time.Now(),
        Source:    "sensor-1",
    }
}

Next Steps

These examples demonstrate just a few of the many ways you can use Quiver in your applications. For more detailed examples and best practices, check out: