UNPKG

harperdb

Version:

HarperDB is a distributed database, caching service, streaming broker, and application development platform focused on performance and ease of use.

88 lines (87 loc) 3.95 kB
import type { Id } from '../../resources/ResourceInterface.ts'; /** * Represents a Hierarchical Navigable Small World (HNSW) index for approximate nearest neighbor search. * This implementation is based on hierarchical graph navigation to efficiently index and search high-dimensional vectors. * A HNSW is basically a multi-dimensional skip list. Each node has (potentially) higher levels that are used for quickly * traversing the graph get in the neighborhood of the node, and then lower levels are used to more accurately find the * closest neighbors. * * This implementation is based on the paper "Efficient and Robust Approximate Nearest Neighbor Search in High Dimensions" * (mostly influenced AI's contributions) */ export declare class HierarchicalNavigableSmallWorld { static useObjectStore: boolean; indexStore: any; M: number; efConstruction: number; efConstructionSearch: number; mL: number; optimizeRouting: number; nodesVisitedCount: number; idIncrementer: BigInt64Array | undefined; distance: (a: number[], b: number[]) => number; constructor(indexStore: any, options: any); index(primaryKey: Id, vector: number[], existingVector?: number[]): void; private getEntryPoint; /** * Search one layer of the skip-list using HNSW algorithm for creating a candidate list and navigating the graph * TODO: This should be async, but we can't really do that with lmdb-js's transaction system right now. Should be * doable with RocksDB. We could also create an async version for searching. * @param queryVector * @param entryPointId * @param entryPoint * @param ef * @param level * @param distanceFunction * @private */ private searchLayer; /** * This the main entry from Harper's query functionality, where we actually search for an ordered list of nearest * neighbors, using the provided sort/order definition object and performing the multi-layer skip-list search. * This returns an iterable of the nearest neighbors to the provided target vector, with nearest ordered first. * @param target * @param value * @param descending * @param distance * @param comparator * @param context */ search({ target, value, descending, distance, comparator, }: { target: number[]; value: number; descending: boolean; distance: string; comparator: string; }): { key: string; distance: number; }[]; private checkSymmetry; private addConnection; validateConnectivity(startLevel?: number): { isFullyConnected: boolean; averageConnections: number; }; get totalNodes(): number; /** * This is used by the query planner to determine what order to apply conditions. It is our best guess at an estimated count. * This unit is typically the number of records that need to be accessed to satisfy the query. We know that we will visit * a minimum of efConstructionSearch nodes and a maximum of the total nodes (in absolute worst case). * The original paper described the complexity as polylogarithmic. From my testing, the * best and simplest guess at the number of nodes that need to be accessed is the geometric mean of the total number of nodes * and the efConstruction parameter (for search), which clearly constrains the estimate to the correct range and is * similar to polylogarithmic for realistic values. * * @returns */ estimateCountAsSort(): number; /** * This is used to resolve the vector property, which should be resolved to the distance when used in a sort comparator * We also want to cache distance calculations so they can be accessed efficently later * @param vector * @param context * @param entry */ propertyResolver(vector: number[], context: any, entry: any): any; }