lucivy 3.0.7 → 4.0.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/README.md +24 -4
- package/index.d.ts +36 -3
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -1,10 +1,18 @@
|
|
|
1
|
-
# lucivy
|
|
1
|
+
# lucivy 4.0.0
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Full-text search for code and technical text, as a library — from Node.js. Substrings, fuzzy and regex **across token boundaries**, BM25, exact byte spans, every answer checked against the files. Runs in your process, in your transaction (bring your own storage), and the same engine runs in the browser. Powered by Rust via napi-rs, MIT.
|
|
4
4
|
|
|
5
5
|
[**Try the live playground**](https://l-defraiteur.github.io/lucivy/) — runs entirely in your browser via WASM.
|
|
6
6
|
|
|
7
|
-
### What's new in
|
|
7
|
+
### What's new in 4.0.0
|
|
8
|
+
|
|
9
|
+
- **The index is 3.7× smaller** — the whole Linux kernel: 18 057 MB in 3.0.8, 4 938 MB in 4.0, 3 344 MB with `derivedInRam`; same answers, same spans, checked against the files ([the comparison with Elasticsearch and tantivy](../../docs/compare-engines-2026-09-05.md))
|
|
10
|
+
- **The shared dictionary is the default** (`Index.create(path, fields, shards, false)` / `BlobIndex` option `sharedDictionary: false` keeps a suffix FST per segment: indexing ×1.5 faster, an index 23 % bigger) — one dictionary of token texts per shard instead of one per segment: 23 % smaller on the kernel, cold queries ×0.8-1.6, same answers; off by default, fixed at creation
|
|
11
|
+
- **`Index.create(path, fields, shards, sharedDictionary, derivedInRam, dictionaryWait)`** and **`BlobIndex` option `dictionaryWait`** — shared dictionary only: a commit returns before the shard's new texts are merged into the dictionary (a background task does it) and, by default, a search waits for that merge so that its cost never depends on when it runs; `false` searches at once over the not-yet-merged parts. Indexing with the dictionary costs ×1.5 (the kernel: 107 s against 56)
|
|
12
|
+
- **`Index.create(path, fields, shards, sharedDictionary, derivedInRam)`** and **`BlobIndex` option `derivedInRam`** — the three derived sidecars of each segment rebuilt byte for byte when the index opens instead of written: about a third less on disk, the open pays (the kernel: 2 s), never a query; off by default
|
|
13
|
+
- **Compatibility contract** — 4.0 opens a 3.0.x index and returns what 3.0.x returned (checked against a fixture the published 3.0.8 wheel built); 3.0.x does not open a 4.0 index; the first commit converts for good
|
|
14
|
+
|
|
15
|
+
### What 3.0.0 brought
|
|
8
16
|
|
|
9
17
|
- **SFX v3 segment format** — per-field suffix FST files, the default for every new index; v2 indexes still open
|
|
10
18
|
- **`parse` query type** — boolean syntax (`AND` / `OR` / `NOT`, quotes, `+` / `-`, parentheses) on top of substring matching
|
|
@@ -18,7 +26,7 @@ Still there from 2.x: SFX-only engine, distributed search (`exportStats` / `merg
|
|
|
18
26
|
## Install
|
|
19
27
|
|
|
20
28
|
```bash
|
|
21
|
-
npm install lucivy
|
|
29
|
+
npm install lucivy # 4.0.0
|
|
22
30
|
```
|
|
23
31
|
|
|
24
32
|
## Quick start
|
|
@@ -55,6 +63,18 @@ const index = Index.create('/tmp/my_index', [
|
|
|
55
63
|
// Sharded (4 shards)
|
|
56
64
|
const sharded = Index.create('/tmp/sharded', [...], 4);
|
|
57
65
|
|
|
66
|
+
// Smaller index: one dictionary per shard instead of one per segment.
|
|
67
|
+
// About 20 % less disk and RAM; queries slightly slower at cold cache
|
|
68
|
+
// (roughly x1.2 to x1.6 on exact queries, fuzzy ones faster); same answers.
|
|
69
|
+
// Fixed at creation. (BlobIndex.create: `{ sharedDictionary: true }` in options.)
|
|
70
|
+
const compact = Index.create('/tmp/compact', [...], 1, true);
|
|
71
|
+
|
|
72
|
+
// Smaller still on disk: the three derived sidecars of each segment (about
|
|
73
|
+
// a third of the index) are rebuilt in RAM, byte for byte, when the index is
|
|
74
|
+
// opened, instead of being written. Same answers; opening pays the rebuild,
|
|
75
|
+
// never a query. (BlobIndex.create: `{ derivedInRam: true }`.)
|
|
76
|
+
const lean = Index.create('/tmp/lean', [...], 1, true, true);
|
|
77
|
+
|
|
58
78
|
// Open existing
|
|
59
79
|
const index2 = Index.open('/tmp/my_index');
|
|
60
80
|
```
|
package/index.d.ts
CHANGED
|
@@ -83,6 +83,21 @@ export interface BlobIndexOptions {
|
|
|
83
83
|
lazy?: boolean
|
|
84
84
|
/** `create()` only: number of shards (default 1). */
|
|
85
85
|
shards?: number
|
|
86
|
+
/**
|
|
87
|
+
* `create()` only: one dictionary per shard instead of one per segment
|
|
88
|
+
* (about 20 % smaller, slightly slower queries) — see `Index.create()`.
|
|
89
|
+
*/
|
|
90
|
+
sharedDictionary?: boolean
|
|
91
|
+
/**
|
|
92
|
+
* `create()` only: the derived sidecars rebuilt in RAM at open instead
|
|
93
|
+
* of written (about a third smaller on disk) — see `Index.create()`.
|
|
94
|
+
*/
|
|
95
|
+
derivedInRam?: boolean
|
|
96
|
+
/**
|
|
97
|
+
* `create()` only, shared dictionary: a search waits for the background
|
|
98
|
+
* merge of the last commit's texts (default `true`) — see `Index.create()`.
|
|
99
|
+
*/
|
|
100
|
+
dictionaryWait?: boolean
|
|
86
101
|
}
|
|
87
102
|
export declare class Index {
|
|
88
103
|
/**
|
|
@@ -92,8 +107,26 @@ export declare class Index {
|
|
|
92
107
|
* @param fields - Field definitions: `[{name: "body", type: "text", stored: true}]`.
|
|
93
108
|
* Types: `"text"` (full-text), `"u64"`, `"i64"`, `"f64"`, `"bool"`, `"date"`.
|
|
94
109
|
* @param shards - Number of shards (default 1). More shards = faster search on large datasets.
|
|
95
|
-
|
|
96
|
-
|
|
110
|
+
* @param sharedDictionary - Store each distinct token text once per shard
|
|
111
|
+
* instead of once per segment: the index is about 20 % smaller on disk
|
|
112
|
+
* and in RAM, queries are slightly slower at cold cache (roughly x1.2
|
|
113
|
+
* to x1.6 on exact queries, fuzzy ones faster) and a commit also writes
|
|
114
|
+
* the shard's new texts. Same answers either way. On by default since
|
|
115
|
+
* 4.0.0; `false` keeps a suffix FST per segment (indexing ×1.5 faster,
|
|
116
|
+
* an index 23 % bigger). Fixed at creation.
|
|
117
|
+
* @param derivedInRam - Do not write the three derived sidecars of each
|
|
118
|
+
* segment (`.posmap`, `.word_pos_map`, `.sibling_v3`, about a third
|
|
119
|
+
* of the index on disk); they are rebuilt in RAM, byte for byte, when
|
|
120
|
+
* the index is opened or reloaded. Same answers; opening pays the
|
|
121
|
+
* rebuild (never a query) and the rebuilt structures stay resident.
|
|
122
|
+
* Off by default; fixed at creation.
|
|
123
|
+
* @param dictionaryWait - Shared dictionary only. A commit returns before
|
|
124
|
+
* the shard's new texts are merged into the dictionary (a background
|
|
125
|
+
* task does it); a search waits for that merge, so that its cost never
|
|
126
|
+
* depends on when it runs. `false` searches at once over the
|
|
127
|
+
* not-yet-merged parts. On by default; fixed at creation.
|
|
128
|
+
*/
|
|
129
|
+
static create(path: string, fields: Array<FieldDef>, shards?: number | undefined | null, sharedDictionary?: boolean | undefined | null, derivedInRam?: boolean | undefined | null, dictionaryWait?: boolean | undefined | null): Index
|
|
97
130
|
/**
|
|
98
131
|
* Open an existing index at the given path.
|
|
99
132
|
*
|
|
@@ -404,7 +437,7 @@ export declare class BlobIndex {
|
|
|
404
437
|
* @param store - Object implementing the store protocol (`load`, `save`, `delete`, `exists`, `list`, optional `blobLen` / `loadRange`).
|
|
405
438
|
* @param indexName - Name of the index inside the store.
|
|
406
439
|
* @param fields - Field definitions, as for `Index.create()`.
|
|
407
|
-
* @param options - `{cacheDir?, lazy?, shards?}`.
|
|
440
|
+
* @param options - `{cacheDir?, lazy?, shards?, sharedDictionary?, derivedInRam?, dictionaryWait?}`.
|
|
408
441
|
*/
|
|
409
442
|
static create(store: BlobStoreCallbacks, indexName: string, fields: Array<FieldDef>, options?: BlobIndexOptions | undefined | null): Promise<BlobIndex>
|
|
410
443
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lucivy",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"description": "Fast BM25 full-text search with substring matching, fuzzy search, and regex — powered by Rust",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -39,10 +39,10 @@
|
|
|
39
39
|
"build:debug": "napi build"
|
|
40
40
|
},
|
|
41
41
|
"optionalDependencies": {
|
|
42
|
-
"lucivy-linux-x64-gnu": "
|
|
43
|
-
"lucivy-linux-arm64-gnu": "
|
|
44
|
-
"lucivy-darwin-x64": "
|
|
45
|
-
"lucivy-darwin-arm64": "
|
|
46
|
-
"lucivy-windows-x64": "
|
|
42
|
+
"lucivy-linux-x64-gnu": "4.0.0",
|
|
43
|
+
"lucivy-linux-arm64-gnu": "4.0.0",
|
|
44
|
+
"lucivy-darwin-x64": "4.0.0",
|
|
45
|
+
"lucivy-darwin-arm64": "4.0.0",
|
|
46
|
+
"lucivy-windows-x64": "4.0.0"
|
|
47
47
|
}
|
|
48
48
|
}
|