import { DistanceMetric } from './HNSWIndex.js'; import type { StorageBackend } from './storage/StorageBackend.js'; import type { MetadataSchema } from './public-api.js'; export type VectorInput = number[] | Float32Array; export type AddVectorInput = VectorInput[] | Float32Array; export interface StoredVectorRecord { id: string; numericId: number; vector: Float32Array; metadata: Record; } export interface CollectionBatchOperations { add(config: AddConfig): Promise; upsert(config: AddConfig): Promise; delete(ids: string[]): Promise; updateMetadata(id: string, metadata: Record): Promise; } /** * Configuration for adding vectors to a collection. */ export interface AddConfig { /** Unique string identifiers for each vector */ ids: string[]; /** * Vectors to add. Pass either one vector per ID or a single row-major * Float32Array packed as `[vector0..., vector1..., ...]`. */ vectors: AddVectorInput; /** Optional metadata for each vector (same length as ids/vectors, plain JSON objects only) */ metadata?: Array>; } export interface CountConfig { /** Optional metadata filter. Uses the same operators and semantics as QueryConfig.filter. */ filter?: Record; } /** * Configuration for querying a collection. * * @example * ```typescript * // Simple query * const results = await collection.query({ * queryVector: [0.1, 0.2, 0.3], * k: 10 * }); * * // Query with metadata filter * const results = await collection.query({ * queryVector: [0.1, 0.2, 0.3], * k: 10, * filter: { * category: 'science', // Exact match * year: { $gte: 2020 }, // Greater than or equal * status: { $in: ['active', 'pending'] } // In array * } * }); * ``` */ export interface QueryConfig { /** The query vector (must match collection dimension) */ queryVector: number[] | Float32Array; /** Number of nearest neighbors to return */ k: number; /** * Optional metadata filter. Supports MongoDB-style operators: * - Simple equality: `{ field: value }` * - `$gt`: Greater than `{ field: { $gt: 5 } }` * - `$gte`: Greater than or equal `{ field: { $gte: 5 } }` * - `$lt`: Less than `{ field: { $lt: 10 } }` * - `$lte`: Less than or equal `{ field: { $lte: 10 } }` * - `$ne`: Not equal `{ field: { $ne: 'excluded' } }` * - `$in`: In array `{ field: { $in: ['a', 'b', 'c'] } }` * - `$nin`: Not in array `{ field: { $nin: ['x', 'y'] } }` */ filter?: Record; /** Search effort parameter (higher = better recall, slower). Default: max(k*2, 50) */ efSearch?: number; /** Use int8 quantized search + float32 rescore. Default: auto (true when quantization enabled) */ useQuantizedSearch?: boolean; /** Oversampling multiplier for quantized rescore (default: 3). Higher = better recall, slower. */ candidateMultiplier?: number; /** Whether to clone and return result metadata (default: true). */ includeMetadata?: boolean; } export interface QueryResult { ids: string[]; distances: number[]; metadata: Array>; } export interface CollectionOptions { /** * Persist mutating operations automatically after they complete. * VectorDB-managed collections enable this by default. */ autoPersist?: boolean; durability?: 'immediate' | 'manual' | { mode: 'batched'; maxOperations?: number; maxDelayMs?: number; }; metadataSchema?: MetadataSchema; } export declare class Collection { private static readonly MAX_INTERNAL_ID; private name; private dimension; private metric; private M; private efConstruction; private storage; private readonly stateKey; private readonly defaultIndexKey; private readonly defaultMetaKey; private readonly defaultDeletedKey; private indexKey; private metaKey; private deletedKey; private hnsw; private idMap; private idReverseMap; private metadata; private deletedIds; private nextNumericId; private activeCount; private readonly autoPersist; private readonly persistenceMode; private readonly batchedMaxOperations; private readonly batchedMaxDelayMs; private readonly metadataSchema?; private metadataExactIndexes; private metadataContainsIndexes; private metadataRangeIndexes; private dirty; private lastFlushedAt; private lastQueryVisitedNodes; private batchActive; private batchedOperationCount; private batchedPersistTimer; private batchedPersistPromise; private batchedPersistError; private mutationLock; constructor(name: string, config: { dimension: number; metric?: DistanceMetric; M?: number; efConstruction?: number; }, storage: StorageBackend, options?: CollectionOptions); init(): Promise; private withMutationLock; private validateBatchPersistenceLimit; private throwIfBatchedPersistenceFailed; private scheduleBatchedPersistence; private flushBatchedPersistence; flush(): Promise; private captureMutationSnapshot; private restoreMutationSnapshot; private cloneMetadata; private resultMetadataFor; /** Convert a public vector input once and reject values lost by Float32. */ private toFloat32; private prepareExactQueryVector; /** * Wrap a mutation in snapshot-capture + auto-persist. * The mutation fn should set `this.dirty = true` when it mutates state. * If autoPersist is on and dirty was set, saves after fn completes. * On error, restores from snapshot. */ private withAutoSave; private reserveNumericIds; private setActiveStorageKeys; private isValidStorageState; private storageStateGeneration; private loadStorageState; /** * Resolve the pre-pointer fixed-key layout only when it is complete and * unambiguous. A pointerless partial/mixed snapshot is corruption, not an * empty collection: silently accepting it would drop vectors or tombstones. */ private loadLegacyStorageState; private createUniqueSaveId; private cleanupSnapshotKeys; private getVersionedDataKeys; private isVersionedDataKey; private validateLoadedIndexConfig; private loadFromDisk; private loadFromDiskCore; add(config: AddConfig): Promise; query(config: QueryConfig): Promise; /** * Batch query for multiple vectors at once. * Shares query semantics with query(), including adaptive candidate expansion * for filters and tombstones. * * @param configs Array of query configurations * @returns Array of query results, one per query */ queryBatch(configs: QueryConfig[]): Promise; /** * Brute-force KNN search for validation and correctness checking * This checks all vectors and returns the true k nearest neighbors */ queryBruteForce(config: QueryConfig): Promise; /** * Upsert vectors (insert or update). * * For existing IDs, the old vectors are tombstone-deleted and new vectors * are inserted. Use compact() periodically to reclaim space from * tombstoned vectors. * * For new IDs, behaves identically to add(). */ upsert(config: AddConfig): Promise; private addInternal; private addInternalUnlocked; /** Returns the vector dimension for this collection. */ getDimension(): number; /** Returns the distance metric for this collection. */ getMetric(): DistanceMetric; /** Returns the HNSW M parameter for this collection. */ getM(): number; /** Returns the HNSW efConstruction parameter for this collection. */ getEfConstruction(): number; /** Internal facade access to the backend identity without exposing the backend itself. */ getStorageType(): string; /** Whether traversal quantization is enabled on the underlying index. */ isQuantizationEnabled(): boolean; /** Diagnostics for the most recent query traversal or exact scan. */ getLastSearchVisitedNodes(): number; /** * Returns the number of active (non-deleted) vectors in the collection. * O(1) without a filter; filtered counts scan metadata for matching active vectors. */ count(config?: CountConfig): number; /** Alias for count() when no filter is required. */ countActive(): number; /** * Returns the total number of tracked vectors including deleted (tombstoned) ones. * Use this to determine when compaction might be beneficial. */ countWithDeleted(): number; /** * Returns the number of deleted (tombstoned) vectors awaiting compaction. */ deletedCount(): number; /** * Mark a vector as deleted (tombstone deletion). * The vector remains in the index but is excluded from search results. * Use compact() to permanently remove deleted vectors and reclaim space. * * @param id The string ID of the vector to delete * @returns true if the vector was deleted, false if it didn't exist or was already deleted */ private deleteInternal; delete(id: string): Promise; /** * Mark multiple vectors as deleted (tombstone deletion). * * @param ids Array of string IDs to delete * @returns Number of vectors that were successfully deleted */ deleteBatch(ids: string[]): Promise; private deleteBatchUnlocked; /** * Check if a vector exists and is not deleted. */ has(id: string): boolean; /** Internal product-facade access to one live record. */ getRecord(id: string): StoredVectorRecord | undefined; /** Internal product-facade access to one live vector with a single defensive copy. */ getVector(id: string): Float32Array | undefined; /** Internal product-facade access to active records in stable insertion order. */ getRecords(): StoredVectorRecord[]; /** Update an existing record's metadata without rebuilding its vector. */ updateMetadata(id: string, metadata: Record): Promise; private updateMetadataUnlocked; /** Execute a coalesced, rollback-safe write session. */ runBatch(callback: (operations: CollectionBatchOperations) => Promise | T): Promise; /** Whether this collection has unflushed state. */ isDirty(): boolean; getLastFlushedAt(): Date | undefined; /** Validate in-memory maps and serialize the index as a corruption check. */ verifyState(): { ok: boolean; records: number; tombstones: number; errors: string[]; }; /** Read byte counts for the committed collection snapshot. */ storageStats(): Promise<{ indexBytes: number; metadataBytes: number; deletedBytes: number; totalBytes: number; }>; /** Export the collection's committed files for the database snapshot API. */ exportStorageFiles(): Promise>; /** * Check if a vector was deleted (tombstoned). */ isDeleted(id: string): boolean; /** * Reorder the internal HNSW index for BFS cache locality. * Remaps all internal IDs so that graph neighbors are stored * contiguously in memory, improving search cache hit rates. */ reorderIndex(): Promise; saveToDisk(): Promise; private saveToDiskUnlocked; private saveToDiskCore; private executeQuery; private searchCandidates; /** * Collect live (non-deleted) numeric ids whose metadata matches `filter`, * stopping early once more than `limit` matches are found. * * `exceeded: true` means the filter is too broad to brute-force — the * returned ids are partial and the caller should fall back to the HNSW * search path. `exceeded: false` means `ids` is the complete matching set. */ private collectFilteredIds; private metadataIndexValue; private metadataIndexKey; private metadataIndexKind; /** Rebuild schema-declared filter indexes from authoritative metadata. */ private rebuildMetadataIndexes; private addMetadataToIndexes; private removeMetadataFromIndexes; private cloneCandidateSet; private unionCandidateSets; private intersectCandidateSets; private lookupIndexedValues; private lookupRangeValues; private indexedCandidatesForField; private indexedCandidatesForFilter; /** * Exact nearest-neighbor search over an explicit set of numeric ids. * Used for selective metadata filters where brute force over the matching * set is both cheap and guarantees up to k correct results. Returns the * full matching set sorted ascending by distance; the caller slices to k. */ private searchExactWithinIds; private filterAndDeduplicateResults; private materializeResults; private validateQueryInput; private validateCountInput; private hasFilter; private validateDeleteBatchInput; private reconcileLoadedState; private matchesFilter; private validateFilterOperators; private validateAddInput; private vectorInputAt; private validateMetadataValue; private parseMetadataLine; private isPlainObject; private isFilterObject; private isOperatorObject; private deepEqual; private matchesInOperator; /** * Compact the collection by rebuilding the index without deleted vectors. * This permanently removes tombstoned vectors and reclaims space. * * @returns Number of vectors removed during compaction */ compact(): Promise; /** * Destroy the collection, freeing all in-memory resources. * @param save Whether to persist data to storage before destroying (default: true). * Pass false when the collection is being deleted entirely. */ destroy(save?: boolean): Promise; } //# sourceMappingURL=Collection.d.ts.map