@kedem/okdb 1.2.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/okdb.js +1 -1
- package/docs/http-api.md +2 -0
- package/docs/querying.md +110 -0
- package/okdb.js +1 -1
- package/package.json +1 -1
package/docs/http-api.md
CHANGED
|
@@ -349,6 +349,8 @@ POST /api/:env/type/:type/query → query records
|
|
|
349
349
|
POST /api/:env/transaction → atomic batch writes
|
|
350
350
|
```
|
|
351
351
|
|
|
352
|
+
**Hybrid search:** The `options` body field now accepts `fts` and `vector` sub-objects alongside `index`. See the querying guide for full documentation. When `fts` or `vector` is provided, the route automatically awaits the async result.
|
|
353
|
+
|
|
352
354
|
```bash
|
|
353
355
|
# Get a record
|
|
354
356
|
curl http://localhost:8080/api/default/type/users/item/alice \
|
package/docs/querying.md
CHANGED
|
@@ -192,6 +192,116 @@ const open = okdb.countByIndex('orders', ['status', 'createdAt'], {
|
|
|
192
192
|
|
|
193
193
|
---
|
|
194
194
|
|
|
195
|
+
## Hybrid queries
|
|
196
|
+
|
|
197
|
+
`query()` accepts `fts` and `vector` options to combine full-text search, semantic similarity, and index constraints in a single call. All signals compose — the result is a unified ranked list with sift post-filtering applied last.
|
|
198
|
+
|
|
199
|
+
### FTS signal
|
|
200
|
+
|
|
201
|
+
```javascript
|
|
202
|
+
// Full-text search — returns results ordered by relevance score
|
|
203
|
+
const results = await okdb.query(
|
|
204
|
+
'articles',
|
|
205
|
+
{},
|
|
206
|
+
{
|
|
207
|
+
fts: { name: 'articles_fts', query: 'database indexing' },
|
|
208
|
+
limit: 20,
|
|
209
|
+
},
|
|
210
|
+
);
|
|
211
|
+
// Each result has: { key, value, ftsScore, numTerms, maxScore }
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### FTS + index constraint
|
|
215
|
+
|
|
216
|
+
The index acts as a **hard constraint** — only documents present in the index range are returned. It does not affect ranking.
|
|
217
|
+
|
|
218
|
+
```javascript
|
|
219
|
+
// FTS results, but only from published articles
|
|
220
|
+
const results = await okdb.query(
|
|
221
|
+
'articles',
|
|
222
|
+
{},
|
|
223
|
+
{
|
|
224
|
+
fts: { name: 'articles_fts', query: 'database indexing' },
|
|
225
|
+
index: { fields: ['status'], prefix: ['published'] },
|
|
226
|
+
limit: 20,
|
|
227
|
+
},
|
|
228
|
+
);
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### FTS + sift post-filter
|
|
232
|
+
|
|
233
|
+
Sift filter is always applied last, after FTS and index narrowing:
|
|
234
|
+
|
|
235
|
+
```javascript
|
|
236
|
+
const results = await okdb.query(
|
|
237
|
+
'articles',
|
|
238
|
+
{ category: 'tech' },
|
|
239
|
+
{
|
|
240
|
+
fts: { name: 'articles_fts', query: 'indexing' },
|
|
241
|
+
limit: 20,
|
|
242
|
+
},
|
|
243
|
+
);
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### FTS + vector (hybrid semantic + keyword)
|
|
247
|
+
|
|
248
|
+
When both `fts` and `vector` are provided, candidates from each signal are combined and re-ranked using **Reciprocal Rank Fusion (RRF)**. RRF works across incomparable score scales — no normalization needed.
|
|
249
|
+
|
|
250
|
+
```javascript
|
|
251
|
+
const results = await okdb.query(
|
|
252
|
+
'articles',
|
|
253
|
+
{},
|
|
254
|
+
{
|
|
255
|
+
fts: { name: 'articles_fts', query: 'database' },
|
|
256
|
+
vector: { engine: 'articles_vec', query: 'fast persistent storage', limit: 50 },
|
|
257
|
+
limit: 20,
|
|
258
|
+
},
|
|
259
|
+
);
|
|
260
|
+
// Each result has: { key, value, score (RRF), ftsScore?, vectorScore? }
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Signal semantics
|
|
264
|
+
|
|
265
|
+
| Signal | Ordering | Can enumerate all matches | Notes |
|
|
266
|
+
| -------- | ---------------- | ------------------------- | ------------------------------------- |
|
|
267
|
+
| `index` | Field value | Yes | Hard constraint only — never reorders |
|
|
268
|
+
| `fts` | Relevance score | Yes | Posting list intersection |
|
|
269
|
+
| `vector` | Similarity score | No — K-bounded | ANN search, approximate |
|
|
270
|
+
|
|
271
|
+
**Important:** `query()` returns a **Promise** when `fts` or `vector` is present (vector search requires async embedding inference). Without these options, `query()` remains synchronous.
|
|
272
|
+
|
|
273
|
+
### FTS options
|
|
274
|
+
|
|
275
|
+
| Option | Type | Default | Description |
|
|
276
|
+
| -------- | --------------- | -------------------- | --------------------------------------------- |
|
|
277
|
+
| `name` | string | required | Registered FTS index name |
|
|
278
|
+
| `query` | string | `''` | Text to search |
|
|
279
|
+
| `mode` | `'and'`\|`'or'` | `'and'` | AND: all terms required. OR: any term matches |
|
|
280
|
+
| `prefix` | boolean | false | Enable prefix matching on last token |
|
|
281
|
+
| `limit` | number | `max(limit×10, 200)` | FTS candidate pool size |
|
|
282
|
+
|
|
283
|
+
### Vector options
|
|
284
|
+
|
|
285
|
+
| Option | Type | Default | Description |
|
|
286
|
+
| -------- | ------ | ------------------- | ------------------------- |
|
|
287
|
+
| `engine` | string | required | Vector search engine name |
|
|
288
|
+
| `query` | string | required | Semantic query text |
|
|
289
|
+
| `limit` | number | `max(limit×4, 100)` | ANN candidate pool size |
|
|
290
|
+
|
|
291
|
+
### Nested index form
|
|
292
|
+
|
|
293
|
+
The `index` option accepts a nested object for clarity:
|
|
294
|
+
|
|
295
|
+
```javascript
|
|
296
|
+
// Nested form (preferred for hybrid queries)
|
|
297
|
+
{ index: { fields: ['status'], prefix: ['active'] } }
|
|
298
|
+
|
|
299
|
+
// Flat form (still works — backward compatible)
|
|
300
|
+
{ index: ['status'], prefix: ['active'] }
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
---
|
|
304
|
+
|
|
195
305
|
## Geo query
|
|
196
306
|
|
|
197
307
|
OKDB has a built-in geospatial index based on geohash. Register a geo index on a field that stores `{ lat, lon }` (or an `[lat, lon]` array):
|