@orama/orama
Advanced tools
Comparing version
@@ -0,1 +1,2 @@ | ||
import { Point } from '../trees/bkd.js'; | ||
import { AnyDocument, AnyOrama, ArraySearchableType, ElapsedTime, ScalarSearchableType, TypedDocument, Vector } from '../types.js'; | ||
@@ -6,2 +7,3 @@ export { getDocumentProperties } from '../utils.js'; | ||
export declare function validateSchema<T extends AnyOrama, ResultDocument extends TypedDocument<T>>(doc: ResultDocument, schema: T['schema']): Promise<string | undefined>; | ||
export declare function isGeoPointType(type: unknown): type is Point; | ||
export declare function isVectorType(type: unknown): type is Vector; | ||
@@ -8,0 +10,0 @@ export declare function isArrayType(type: unknown): type is ArraySearchableType; |
@@ -25,2 +25,5 @@ import { createError } from '../errors.js'; | ||
} | ||
if (type === 'geopoint' && typeof value === 'object' && typeof value.lon === 'number' && typeof value.lat === 'number') { | ||
continue; | ||
} | ||
if (type === 'enum' && (typeof value === 'string' || typeof value === 'number')) { | ||
@@ -80,2 +83,3 @@ continue; | ||
enum: false, | ||
geopoint: false, | ||
'string[]': true, | ||
@@ -92,2 +96,5 @@ 'number[]': true, | ||
}; | ||
export function isGeoPointType(type) { | ||
return type === 'geopoint'; | ||
} | ||
export function isVectorType(type) { | ||
@@ -94,0 +101,0 @@ return typeof type === 'string' && /^vector\[\d+\]$/.test(type); |
@@ -5,2 +5,3 @@ import type { AnyIndexStore, AnyOrama, IIndex, SearchableType, SearchableValue, SearchContext, Tokenizer, TokenScore, TypedDocument, VectorIndex, WhereCondition } from '../types.js'; | ||
import { Node as RadixNode } from '../trees/radix.js'; | ||
import { RootNode as BKDNode } from '../trees/bkd.js'; | ||
import { DocumentID, InternalDocumentID, InternalDocumentIDStore } from './internal-document-id-store.js'; | ||
@@ -18,3 +19,3 @@ export type FrequencyMap = { | ||
}; | ||
export type TreeType = 'AVL' | 'Radix' | 'Bool' | 'Flat'; | ||
export type TreeType = 'AVL' | 'Radix' | 'Bool' | 'Flat' | 'BKD'; | ||
export type TTree<T = TreeType, N = unknown> = { | ||
@@ -25,3 +26,3 @@ type: T; | ||
}; | ||
export type Tree = TTree<'Radix', RadixNode> | TTree<'AVL', AVLNode<number, InternalDocumentID[]>> | TTree<'Bool', BooleanIndex> | TTree<'Flat', FlatTree>; | ||
export type Tree = TTree<'Radix', RadixNode> | TTree<'AVL', AVLNode<number, InternalDocumentID[]>> | TTree<'Bool', BooleanIndex> | TTree<'Flat', FlatTree> | TTree<'BKD', BKDNode>; | ||
export interface Index extends AnyIndexStore { | ||
@@ -28,0 +29,0 @@ sharedInternalDocumentStore: InternalDocumentIDStore; |
@@ -5,3 +5,4 @@ import { createError } from '../errors.js'; | ||
import { create as radixCreate, find as radixFind, insert as radixInsert, removeDocumentByWord as radixRemoveDocument } from '../trees/radix.js'; | ||
import { intersect, safeArrayPush } from '../utils.js'; | ||
import { create as bkdCreate, insert as bkdInsert, removeDocByID as bkdRemoveDocByID, searchByRadius, searchByPolygon } from '../trees/bkd.js'; | ||
import { convertDistanceToMeters, intersect, safeArrayPush } from '../utils.js'; | ||
import { BM25 } from './algorithms.js'; | ||
@@ -136,2 +137,9 @@ import { getMagnitude } from './cosine-similarity.js'; | ||
break; | ||
case 'geopoint': | ||
index.indexes[path] = { | ||
type: 'BKD', | ||
node: bkdCreate(), | ||
isArray | ||
}; | ||
break; | ||
default: | ||
@@ -156,6 +164,8 @@ throw createError('INVALID_SCHEMA_TYPE', Array.isArray(type) ? 'array' : type, path); | ||
case 'AVL': | ||
avlInsert(node, value, [ | ||
internalId | ||
]); | ||
break; | ||
{ | ||
avlInsert(node, value, [ | ||
internalId | ||
]); | ||
break; | ||
} | ||
case 'Radix': | ||
@@ -176,2 +186,9 @@ { | ||
} | ||
case 'BKD': | ||
{ | ||
bkdInsert(node, value, [ | ||
internalId | ||
]); | ||
break; | ||
} | ||
} | ||
@@ -239,2 +256,7 @@ } | ||
} | ||
case 'BKD': | ||
{ | ||
bkdRemoveDocByID(node, value, internalId); | ||
return false; | ||
} | ||
} | ||
@@ -294,2 +316,25 @@ } | ||
} | ||
if (type === 'BKD') { | ||
let reqOperation; | ||
if ('radius' in operation) { | ||
reqOperation = 'radius'; | ||
} else if ('polygon' in operation) { | ||
reqOperation = 'polygon'; | ||
} else { | ||
throw new Error(`Invalid operation ${operation}`); | ||
} | ||
if (reqOperation === 'radius') { | ||
const { value , coordinates , unit ='m' , inside =true } = operation[reqOperation]; | ||
const distanceInMeters = convertDistanceToMeters(value, unit); | ||
const ids = searchByRadius(node.root, coordinates, distanceInMeters, inside); | ||
// @todo: convert this into a for loop | ||
safeArrayPush(filtersMap[param], ids.map(({ docIDs })=>docIDs).flat()); | ||
} else { | ||
const { coordinates , inside =true } = operation[reqOperation]; | ||
const ids = searchByPolygon(node.root, coordinates, inside); | ||
// @todo: convert this into a for loop | ||
safeArrayPush(filtersMap[param], ids.map(({ docIDs })=>docIDs).flat()); | ||
} | ||
continue; | ||
} | ||
if (type === 'Radix' && (typeof operation === 'string' || Array.isArray(operation))) { | ||
@@ -296,0 +341,0 @@ for (const raw of [ |
@@ -48,2 +48,3 @@ import { createError } from '../errors.js'; | ||
break; | ||
case 'geopoint': | ||
case 'enum': | ||
@@ -50,0 +51,0 @@ continue; |
@@ -32,2 +32,3 @@ declare const errors: { | ||
FACET_NOT_SUPPORTED: string; | ||
INVALID_DISTANCE_SUFFIX: string; | ||
}; | ||
@@ -34,0 +35,0 @@ export type ErrorCode = keyof typeof errors; |
@@ -34,3 +34,4 @@ import { SUPPORTED_LANGUAGES } from './components/tokenizer/languages.js'; | ||
WRONG_SEARCH_PROPERTY_TYPE: `Property "%s" is not searchable. Only "string" properties are searchable.`, | ||
FACET_NOT_SUPPORTED: `Facet doens't support the type "%s".` | ||
FACET_NOT_SUPPORTED: `Facet doens't support the type "%s".`, | ||
INVALID_DISTANCE_SUFFIX: `Invalid distance suffix "%s". Valid suffixes are: cm, m, km, mi, yd, ft.` | ||
}; | ||
@@ -37,0 +38,0 @@ export function createError(code, ...args) { |
@@ -1,2 +0,2 @@ | ||
import { isArrayType, isVectorType } from '../components.js'; | ||
import { isArrayType, isGeoPointType, isVectorType } from '../components.js'; | ||
import { runMultipleHook, runSingleHook } from '../components/hooks.js'; | ||
@@ -34,2 +34,5 @@ import { trackInsertion } from '../components/sync-blocking-checker.js'; | ||
const expectedType = indexablePropertiesWithTypes[key]; | ||
if (isGeoPointType(expectedType) && typeof value === 'object' && typeof value.lon === 'number' && typeof value.lat === 'number') { | ||
continue; | ||
} | ||
if (isVectorType(expectedType) && Array.isArray(value)) { | ||
@@ -36,0 +39,0 @@ continue; |
export * as radix from './trees/radix.js'; | ||
export * as avl from './trees/avl.js'; | ||
export * as zip from './trees/zip.js'; | ||
export * as bkd from './trees/bkd.js'; |
export * as radix from './trees/radix.js'; | ||
export * as avl from './trees/avl.js'; | ||
export * as zip from './trees/zip.js'; | ||
export * as bkd from './trees/bkd.js'; | ||
//# sourceMappingURL=trees.js.map |
@@ -1,3 +0,3 @@ | ||
import { InternalDocumentID } from '../components/internal-document-id-store.js'; | ||
import { EnumArrComparisonOperator, EnumComparisonOperator, Nullable, ScalarSearchableValue } from '../types.js'; | ||
import { InternalDocumentID } from "../components/internal-document-id-store.js"; | ||
import { EnumArrComparisonOperator, EnumComparisonOperator, Nullable, ScalarSearchableValue } from "../types.js"; | ||
export interface FlatTree { | ||
@@ -4,0 +4,0 @@ numberToDocumentId: Map<ScalarSearchableValue, InternalDocumentID[]>; |
@@ -1,2 +0,2 @@ | ||
import { intersect, safeArrayPush } from '../utils.js'; | ||
import { intersect, safeArrayPush } from "../utils.js"; | ||
export function create() { | ||
@@ -3,0 +3,0 @@ return { |
@@ -6,2 +6,3 @@ import { DocumentsStore } from './components/documents-store.js'; | ||
import { Language } from './components/tokenizer/languages.js'; | ||
import { Point } from './trees/bkd.js'; | ||
export type Nullable<T> = T | null; | ||
@@ -15,3 +16,3 @@ export type SingleOrArray<T> = T | T[]; | ||
} extends Record<keyof T, (y: infer O) => void> ? O : never; | ||
export type SchemaTypes<Value> = Value extends 'string' ? string : Value extends 'string[]' ? string[] : Value extends 'boolean' ? boolean : Value extends 'boolean[]' ? boolean[] : Value extends 'number' ? number : Value extends 'number[]' ? number[] : Value extends 'enum' ? string | number : Value extends 'enum[]' ? (string | number)[] : Value extends `vector[${number}]` ? number[] : Value extends object ? { | ||
export type SchemaTypes<Value> = Value extends 'string' ? string : Value extends 'string[]' ? string[] : Value extends 'boolean' ? boolean : Value extends 'boolean[]' ? boolean[] : Value extends 'number' ? number : Value extends 'number[]' ? number[] : Value extends 'enum' ? string | number : Value extends 'enum[]' ? (string | number)[] : Value extends 'geopoint' ? Point : Value extends `vector[${number}]` ? number[] : Value extends object ? { | ||
[Key in keyof Value]: SchemaTypes<Value[Key]>; | ||
@@ -48,6 +49,6 @@ } & { | ||
export type VectorType = Float32Array; | ||
export type ScalarSearchableType = 'string' | 'number' | 'boolean' | 'enum'; | ||
export type ScalarSearchableType = 'string' | 'number' | 'boolean' | 'enum' | 'geopoint'; | ||
export type ArraySearchableType = 'string[]' | 'number[]' | 'boolean[]' | 'enum[]' | Vector; | ||
export type SearchableType = ScalarSearchableType | ArraySearchableType; | ||
export type ScalarSearchableValue = string | number | boolean; | ||
export type ScalarSearchableValue = string | number | boolean | Point; | ||
export type ArraySearchableValue = string[] | number[] | boolean[] | VectorType; | ||
@@ -68,3 +69,4 @@ export type SearchableValue = ScalarSearchableValue | ArraySearchableValue; | ||
}; | ||
export type FacetSorting = 'asc' | 'desc' | 'ASC' | 'DESC'; | ||
export type GenericSorting = 'asc' | 'desc' | 'ASC' | 'DESC'; | ||
export type FacetSorting = GenericSorting; | ||
export interface StringFacetDefinition { | ||
@@ -113,3 +115,19 @@ limit?: number; | ||
}; | ||
export type Operator<Value> = Value extends 'string' ? (string | string[]) : Value extends 'string[]' ? (string | string[]) : Value extends 'boolean' ? boolean : Value extends 'boolean[]' ? boolean : Value extends 'number' ? ComparisonOperator : Value extends 'number[]' ? ComparisonOperator : Value extends 'enum' ? EnumComparisonOperator : Value extends 'enum[]' ? EnumArrComparisonOperator : never; | ||
export type GeosearchDistanceUnit = 'cm' | 'm' | 'km' | 'ft' | 'yd' | 'mi'; | ||
export type GeosearchRadiusOperator = { | ||
radius: { | ||
coordinates: Point; | ||
value: number; | ||
unit?: GeosearchDistanceUnit; | ||
inside?: boolean; | ||
}; | ||
}; | ||
export type GeosearchPolygonOperator = { | ||
polygon: { | ||
coordinates: Point[]; | ||
inside?: boolean; | ||
}; | ||
}; | ||
export type GeosearchOperation = GeosearchRadiusOperator | GeosearchPolygonOperator; | ||
export type Operator<Value> = Value extends 'string' ? (string | string[]) : Value extends 'string[]' ? (string | string[]) : Value extends 'boolean' ? boolean : Value extends 'boolean[]' ? boolean : Value extends 'number' ? ComparisonOperator : Value extends 'number[]' ? ComparisonOperator : Value extends 'enum' ? EnumComparisonOperator : Value extends 'enum[]' ? EnumArrComparisonOperator : Value extends 'geopoint' ? GeosearchOperation : never; | ||
export type WhereCondition<TSchema> = { | ||
@@ -116,0 +134,0 @@ [key in keyof TSchema]?: Operator<TSchema[key]>; |
@@ -1,2 +0,2 @@ | ||
import type { AnyDocument, SearchableValue, TokenScore } from './types.js'; | ||
import type { AnyDocument, GeosearchDistanceUnit, SearchableValue, TokenScore } from './types.js'; | ||
export declare const isServer: boolean; | ||
@@ -19,3 +19,3 @@ /** | ||
export declare function safeArrayPush<T>(arr: T[], newArr: T[]): void; | ||
export declare function sprintf(template: string, ...args: (string | number)[]): string; | ||
export declare function sprintf(template: string, ...args: Array<string | number>): string; | ||
export declare function formatBytes(bytes: number, decimals?: number): Promise<string>; | ||
@@ -29,5 +29,6 @@ export declare function formatNanoseconds(value: number | bigint): Promise<string>; | ||
export declare function sortTokenScorePredicate(a: TokenScore, b: TokenScore): number; | ||
export declare function intersect<T>(arrays: ReadonlyArray<T>[]): T[]; | ||
export declare function intersect<T>(arrays: Array<readonly T[]>): T[]; | ||
export declare function getDocumentProperties(doc: AnyDocument, paths: string[]): Promise<Record<string, SearchableValue>>; | ||
export declare function getNested<T = SearchableValue>(obj: object, path: string): Promise<T | undefined>; | ||
export declare function flattenObject(obj: object, prefix?: string): AnyDocument; | ||
export declare function convertDistanceToMeters(distance: number, unit: GeosearchDistanceUnit): number; |
@@ -0,1 +1,2 @@ | ||
import { createError } from './errors.js'; | ||
const baseId = Date.now().toString().slice(5); | ||
@@ -184,5 +185,10 @@ let lastId = 0; | ||
// We found an object but we were supposed to be done | ||
if (typeof current === 'object' && !Array.isArray(current) && current !== null && j === pathTokensLength - 1) { | ||
current = undefined; | ||
break; | ||
if (typeof current === 'object') { | ||
if (current !== null && 'lat' in current && 'lon' in current && typeof current.lat === 'number' && typeof current.lon === 'number') { | ||
current = properties[path] = current; | ||
break; | ||
} else if (!Array.isArray(current) && current !== null && j === pathTokensLength - 1) { | ||
current = undefined; | ||
break; | ||
} | ||
} else if ((current === null || typeof current !== 'object') && j < pathTokensLength - 1) { | ||
@@ -219,3 +225,18 @@ // We can't recurse anymore but we were supposed to | ||
} | ||
const mapDistanceToMeters = { | ||
cm: 0.01, | ||
m: 1, | ||
km: 1000, | ||
ft: 0.3048, | ||
yd: 0.9144, | ||
mi: 1609.344 | ||
}; | ||
export function convertDistanceToMeters(distance, unit) { | ||
const ratio = mapDistanceToMeters[unit]; | ||
if (ratio === undefined) { | ||
throw new Error(createError('INVALID_DISTANCE_SUFFIX', distance).message); | ||
} | ||
return distance * ratio; | ||
} | ||
//# sourceMappingURL=utils.js.map |
{ | ||
"name": "@orama/orama", | ||
"version": "1.2.11", | ||
"version": "2.0.0-beta.1", | ||
"type": "module", | ||
@@ -92,4 +92,4 @@ "description": "Next generation full-text and vector search engine, written in TypeScript", | ||
"vite": "^4.1.4", | ||
"@orama/stemmers": "1.2.11", | ||
"@orama/stopwords": "1.2.11" | ||
"@orama/stemmers": "2.0.0-beta.1", | ||
"@orama/stopwords": "2.0.0-beta.1" | ||
}, | ||
@@ -96,0 +96,0 @@ "engines": { |
@@ -18,2 +18,3 @@ # Orama | ||
- [Search filters](https://docs.oramasearch.com/usage/search/filters) | ||
- [Geosearch](https://docs.oramasearch.com/usage/search/geosearch) | ||
- [Facets](https://docs.oramasearch.com/usage/search/facets) | ||
@@ -20,0 +21,0 @@ - [Fields Boosting](https://docs.oramasearch.com/usage/search/fields-boosting) |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
603929
7.39%139
2.21%6234
7.63%245
0.41%2
100%