@infino-ai/infino 0.1.0 → 0.1.1
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/README.md +49 -18
- package/infino/index.d.ts +28 -5
- package/infino/index.js +5 -0
- package/infino/native.d.ts +23 -7
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -144,18 +144,22 @@ vecs.vectorSearch("emb", queryVector, 10, {
|
|
|
144
144
|
|
|
145
145
|
## Hybrid search
|
|
146
146
|
|
|
147
|
-
Combine BM25 and vector search in **one
|
|
148
|
-
|
|
147
|
+
Combine BM25 and vector search in **one call** — a single pass over both
|
|
148
|
+
indexes, fused inside the engine with reciprocal-rank fusion (no separate
|
|
149
149
|
reranker service, no two round-trips). Keyword-only search misses paraphrases;
|
|
150
150
|
vector-only search misses exact terms — hybrid gets both. Results come back
|
|
151
|
-
best-first with a fused `score
|
|
151
|
+
best-first with a fused `score` (higher is better).
|
|
152
152
|
|
|
153
153
|
```javascript
|
|
154
154
|
const spec = new IndexSpec().fts("body").vector("emb", 384, 256, "cosine");
|
|
155
155
|
const docs = db.createTable("docs", { body: "large_utf8", emb: { vector: 384 } }, spec);
|
|
156
156
|
docs.append([{ body: "To cancel a subscription, open Settings then Billing.", emb: embed(/* … */) }]);
|
|
157
157
|
|
|
158
|
-
//
|
|
158
|
+
// hybridSearch(textColumn, textQuery, vectorColumn, vectorQuery, k, opts?)
|
|
159
|
+
docs.hybridSearch("body", "cancel subscription", "emb", embed("how do I stop my plan?"), 10);
|
|
160
|
+
// opts: { mode } tunes the BM25 side, { nprobe } the vector side.
|
|
161
|
+
|
|
162
|
+
// The same fusion is also a SQL table function, so it composes in a query:
|
|
159
163
|
const qvec = embed("how do I stop my plan?").join(",");
|
|
160
164
|
db.querySql(
|
|
161
165
|
`SELECT _id, score FROM hybrid_search('docs', 'body', 'cancel subscription', 'emb', '${qvec}', 10)`,
|
|
@@ -226,24 +230,51 @@ docs.optimize({ targetSuperfileSizeMb: 256, minFillPercent: 50 });
|
|
|
226
230
|
|
|
227
231
|
`connect` selects the backend from the URI:
|
|
228
232
|
|
|
229
|
-
| URI
|
|
230
|
-
|
|
|
231
|
-
| `./data`, `/abs/path`
|
|
232
|
-
| `s3://bucket/prefix`
|
|
233
|
-
| `
|
|
233
|
+
| URI | Backend |
|
|
234
|
+
| ------------------------ | ---------------------------------------- |
|
|
235
|
+
| `./data`, `/abs/path` | Local filesystem |
|
|
236
|
+
| `s3://bucket/prefix` | Amazon S3 / S3-compatible object storage |
|
|
237
|
+
| `az://container/prefix` | Azure Blob Storage |
|
|
238
|
+
| `memory://` | In-process, ephemeral (testing) |
|
|
234
239
|
|
|
235
|
-
|
|
236
|
-
|
|
240
|
+
Credentials go in `storageOptions`, keyed by the standard `object_store` config
|
|
241
|
+
strings (`aws_*` / `azure_*` — the same names the AWS and Azure SDKs use). Omit
|
|
242
|
+
them to use ambient cloud identity (IAM instance role / managed identity);
|
|
243
|
+
infino reads no credentials from the environment.
|
|
237
244
|
|
|
238
245
|
```javascript
|
|
246
|
+
// S3
|
|
239
247
|
const db = connect("s3://bucket/prefix", {
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
248
|
+
storageOptions: {
|
|
249
|
+
aws_access_key_id: "…",
|
|
250
|
+
aws_secret_access_key: "…",
|
|
251
|
+
aws_region: "us-east-1",
|
|
252
|
+
},
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
// Azure
|
|
256
|
+
const db = connect("az://container/prefix", {
|
|
257
|
+
storageOptions: {
|
|
258
|
+
azure_storage_account_name: "…",
|
|
259
|
+
azure_storage_account_key: "…",
|
|
260
|
+
},
|
|
244
261
|
});
|
|
245
262
|
```
|
|
246
263
|
|
|
264
|
+
Common keys:
|
|
265
|
+
|
|
266
|
+
| Backend | Keys |
|
|
267
|
+
| ------- | ---- |
|
|
268
|
+
| S3 | `aws_access_key_id`, `aws_secret_access_key`, `aws_region`, `aws_session_token`, `aws_endpoint` |
|
|
269
|
+
| Azure | `azure_storage_account_name`, `azure_storage_account_key`, `azure_storage_sas_key`, `azure_storage_client_id`, `azure_storage_client_secret`, `azure_storage_tenant_id` |
|
|
270
|
+
|
|
271
|
+
The full set is whatever `object_store` accepts for the backend; an unknown key
|
|
272
|
+
is rejected at `connect`. Pass `validate: true` to probe the backend at
|
|
273
|
+
`connect`, so wrong credentials or an unreachable bucket throw there instead of
|
|
274
|
+
on the first query. For an S3-compatible endpoint (MinIO / R2 / Ceph), set
|
|
275
|
+
`aws_endpoint` (with `aws_allow_http: "true"` for plain HTTP) alongside the
|
|
276
|
+
credentials.
|
|
277
|
+
|
|
247
278
|
### Local disk cache
|
|
248
279
|
|
|
249
280
|
For object-storage-backed catalogs, a local disk cache keeps hot data on fast
|
|
@@ -273,9 +304,9 @@ const db = connect("s3://bucket/prefix", {
|
|
|
273
304
|
## API reference
|
|
274
305
|
|
|
275
306
|
- `connect(uri, options?)` — backend from the URI scheme. `options`:
|
|
276
|
-
|
|
277
|
-
`
|
|
278
|
-
|
|
307
|
+
`storageOptions` (credentials, keyed by `object_store`'s `aws_*` / `azure_*`
|
|
308
|
+
strings), `validate`, and a local disk cache (`cacheDir`, `cacheBudgetBytes`,
|
|
309
|
+
`coldFetchMode`).
|
|
279
310
|
- `Connection`
|
|
280
311
|
- `createTable(name, schema, IndexSpec)` / `openTable(name)` /
|
|
281
312
|
`dropTable(name, purge?)` (`purge = true` also deletes the data) /
|
package/infino/index.d.ts
CHANGED
|
@@ -17,17 +17,23 @@ export type SchemaDescriptor = Record<string, string | {
|
|
|
17
17
|
export type AppendData = RowRecord[] | arrow.Table | arrow.RecordBatch | Buffer | Uint8Array;
|
|
18
18
|
/** Storage and cache config the `connect` URI can't carry. All optional. */
|
|
19
19
|
export interface ConnectOptions {
|
|
20
|
-
/**
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Credentials/tuning for the URI-selected backend, keyed by `object_store`
|
|
22
|
+
* config strings (`aws_*` / `azure_*`). An unknown key is rejected at
|
|
23
|
+
* `connect`.
|
|
24
|
+
*/
|
|
25
|
+
storageOptions?: Record<string, string>;
|
|
25
26
|
/** Local disk-cache directory for remote-backed tables. */
|
|
26
27
|
cacheDir?: string;
|
|
27
28
|
/** Disk-cache budget in bytes. */
|
|
28
29
|
cacheBudgetBytes?: number;
|
|
29
30
|
/** How cold misses are serviced. */
|
|
30
31
|
coldFetchMode?: "hybrid_with_prefetch" | "range_only" | "lazy_foreground_with_background_fill";
|
|
32
|
+
/**
|
|
33
|
+
* Probe the object store at `connect` (default `false`). `true` fails fast
|
|
34
|
+
* on bad credentials instead of on the first table operation.
|
|
35
|
+
*/
|
|
36
|
+
validate?: boolean;
|
|
31
37
|
}
|
|
32
38
|
/** Row counts returned by `update` / `delete`. */
|
|
33
39
|
export interface MutationStats {
|
|
@@ -74,6 +80,16 @@ export interface VectorSearchOptions {
|
|
|
74
80
|
/** Restrict the kNN to rows matching a text predicate (pushdown pre-filter). */
|
|
75
81
|
filter?: VectorFilter;
|
|
76
82
|
}
|
|
83
|
+
/** Options for `hybridSearch`. `mode` applies to the BM25 side; `nprobe` to
|
|
84
|
+
* the vector side. */
|
|
85
|
+
export interface HybridSearchOptions {
|
|
86
|
+
/** BM25 boolean mode: `"or"` (default) or `"and"`. */
|
|
87
|
+
mode?: BoolMode;
|
|
88
|
+
/** IVF partitions to probe on the vector side (higher = better recall). */
|
|
89
|
+
nprobe?: number;
|
|
90
|
+
projection?: string[];
|
|
91
|
+
arrow?: boolean;
|
|
92
|
+
}
|
|
77
93
|
export interface TokenMatchOptions {
|
|
78
94
|
mode?: BoolMode;
|
|
79
95
|
projection?: string[];
|
|
@@ -107,6 +123,13 @@ export declare class Table {
|
|
|
107
123
|
arrow: true;
|
|
108
124
|
}): arrow.Table;
|
|
109
125
|
vectorSearch(column: string, query: number[] | Float32Array, k: number, opts?: VectorSearchOptions): RowRecord[];
|
|
126
|
+
/** Hybrid BM25 + vector search, fused with reciprocal-rank fusion; rows as
|
|
127
|
+
* records (or an Arrow `Table`). `score` is the fused RRF score (higher is
|
|
128
|
+
* better). */
|
|
129
|
+
hybridSearch(textColumn: string, textQuery: string, vectorColumn: string, vectorQuery: number[] | Float32Array, k: number, opts: HybridSearchOptions & {
|
|
130
|
+
arrow: true;
|
|
131
|
+
}): arrow.Table;
|
|
132
|
+
hybridSearch(textColumn: string, textQuery: string, vectorColumn: string, vectorQuery: number[] | Float32Array, k: number, opts?: HybridSearchOptions): RowRecord[];
|
|
110
133
|
/** Unranked token match; matching rows as records (or an Arrow `Table`). */
|
|
111
134
|
tokenMatch(column: string, query: string, opts: TokenMatchOptions & {
|
|
112
135
|
arrow: true;
|
package/infino/index.js
CHANGED
|
@@ -216,6 +216,11 @@ class Table {
|
|
|
216
216
|
const buf = this.inner.vectorSearch(column, q, k, opts.nprobe, opts.rerankMult, opts.projection, opts.filter);
|
|
217
217
|
return decode(buf, opts.arrow);
|
|
218
218
|
}
|
|
219
|
+
hybridSearch(textColumn, textQuery, vectorColumn, vectorQuery, k, opts = {}) {
|
|
220
|
+
const q = vectorQuery instanceof Float32Array ? vectorQuery : Float32Array.from(vectorQuery);
|
|
221
|
+
const buf = this.inner.hybridSearch(textColumn, textQuery, vectorColumn, q, k, opts.mode, opts.nprobe, opts.projection);
|
|
222
|
+
return decode(buf, opts.arrow);
|
|
223
|
+
}
|
|
219
224
|
tokenMatch(column, query, opts = {}) {
|
|
220
225
|
const buf = this.inner.tokenMatch(column, query, opts.mode, opts.projection);
|
|
221
226
|
return decode(buf, opts.arrow);
|
package/infino/native.d.ts
CHANGED
|
@@ -9,11 +9,12 @@
|
|
|
9
9
|
* disk cache.
|
|
10
10
|
*/
|
|
11
11
|
export interface ConnectOptions {
|
|
12
|
-
/**
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Credentials/tuning for the URI-selected backend, keyed by
|
|
14
|
+
* `object_store` config strings (`aws_*` / `azure_*`). An unknown key
|
|
15
|
+
* is rejected at `connect`.
|
|
16
|
+
*/
|
|
17
|
+
storageOptions?: Record<string, string>
|
|
17
18
|
/** Local disk-cache directory for remote-backed tables. */
|
|
18
19
|
cacheDir?: string
|
|
19
20
|
/** Disk-cache budget in bytes (a JS number; up to 2^53). */
|
|
@@ -23,6 +24,11 @@ export interface ConnectOptions {
|
|
|
23
24
|
* `"lazy_foreground_with_background_fill"`.
|
|
24
25
|
*/
|
|
25
26
|
coldFetchMode?: string
|
|
27
|
+
/**
|
|
28
|
+
* Probe the object store at `connect` (default `false`). `true` fails
|
|
29
|
+
* fast on bad credentials instead of on first use.
|
|
30
|
+
*/
|
|
31
|
+
validate?: boolean
|
|
26
32
|
}
|
|
27
33
|
/** Tuning for `optimize`; all fields optional (omitted ⇒ engine default). */
|
|
28
34
|
export interface OptimizeOptions {
|
|
@@ -57,8 +63,10 @@ export interface VectorFilter {
|
|
|
57
63
|
}
|
|
58
64
|
/**
|
|
59
65
|
* Open (or create) a catalog rooted at `uri` (local dir, `memory://`, or
|
|
60
|
-
* object-store prefix).
|
|
61
|
-
*
|
|
66
|
+
* object-store prefix). Credentials are passed via `options.storageOptions`
|
|
67
|
+
* (the JS-idiomatic form of the Rust `ConnectOptions`). Pass `validate: true`
|
|
68
|
+
* to probe object stores at connect (off by default) so bad credentials fail
|
|
69
|
+
* there rather than on the first table operation.
|
|
62
70
|
*/
|
|
63
71
|
export declare function connect(uri: string, options?: ConnectOptions | undefined | null): Connection
|
|
64
72
|
/**
|
|
@@ -141,6 +149,14 @@ export declare class Table {
|
|
|
141
149
|
* columns (omit for full rows).
|
|
142
150
|
*/
|
|
143
151
|
exactMatch(column: string, value: string, projection?: Array<string> | undefined | null): Buffer
|
|
152
|
+
/**
|
|
153
|
+
* Hybrid BM25 + vector search fused with reciprocal-rank fusion.
|
|
154
|
+
* `text_column`/`text_query` (under `mode`) drive BM25; `vector_column`/
|
|
155
|
+
* `vector_query` (a `Float32Array`, with optional `nprobe`) drive vector
|
|
156
|
+
* kNN. Returns Arrow rows like [`Table::bm25_search`], with `score` the
|
|
157
|
+
* fused RRF score (higher is better); `projection` selects columns.
|
|
158
|
+
*/
|
|
159
|
+
hybridSearch(textColumn: string, textQuery: string, vectorColumn: string, vectorQuery: Float32Array, k: number, mode?: string | undefined | null, nprobe?: number | undefined | null, projection?: Array<string> | undefined | null): Buffer
|
|
144
160
|
/**
|
|
145
161
|
* Delete every row matching a SQL `predicate` (e.g. `"status = 'spam'"`),
|
|
146
162
|
* returning the mutation counts. Requires durable storage — a `memory://`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@infino-ai/infino",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Fast search on object storage — SQL, full-text, and vector search.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"publishConfig": {
|
|
@@ -82,12 +82,12 @@
|
|
|
82
82
|
"apache-arrow": "^17"
|
|
83
83
|
},
|
|
84
84
|
"optionalDependencies": {
|
|
85
|
-
"infx-darwin-x64": "0.1.
|
|
86
|
-
"infx-darwin-arm64": "0.1.
|
|
87
|
-
"infx-linux-x64-gnu": "0.1.
|
|
88
|
-
"infx-linux-arm64-gnu": "0.1.
|
|
89
|
-
"infx-linux-x64-musl": "0.1.
|
|
90
|
-
"infx-linux-arm64-musl": "0.1.
|
|
85
|
+
"infx-darwin-x64": "0.1.1",
|
|
86
|
+
"infx-darwin-arm64": "0.1.1",
|
|
87
|
+
"infx-linux-x64-gnu": "0.1.1",
|
|
88
|
+
"infx-linux-arm64-gnu": "0.1.1",
|
|
89
|
+
"infx-linux-x64-musl": "0.1.1",
|
|
90
|
+
"infx-linux-arm64-musl": "0.1.1"
|
|
91
91
|
},
|
|
92
92
|
"devDependencies": {
|
|
93
93
|
"@napi-rs/cli": "^2.18.0",
|
|
@@ -99,4 +99,4 @@
|
|
|
99
99
|
"infino/native.js",
|
|
100
100
|
"infino/native.d.ts"
|
|
101
101
|
]
|
|
102
|
-
}
|
|
102
|
+
}
|