meta

package
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 14, 2025 License: MIT Imports: 4 Imported by: 1

README

Metadata Extension for HNSW

This extension adds support for storing and retrieving JSON metadata alongside vectors in HNSW graphs.

Features

  • Store arbitrary JSON metadata with each vector
  • Retrieve metadata along with search results
  • Support for all HNSW search operations (regular search, search with negative examples, batch search)
  • Memory-efficient storage using json.RawMessage
  • Type-safe implementation using Go generics

Usage

Basic Usage
// Create a graph and metadata store
graph := hnsw.NewGraph[int]()
store := meta.NewMemoryMetadataStore[int]()
metadataGraph := meta.NewMetadataGraph(graph, store)

// Create a node with metadata
node := hnsw.MakeNode(1, []float32{0.1, 0.2, 0.3})
metadata := map[string]interface{}{
    "name":     "Product 1",
    "category": "Electronics",
    "price":    999.99,
    "tags":     []string{"smartphone", "5G", "camera"},
}

// Add the node with metadata
metadataNode, err := meta.NewMetadataNode(node, metadata)
if err != nil {
    log.Fatalf("Failed to create metadata node: %v", err)
}

err = metadataGraph.Add(metadataNode)
if err != nil {
    log.Fatalf("Failed to add node: %v", err)
}

// Search with metadata
query := []float32{0.1, 0.2, 0.3}
results, err := metadataGraph.Search(query, 10)
if err != nil {
    log.Fatalf("Search failed: %v", err)
}

// Access metadata in search results
for i, result := range results {
    var metadata map[string]interface{}
    err := result.GetMetadataAs(&metadata)
    if err != nil {
        log.Printf("Failed to get metadata for result %d: %v", i, err)
        continue
    }
    
    fmt.Printf("Result %d: %s - $%.2f (%s)\n", 
        i+1, 
        metadata["name"], 
        metadata["price"], 
        metadata["category"],
    )
}
Search with Negative Examples
// Search with a negative example
query := []float32{0.1, 0.2, 0.3}
negative := []float32{0.9, 0.8, 0.7}
results, err := metadataGraph.SearchWithNegative(query, negative, 10, 0.7)
if err != nil {
    log.Fatalf("Search with negative failed: %v", err)
}

// Process results as before
Batch Operations
// Batch add nodes with metadata
nodes := []meta.MetadataNode[int]{
    createNode(1, vector1, metadata1),
    createNode(2, vector2, metadata2),
    createNode(3, vector3, metadata3),
}

err := metadataGraph.BatchAdd(nodes)
if err != nil {
    log.Fatalf("Batch add failed: %v", err)
}

// Batch search
queries := []hnsw.Vector{query1, query2, query3}
batchResults, err := metadataGraph.BatchSearch(queries, 10)
if err != nil {
    log.Fatalf("Batch search failed: %v", err)
}

// Process batch results
for i, results := range batchResults {
    fmt.Printf("Results for query %d:\n", i+1)
    for j, result := range results {
        // Process each result
    }
}

Custom Metadata Types

You can use any JSON-serializable type for metadata:

// Define a custom metadata type
type ProductMetadata struct {
    Name        string   `json:"name"`
    Category    string   `json:"category"`
    Price       float64  `json:"price"`
    Tags        []string `json:"tags"`
    InStock     bool     `json:"inStock"`
    ReleaseDate string   `json:"releaseDate"`
}

// Create metadata
metadata := ProductMetadata{
    Name:        "Smartphone X",
    Category:    "Electronics",
    Price:       999.99,
    Tags:        []string{"smartphone", "5G", "camera"},
    InStock:     true,
    ReleaseDate: "2023-01-15",
}

// Create and add node
node := hnsw.MakeNode(1, []float32{0.1, 0.2, 0.3})
metadataNode, _ := meta.NewMetadataNode(node, metadata)
metadataGraph.Add(metadataNode)

// Later, retrieve and use the typed metadata
var productMetadata ProductMetadata
result.GetMetadataAs(&productMetadata)
fmt.Printf("Product: %s, Price: $%.2f\n", productMetadata.Name, productMetadata.Price)

Custom Metadata Stores

You can implement your own metadata store by implementing the MetadataStore interface:

type MetadataStore[K cmp.Ordered] interface {
    // Add adds metadata for a key.
    Add(key K, metadata json.RawMessage) error

    // Get retrieves metadata for a key.
    Get(key K) (json.RawMessage, bool)

    // Delete removes metadata for a key.
    Delete(key K) bool

    // BatchAdd adds metadata for multiple keys.
    BatchAdd(keys []K, metadatas []json.RawMessage) error

    // BatchGet retrieves metadata for multiple keys.
    BatchGet(keys []K) []json.RawMessage

    // BatchDelete removes metadata for multiple keys.
    BatchDelete(keys []K) []bool
}

This allows you to store metadata in different backends, such as databases or file systems.

Documentation

Overview

Package meta provides extensions to the HNSW library for storing and retrieving JSON metadata alongside vectors.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type MemoryMetadataStore

type MemoryMetadataStore[K cmp.Ordered] struct {
	// contains filtered or unexported fields
}

MemoryMetadataStore is an in-memory implementation of MetadataStore.

func NewMemoryMetadataStore

func NewMemoryMetadataStore[K cmp.Ordered]() *MemoryMetadataStore[K]

NewMemoryMetadataStore creates a new in-memory metadata store.

func (*MemoryMetadataStore[K]) Add

func (s *MemoryMetadataStore[K]) Add(key K, metadata json.RawMessage) error

Add adds metadata for a key.

func (*MemoryMetadataStore[K]) BatchAdd

func (s *MemoryMetadataStore[K]) BatchAdd(keys []K, metadatas []json.RawMessage) error

BatchAdd adds metadata for multiple keys.

func (*MemoryMetadataStore[K]) BatchDelete

func (s *MemoryMetadataStore[K]) BatchDelete(keys []K) []bool

BatchDelete removes metadata for multiple keys.

func (*MemoryMetadataStore[K]) BatchGet

func (s *MemoryMetadataStore[K]) BatchGet(keys []K) []json.RawMessage

BatchGet retrieves metadata for multiple keys.

func (*MemoryMetadataStore[K]) Delete

func (s *MemoryMetadataStore[K]) Delete(key K) bool

Delete removes metadata for a key.

func (*MemoryMetadataStore[K]) ForEach added in v0.3.0

func (s *MemoryMetadataStore[K]) ForEach(fn func(key K, metadata json.RawMessage))

ForEach iterates over all metadata entries and calls the provided function for each entry.

func (*MemoryMetadataStore[K]) Get

func (s *MemoryMetadataStore[K]) Get(key K) (json.RawMessage, bool)

Get retrieves metadata for a key.

type MetadataError

type MetadataError struct {
	Message string
}

MetadataError represents an error related to metadata operations.

func (MetadataError) Error

func (e MetadataError) Error() string

Error returns the error message.

type MetadataGraph

type MetadataGraph[K cmp.Ordered] struct {
	Graph *hnsw.Graph[K]
	Store MetadataStore[K]
}

MetadataGraph combines an HNSW graph with metadata storage.

func NewMetadataGraph

func NewMetadataGraph[K cmp.Ordered](graph *hnsw.Graph[K], store MetadataStore[K]) *MetadataGraph[K]

NewMetadataGraph creates a new MetadataGraph with the given HNSW graph and metadata store.

func (*MetadataGraph[K]) Add

func (g *MetadataGraph[K]) Add(node MetadataNode[K]) error

Add adds a node with metadata to both the graph and the metadata store.

func (*MetadataGraph[K]) BatchAdd

func (g *MetadataGraph[K]) BatchAdd(nodes []MetadataNode[K]) error

BatchAdd adds multiple nodes with metadata in a single operation.

func (*MetadataGraph[K]) BatchDelete

func (g *MetadataGraph[K]) BatchDelete(keys []K) []bool

BatchDelete removes multiple nodes in a single operation.

func (*MetadataGraph[K]) BatchSearch

func (g *MetadataGraph[K]) BatchSearch(queries []hnsw.Vector, k int) ([][]MetadataSearchResult[K], error)

BatchSearch performs multiple searches in a single operation and attaches metadata to results.

func (*MetadataGraph[K]) BatchSearchWithNegatives

func (g *MetadataGraph[K]) BatchSearchWithNegatives(queries []hnsw.Vector, negatives []hnsw.Vector, k int, negWeight float32) ([][]MetadataSearchResult[K], error)

BatchSearchWithNegatives performs multiple searches with negative examples in a single operation and attaches metadata to results.

func (*MetadataGraph[K]) Delete

func (g *MetadataGraph[K]) Delete(key K) bool

Delete removes a node from both the graph and the metadata store.

func (*MetadataGraph[K]) Get

func (g *MetadataGraph[K]) Get(key K) (MetadataNode[K], bool)

Get retrieves a node with its metadata.

func (*MetadataGraph[K]) Search

func (g *MetadataGraph[K]) Search(query hnsw.Vector, k int) ([]MetadataSearchResult[K], error)

Search performs a search and attaches metadata to results.

func (*MetadataGraph[K]) SearchWithNegative

func (g *MetadataGraph[K]) SearchWithNegative(query, negative hnsw.Vector, k int, negWeight float32) ([]MetadataSearchResult[K], error)

SearchWithNegative performs a search with a negative example and attaches metadata to results.

type MetadataNode

type MetadataNode[K cmp.Ordered] struct {
	Node     hnsw.Node[K]
	Metadata json.RawMessage
}

MetadataNode extends the basic HNSW Node with JSON metadata.

func NewMetadataNode

func NewMetadataNode[K cmp.Ordered](node hnsw.Node[K], metadata interface{}) (MetadataNode[K], error)

NewMetadataNode creates a new MetadataNode with the given node and metadata.

func (MetadataNode[K]) GetMetadataAs

func (n MetadataNode[K]) GetMetadataAs(target interface{}) error

GetMetadataAs unmarshals the metadata into the provided target.

type MetadataSearchResult

type MetadataSearchResult[K cmp.Ordered] struct {
	SearchResult[K]
	Metadata json.RawMessage
}

MetadataSearchResult extends the basic HNSW SearchResult with metadata.

func (MetadataSearchResult[K]) GetMetadataAs

func (r MetadataSearchResult[K]) GetMetadataAs(target interface{}) error

GetMetadataAs unmarshals the metadata into the provided target.

type MetadataStore

type MetadataStore[K cmp.Ordered] interface {
	// Add adds metadata for a key.
	Add(key K, metadata json.RawMessage) error

	// Get retrieves metadata for a key.
	Get(key K) (json.RawMessage, bool)

	// Delete removes metadata for a key.
	Delete(key K) bool

	// BatchAdd adds metadata for multiple keys.
	BatchAdd(keys []K, metadatas []json.RawMessage) error

	// BatchGet retrieves metadata for multiple keys.
	BatchGet(keys []K) []json.RawMessage

	// BatchDelete removes metadata for multiple keys.
	BatchDelete(keys []K) []bool

	// ForEach iterates over all metadata entries and calls the provided function for each entry.
	ForEach(fn func(key K, metadata json.RawMessage))
}

MetadataStore is an interface for storing and retrieving metadata.

type SearchResult

type SearchResult[K cmp.Ordered] struct {
	Key  K
	Dist float32
}

SearchResult represents a search result from the HNSW graph. This is a copy of the type from the HNSW package to avoid import cycles.

Directories

Path Synopsis
Package example provides examples of using the metadata extension for HNSW.
Package example provides examples of using the metadata extension for HNSW.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL