Chroma Go

repository·main·Indexed 42 days ago

https://github.com/amikos-tech/chroma-go

A Go client for the Chroma Vector Database. It supports local in-process execution via a persistent client, self-hosted HTTP servers, and Chroma Cloud. Features include collection management, document operations, metadata filtering using logical expressions, and advanced search capabilities such as KNN ranking and Hybrid Search (RRF) via the Cloud Search API.

Tokens
107.7K
Snippets
295
Records
359
Agent score
50%

What's inside Chroma Go

  1. Available Embedding Model Wrappers

    main

    Chroma Go provides a wide range of embedding function wrappers for various providers and specialized use cases. These include:

    Standard Providers:

    • OpenAI: Access OpenAI's embedding models.
    • Cohere: Access Cohere's embedding API.
    • HuggingFace: Use either the Inference API or a local Embedding Inference Server.
    • Ollama: Local embeddings via Ollama.
    • Cloudflare Workers AI: Embeddings via Cloudflare.
    • Together AI, Voyage AI, Google Gemini, Mistral AI, Nomic AI, Jina AI, Perplexity, OpenRouter.

    Specialized & Multimodal:

    • Roboflow CLIP: Multimodal (text + images).
    • Twelve Labs: Multimodal (text, image, audio, video).
    • Amazon Bedrock: Titan models.
    • Baseten BEI: Deploy your own models.
    • Morph AI.

    Sparse & Hybrid Search:

    • Chroma Cloud: Hosted embeddings.
    • Chroma Cloud Splade: Sparse embeddings for hybrid search.
    • BM25: Local sparse embeddings (no external API required).
  2. Customize Search Scoring with Arithmetic Operations

    main

    Chroma allows you to manipulate search scores using arithmetic operations on ranking expressions. This is useful for weighted multi-query searches, score adjustments, or log compression.

    Key Concepts:

    • Weighted Ranking: Combine multiple KNN queries by multiplying them by weights (e.g., knn1.Multiply(v2.FloatOperand(0.7)).Add(knn2.Multiply(v2.FloatOperand(0.3)))).
    • Score Adjustment: Add or subtract constant values using v2.Val(x).
    • Log Compression: Apply .Log() to scores (ensure values are positive by adding an offset first, e.g., knn.Add(v2.Val(1.0)).Log()).
    • Constants: Use v2.Val(x) to create constant value rank expressions for use in math operations.
    package main
    
    import (
    	"context"
    	v2 "github.com/amikos-tech/chroma-go/pkg/api/v2"
    )
    
    func main() {
    	// ... client and collection setup ...
    
    	// Weighted ranking: rank1 * 0.7 + rank2 * 0.3
    	knn4, _ := v2.NewKnnRank(v2.KnnQueryText("machine learning"))
    	knn5, _ := v2.NewKnnRank(v2.KnnQueryText("deep learning"))
    	combinedRank := knn4.Multiply(v2.FloatOperand(0.7)).Add(
    		knn5.Multiply(v2.FloatOperand(0.3)),
    	)
    
    	result, _ := collection.Search(ctx, v2.NewSearchRequest(
    		v2.WithRank(combinedRank),
    		v2.NewPage(v2.Limit(10)),
    	))
    }
  3. Best Practices for Hybrid Retrieval

    main

    For optimal search performance, combine dense and sparse vectors:

    • Hybrid Search: Use both dense vectors (for semantic meaning) and sparse vectors (for exact keyword matching) to achieve the best results.
    • Reciprocal Rank Fusion (RRF): Use RRF to combine the results from dense and sparse searches.
    • Weight Tuning: When combining results, start with a weight ratio of 0.7 (dense) / 0.3 (sparse) and adjust based on your specific use case.
    • Result Iteration: Use the Rows() method for ergonomic iteration over search results, and At(group, index) for safe indexed access with bounds checking.
  4. Advanced Schema Configuration Options

    main

    Beyond basic indexing, the schema API supports fine-tuning for specific workloads:

    • HNSW Tuning: Use WithHnsw() for fine-grained control over the HNSW graph.
    • Cloud-Scale Workloads: Use WithSpann() to configure SPANN (Scalable Partitioned Approximate Nearest Neighbors) for large-scale datasets in Chroma Cloud.
    • Persistence: Schemas are automatically persisted along with the collection.
  5. How to page through results using a general formula

    main

    To implement zero-indexed pagination (where Page 0 is the first set of results), use the following formula for the offset:

    offset = page_number * page_size

    Example pattern for Page $N$:

    • Page 0: Limit(pageSize), Offset(0)
    • Page 1: Limit(pageSize), Offset(pageSize)
    • Page 2: Limit(pageSize), Offset(2 * pageSize)
    // General formula for page N
    getPage := func(pageNumber int, pageSize int) v2.SearchCollectionOption {
    	return v2.NewSearchRequest(
    		v2.NewPage(
    			v2.Limit(pageSize),
    			v2.Offset(pageNumber*pageSize),
    		),
    	)
    }
    
    // Get page 5
    page5, _ := collection.Search(ctx, getPage(5, 10))
  6. Best practices for managing collections in Chroma Go

    main

    When working with collections in chroma-go, keep the following operational constraints and best practices in mind:

    • Uniqueness: Collection names must be unique within a single database.
    • Persistence: The embedding function is persisted along with the collection (requires Chroma version >= 1.1.13).
    • Error Prevention: Use GetOrCreateCollection instead of CreateCollection if you want to avoid errors when a collection might already exist.
    • Data Safety: Deleting a collection is a permanent operation and removes all associated data.
    • Resource Management: Always use defer client.Close() to ensure client resources are properly released after use.
  7. Filter records by metadata using the `where` argument

    main

    When using the get or query methods, you can filter the returned records based on their metadata by providing a where argument. To ensure clarity and avoid ambiguity in filter expressions, use v2.K("field_name") to explicitly mark metadata field names.

    This allows you to target specific keys within the metadata dictionary of your stored documents.

    // Example concept of using the where argument
    // (Note: Full implementation details follow in subsequent segments)
    // client.Query(ctx, collectionName, queryText, &chroma.QueryOptions{
    //     Where: v2.K("my_metadata_field").Eq("some_value"),
    // })
  8. Use cases for Collection Forking

    main

    Collection forking allows you to create isolated copies of existing collections to support several workflows:

    • Data versioning/checkpointing: Maintain consistent snapshots as your data evolves.
    • Git-like workflows: Index a branch by forking from its divergence point, then apply the diff.
    • A/B testing: Compare different embedding strategies or data configurations.
    • Safe experimentation: Test changes without affecting production data.
  9. How GroupBy and Aggregation work in Chroma Go

    main

    GroupBy allows you to group search results by one or more metadata keys and select a specific number of top results from each group. This is useful for diversifying search results (e.g., ensuring results from multiple categories appear), deduplication, and category-aware ranking.

    Key Concepts:

    • Ranking Requirement: GroupBy requires a ranking expression (like KnnQueryText) to be present in the search request.
    • Aggregation Types:
      • MinK: Keeps $N$ records with the smallest values for the specified keys. Use this with v2.KScore for distance-based scoring where a lower score is better.
      • MaxK: Keeps $N$ records with the largest values for the specified keys. Use this for metrics where higher is better (e.g., ratings, popularity).
    • Tiebreaking: You can provide multiple keys to an aggregation function to act as tiebreakers (e.g., v2.NewMinK(2, v2.K("priority"), v2.KScore) will keep 2 records based on lowest priority, then lowest score).
    • Edge Cases:
      • Groups with fewer than $k$ records will return all available records in that group.
      • Documents missing the grouping key are grouped together under a null group.
      • Ensure your KNN limit is high enough to capture candidates from all intended groups.
    // Example of grouping by category and keeping top 2 per category using MinK
    result, err := collection.Search(ctx, 
        v2.NewSearchRequest(
            v2.WithKnnRank(v2.KnnQueryText("query"), v2.WithKnnLimit(100)),
            v2.WithGroupBy(
                v2.NewGroupBy(
                    v2.NewMinK(2, v2.KScore), 
                    v2.K("category"),
                ),
            ),
        ),
    )