UNPKG

@orama/orama

Version:

A complete search engine and RAG pipeline in your browser, server, or edge network with support for full-text, vector, and hybrid search in less than 2kb.

102 lines 4.46 kB
import { getNanosecondsTime, formatNanoseconds, sortTokenScorePredicate } from '../utils.js'; import { getFacets } from '../components/facets.js'; import { createError } from '../errors.js'; import { getGroups } from '../components/groups.js'; import { getDocumentIdFromInternalId } from '../components/internal-document-id-store.js'; import { runBeforeSearch, runAfterSearch } from '../components/hooks.js'; import { DEFAULT_SIMILARITY } from '../trees/vector.js'; import { applyPinningRules } from '../components/pinning-manager.js'; export function innerVectorSearch(orama, params, language) { const vector = params.vector; if (vector && (!('value' in vector) || !('property' in vector))) { throw createError('INVALID_VECTOR_INPUT', Object.keys(vector).join(', ')); } const vectorIndex = orama.data.index.vectorIndexes[vector.property]; if (!vectorIndex) { throw createError('UNKNOWN_VECTOR_PROPERTY', vector.property); } const vectorSize = vectorIndex.node.size; if (vector?.value.length !== vectorSize) { if (vector?.property === undefined || vector?.value.length === undefined) { throw createError('INVALID_INPUT_VECTOR', 'undefined', vectorSize, 'undefined'); } throw createError('INVALID_INPUT_VECTOR', vector.property, vectorSize, vector.value.length); } const index = orama.data.index; let whereFiltersIDs; const hasFilters = Object.keys(params.where ?? {}).length > 0; if (hasFilters) { whereFiltersIDs = orama.index.searchByWhereClause(index, orama.tokenizer, params.where, language); } return vectorIndex.node.find(vector.value, params.similarity ?? DEFAULT_SIMILARITY, whereFiltersIDs); } export function searchVector(orama, params, language = 'english') { const timeStart = getNanosecondsTime(); function performSearchLogic() { let results = innerVectorSearch(orama, params, language).sort(sortTokenScorePredicate); // Apply pinning rules after sorting but before pagination results = applyPinningRules(orama, orama.data.pinning, results, undefined); let facetsResults = []; const shouldCalculateFacets = params.facets && Object.keys(params.facets).length > 0; if (shouldCalculateFacets) { const facets = getFacets(orama, results, params.facets); facetsResults = facets; } const vectorProperty = params.vector.property; const includeVectors = params.includeVectors ?? false; const limit = params.limit ?? 10; const offset = params.offset ?? 0; const docs = Array.from({ length: limit }); for (let i = 0; i < limit; i++) { const result = results[i + offset]; if (!result) { break; } const doc = orama.data.docs.docs[result[0]]; if (doc) { if (!includeVectors) { doc[vectorProperty] = null; } const newDoc = { id: getDocumentIdFromInternalId(orama.internalDocumentIDStore, result[0]), score: result[1], document: doc }; docs[i] = newDoc; } } let groups = []; if (params.groupBy) { groups = getGroups(orama, results, params.groupBy); } const timeEnd = getNanosecondsTime(); const elapsedTime = timeEnd - timeStart; return { count: results.length, hits: docs.filter(Boolean), elapsed: { raw: Number(elapsedTime), formatted: formatNanoseconds(elapsedTime) }, ...(facetsResults ? { facets: facetsResults } : {}), ...(groups ? { groups } : {}) }; } async function executeSearchAsync() { if (orama.beforeSearch) { await runBeforeSearch(orama.beforeSearch, orama, params, language); } const results = performSearchLogic(); if (orama.afterSearch) { await runAfterSearch(orama.afterSearch, orama, params, language, results); } return results; } const asyncNeeded = orama.beforeSearch?.length || orama.afterSearch?.length; if (asyncNeeded) { return executeSearchAsync(); } // Sync path return performSearchLogic(); } //# sourceMappingURL=search-vector.js.map