README

#core/attr

Attribute indexing strategies for filtered search.

#Strategies

  • Basic: Hash map based indexing
  • Bitmap: Bitmap index for low-cardinality fields
  • BPTree: B+ tree for balanced read/write
  • LSM: Write-optimized with memtable

#Key Types

  • AttrIndexStrategy: Strategy selection enum
  • NumEntry: Sorted entry for numeric index (value, id) pair
  • BasicAttrIndex: Hash map based attribute index
  • BitmapIndex: Bitmap index implementation
  • BPTree: B+ tree index implementation
  • LSMTree: LSM tree with memtable and levels

#Usage

let index = BasicAttrIndex::new()
index.insert("category", @types.String("electronics"), 123L)
let ids = index.find("category", @types.String("electronics"))

#
BPTree

type BPTree

B+ Tree structure

#
BPTreeAttrIndex

pub struct BPTreeAttrIndex {
field_trees : Map[String, BPTree]
exists_trees : Map[String, BPTree]
data : Map[
VectorId
,
Attrs
]
order : Int
}

B+ Tree Attribute Index container

#
BPTreeAttrIndex::all_ids

Return every indexed ID (from the data map).

#
BPTreeAttrIndex::deserialize

fn BPTreeAttrIndex::deserialize(data : Bytes) -> BPTreeAttrIndex

Deserialize a B+ tree attribute index from serialized bytes.

Three on-disk layouts are supported (see IdFormat for the history). The legacy v2-tag-byte layout shipped by trkbt10/vcdb <= 0.3.0 is distinguished from the current length-prefixed layout by peeking the first byte of the first VectorId — the two encodings never share a possible first byte, so the choice is unambiguous when data exists. Empty indices default to the current layout.

#
BPTreeAttrIndex::eq

Find IDs where key equals value

#
BPTreeAttrIndex::exists

Find IDs where key exists

#
BPTreeAttrIndex::get_attrs

Get attributes for an ID

#
BPTreeAttrIndex::new

fn BPTreeAttrIndex::new(order? : Int) -> BPTreeAttrIndex

Create a new BPTreeAttrIndex

#
BPTreeAttrIndex::range

Find IDs matching a numeric range

#
BPTreeAttrIndex::remove_id

Remove an ID from the index

#
BPTreeAttrIndex::serialize

fn BPTreeAttrIndex::serialize(self : BPTreeAttrIndex) -> Bytes

Serialize a B+ tree attribute index, including node graphs and stored attrs

#
BPTreeAttrIndex::set_attrs

Set attributes for an ID

#
BPTreeAttrIndex::size

fn BPTreeAttrIndex::size(self : BPTreeAttrIndex) -> Int

Get the number of indexed IDs

#
BasicAttrIndex

Basic Attribute Index - Hash map based implementation Provides fast equality lookups and range queries via sorted numeric arrays.

#
BasicAttrIndex::eq

Find IDs where key equals value

#
BasicAttrIndex::exists

Find IDs where key exists

#
BasicAttrIndex::get_attrs

Get attributes for an ID

#
BasicAttrIndex::new

Create a new empty BasicAttrIndex

#
BasicAttrIndex::range

Find IDs matching a numeric range Returns None if range queries are not supported for this key

#
BasicAttrIndex::remove_id

Remove an ID from the index

#
BasicAttrIndex::set_attrs

Set attributes for an ID (replaces existing)

#
BasicAttrIndex::size

fn BasicAttrIndex::size(self : BasicAttrIndex) -> Int

Get the number of indexed IDs

#
BitmapAttrIndex

Bitmap Attribute Index - Simplified index for low-cardinality fields Supports equality and existence queries only, no range queries.

#
BitmapAttrIndex::eq

Find IDs where key equals value

#
BitmapAttrIndex::exists

Find IDs where key exists

#
BitmapAttrIndex::get_attrs

Get attributes for an ID

#
BitmapAttrIndex::new

Create a new empty BitmapAttrIndex

#
BitmapAttrIndex::range

Range queries not supported for Bitmap index

#
BitmapAttrIndex::remove_id

Remove an ID from the index

#
BitmapAttrIndex::set_attrs

Set attributes for an ID (replaces existing)

#
BitmapAttrIndex::size

fn BitmapAttrIndex::size(self : BitmapAttrIndex) -> Int

Get the number of indexed IDs

#
BloomFilter

pub struct BloomFilter {
bits : Bytes
hash_count : Int
bit_count : Int
}

Bloom filter for fast negative lookups

#
BloomFilter::create

fn BloomFilter::create(keys : Array[Bytes], false_positive_rate : Double) -> BloomFilter

Create a bloom filter from a set of keys

#
BloomFilter::decode

fn BloomFilter::decode(buf : Bytes) -> BloomFilter?

Decode bloom filter from bytes

#
BloomFilter::encode

fn BloomFilter::encode(self : BloomFilter) -> Bytes

Encode bloom filter to bytes

#
BloomFilter::might_contain

fn BloomFilter::might_contain(self : BloomFilter, key : Bytes) -> Bool

Check if a key might be in the bloom filter

#
LSMAttrIndex

pub struct LSMAttrIndex {
memtable : Memtable
exists_memtable : Memtable
data : Map[
VectorId
,
Attrs
]
flush_threshold : Int
}

LSM Index

#
LSMAttrIndex::clear_memtable

fn LSMAttrIndex::clear_memtable(self : LSMAttrIndex) -> Unit

Clear memtable (for manual flush)

#
LSMAttrIndex::eq

Find IDs where key equals value

#
LSMAttrIndex::exists

Find IDs where key exists

#
LSMAttrIndex::get_attrs

Get attributes for an ID

#
LSMAttrIndex::memtable_size

fn LSMAttrIndex::memtable_size(self : LSMAttrIndex) -> Int

Get memtable size (for flush threshold checking)

#
LSMAttrIndex::new

fn LSMAttrIndex::new(flush_threshold? : Int) -> LSMAttrIndex

Create a new LSM attribute index

#
LSMAttrIndex::range

Find IDs matching a numeric range Note: Range queries scan through all entries - not optimal for large datasets

#
LSMAttrIndex::remove_id

Remove an ID from the index

#
LSMAttrIndex::set_attrs

Set attributes for an ID

#
LSMAttrIndex::should_flush

fn LSMAttrIndex::should_flush(self : LSMAttrIndex) -> Bool

Check if memtable should be flushed

#
LSMAttrIndex::size

fn LSMAttrIndex::size(self : LSMAttrIndex) -> Int

Get the number of indexed IDs

#
Memtable

type Memtable

Memtable structure

#
NumEntry

pub struct NumEntry {
value : Double
id :
VectorId

}

Sorted entry for numeric index (value, id) pair
impl Show for NumEntry

#
NumEntry::compare

fn NumEntry::compare(self : NumEntry, other : NumEntry) -> Int

Compare NumEntry by value for sorting

#
SSTable

pub struct SSTable {
records : Array[SSTableRecord]
index : Array[SparseIndexEntry]
bloom : BloomFilter?
footer : SSTableFooter
}

Decoded SSTable structure (in-memory)

#
SSTable::build

fn SSTable::build(records : Array[SSTableRecord], index_interval : Int) -> Bytes

Build an SSTable from sorted records

#
SSTable::find

fn SSTable::find(self : SSTable, key : Bytes) -> SSTableRecord?

Find a record in SSTable by key

#
SSTable::read

fn SSTable::read(buf : Bytes) -> SSTable?

Read an SSTable from bytes

#
SSTableFooter

pub struct SSTableFooter {
magic : UInt
version : UInt
data_offset : Int
data_size : Int
index_offset : Int
index_size : Int
bloom_offset : Int
bloom_size : Int
}

SSTable footer structure

#
SSTableFooter::decode

fn SSTableFooter::decode(buf : Bytes) -> SSTableFooter?

Decode footer from bytes

#
SSTableFooter::encode

fn SSTableFooter::encode(self : SSTableFooter) -> Bytes

Encode footer to bytes

#
SSTableRecord

pub struct SSTableRecord {
key : Bytes
value : Bytes
}

SSTable record

#
SSTableRecord::decode

fn SSTableRecord::decode(buf : Bytes, offset : Int) -> (SSTableRecord, Int)?

Decode a single record from bytes at given offset

#
SSTableRecord::encode

fn SSTableRecord::encode(self : SSTableRecord) -> Bytes

Encode a single record to bytes

#
SparseIndexEntry

pub struct SparseIndexEntry {
key : Bytes
offset : Int
}

Sparse index entry

#
attr_value_to_key

fn attr_value_to_key(value :
AttrValue
) -> String

Convert AttrValue to string key for indexing Uses type prefix to disambiguate different types with same string representation

#
attr_value_to_number

fn attr_value_to_number(value :
AttrValue
) -> Double?

Extract numeric value from AttrValue for range queries

#
lower_bound

fn lower_bound(arr : Array[NumEntry], target : Double) -> Int

Binary search for lower bound in sorted array Returns index of first element >= target

#
remove_num_entry_swap

fn remove_num_entry_swap(arr : Array[NumEntry], id :
VectorId
) -> Bool

Remove a NumEntry by id from an array using swap-and-pop Returns true if the entry was found and removed

#
remove_vectorid_swap

Remove an Int64 value from an array using swap-and-pop Returns true if the value was found and removed

#
sort_num_entries

fn sort_num_entries(arr : Array[NumEntry]) -> Unit

Sort NumEntry array by value

#
upper_bound

fn upper_bound(arr : Array[NumEntry], target : Double) -> Int

Binary search for upper bound in sorted array Returns index of first element > target