@yoch/frozenminisearch 1.0.0 → 1.0.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/CHANGELOG.md +14 -0
- package/README.md +41 -11
- package/dist/cjs/index.cjs +357 -167
- package/dist/cjs/index.require.cjs +1 -0
- package/dist/es/index.d.ts +8 -6
- package/dist/es/index.js +357 -168
- package/package.json +5 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## v1.0.1 — `@yoch/frozenminisearch`
|
|
6
|
+
|
|
7
|
+
Patch release: lower build-time peak memory and migration ergonomics. No API or wire-format changes.
|
|
8
|
+
|
|
9
|
+
### Improved
|
|
10
|
+
|
|
11
|
+
- **`FrozenIndexBuilder` peak heap** — incremental typed-array posting accumulators replace per-term `number[][]` scratch; token and term-frequency buffers are reused across `add()` calls.
|
|
12
|
+
- **Default tokenization during build** — single-pass field scan when the default splitter is in use (`collectFieldTermFreqsFromFieldInto`).
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- **Default tokenizer parity** — leading delimiter produces an empty token (e.g. `::a` → `["", "a"]`), matching lucaong `split` behaviour.
|
|
17
|
+
- **Named export** — `FrozenMiniSearch` is exported again alongside the default export (ESM and CJS).
|
|
18
|
+
|
|
5
19
|
## v1.0.0 — `@yoch/frozenminisearch`
|
|
6
20
|
|
|
7
21
|
First stable release on npm. Frozen-only read-only search for Node.js.
|
package/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# @yoch/frozenminisearch
|
|
2
2
|
|
|
3
|
-
**Read-only full-text search for Node.js** — compact frozen indexes, fast binary snapshots, and
|
|
3
|
+
**Read-only full-text search for Node.js** — compact frozen indexes, fast binary snapshots, and a **drop-in** search API for frozen workloads: same `search`, `autoSuggest`, scoring, and query options as [MiniSearch](https://github.com/lucaong/minisearch) by [Luca Ongaro](https://github.com/lucaong).
|
|
4
4
|
|
|
5
|
-
> **Current release:** `1.0.
|
|
5
|
+
> **Current release:** `1.0.1` on npm
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
**Design goal:** once an index is built or loaded, migrate with the minimum code change — package name and index construction only; serving code stays the same. No mutable `MiniSearch` class is published here; build indexes with `fromDocuments`, the incremental builder, or migrate from an existing lucaong index via `fromMiniSearchJson`.
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
@@ -19,15 +19,15 @@ Same BM25 queries on identical corpora. **Frozen wins on what we optimize for**:
|
|
|
19
19
|
|
|
20
20
|
| Scenario | Docs | Index RAM¹ | Disk (binary vs JSON)² | Cold load³ | Search p50⁴ |
|
|
21
21
|
|----------|-----:|------------|------------------------:|-----------:|------------:|
|
|
22
|
-
| Divina with storeFields | 14,097 | 1.1 vs 16.0 MB (~93% less) | ~73% less | ~
|
|
23
|
-
| Divina index only | 14,097 | 0.3 vs 14.9 MB (~98% less) | ~77% less | ~86% faster | ~
|
|
24
|
-
| high-frequency terms (10k docs) | 10,000 | 0.2 vs 7.4 MB (~
|
|
25
|
-
| Dense numeric ids (100k, identity lookup) | 100,000 | 1.
|
|
26
|
-
| Doc id Uint16 boundary (65535 docs) | 65,535 | 1.1 vs 58.6 MB (~98% less) | ~91% less | ~
|
|
22
|
+
| Divina with storeFields | 14,097 | 1.1 vs 16.0 MB (~93% less) | ~73% less | ~70% faster | ~13% faster |
|
|
23
|
+
| Divina index only | 14,097 | 0.3 vs 14.9 MB (~98% less) | ~77% less | ~86% faster | ~8% faster |
|
|
24
|
+
| high-frequency terms (10k docs) | 10,000 | 0.2 vs 7.4 MB (~98% less) | ~94% less | ~93% faster | ~29% faster |
|
|
25
|
+
| Dense numeric ids (100k, identity lookup) | 100,000 | 1.6 vs 91.2 MB (~98% less) | ~88% less | ~91% faster | ~18% faster |
|
|
26
|
+
| Doc id Uint16 boundary (65535 docs) | 65,535 | 1.1 vs 58.6 MB (~98% less) | ~91% less | ~93% faster | ~43% faster |
|
|
27
27
|
|
|
28
|
-
**Headline:** 22/27 query benchmarks favor frozen (paired **hrtime** protocol v2). Divina `inferno` (exact, paired p50): mutable 16.
|
|
28
|
+
**Headline:** 22/27 query benchmarks favor frozen (paired **hrtime** protocol v2). Divina `inferno` (exact, paired p50): mutable 16.2 µs → frozen 13.7 µs (**-2 µs**, ratio 0.90).
|
|
29
29
|
|
|
30
|
-
Decomposition (Divina exact): L0 lookup ~300 ns frozen, L1 `executeQuery` ~8.
|
|
30
|
+
Decomposition (Divina exact): L0 lookup ~300 ns frozen, L1 `executeQuery` ~8.3 µs, L2 full `search` ~11.6 µs (finalize ≈ 3 µs).
|
|
31
31
|
|
|
32
32
|
| | lucaong `minisearch` | `@yoch/frozenminisearch` |
|
|
33
33
|
|---|------------------------|---------------------------|
|
|
@@ -38,7 +38,7 @@ Decomposition (Divina exact): L0 lookup ~300 ns frozen, L1 `executeQuery` ~8.1
|
|
|
38
38
|
<details>
|
|
39
39
|
<summary><strong>How to read these numbers (limits & protocol)</strong></summary>
|
|
40
40
|
|
|
41
|
-
- **Captured:** 2026-06-07 · commit `
|
|
41
|
+
- **Captured:** 2026-06-07 · commit `9f32207` · Node v24.16.0 · minisearch **7.2.0** · **3** run(s)/scenario · protocol **v2** (hrtime-paired, batch target 3 ms).
|
|
42
42
|
- ¹ **Index RAM** — `measureHeap` with `--expose-gc`, one index alive. V8 overhead is extra; treat as **trend**, not accounting. Sporadic outliers happen (e.g. index-only Divina).
|
|
43
43
|
- ² **Disk** — `JSON.stringify(mutable)` vs `saveBinarySync`.
|
|
44
44
|
- ³ **Cold load** — median wall time to searchable index after read from disk format.
|
|
@@ -89,6 +89,36 @@ ESM and CommonJS are both supported (`main` → CJS, `module` → ESM).
|
|
|
89
89
|
|
|
90
90
|
---
|
|
91
91
|
|
|
92
|
+
## Drop-in
|
|
93
|
+
|
|
94
|
+
For **fixed corpora** (build once, serve read-only), treat this package as a drop-in replacement for lucaong `minisearch` on the serving path.
|
|
95
|
+
|
|
96
|
+
**Change only:**
|
|
97
|
+
|
|
98
|
+
| What | Before | After |
|
|
99
|
+
|------|--------|-------|
|
|
100
|
+
| Package | lucaong `minisearch` | `@yoch/frozenminisearch` |
|
|
101
|
+
| Construction | `new MiniSearch(opts).addAll(docs)` | `FrozenMiniSearch.fromDocuments(docs, opts)` or `fromMiniSearch(mutable, opts)` |
|
|
102
|
+
| JSON snapshot | `MiniSearch.loadJSON(json)` / `toJSON()` wire format | `FrozenMiniSearch.fromMiniSearchJson(json, opts)` or `fromMiniSearchSnapshot(obj)` — no runtime dependency on lucaong `minisearch` |
|
|
103
|
+
|
|
104
|
+
**Keep unchanged** after load: `search`, `autoSuggest`, `has`, `getStoredFields`, query options (`prefix`, `fuzzy`, `AND` / `OR` / `AND_NOT`, filters, boosts). Parity vs `minisearch@7` is enforced in `dev/parity/`.
|
|
105
|
+
|
|
106
|
+
**Imports** — default and named both work (ESM and CJS):
|
|
107
|
+
|
|
108
|
+
```javascript
|
|
109
|
+
// ESM
|
|
110
|
+
import FrozenMiniSearch from '@yoch/frozenminisearch'
|
|
111
|
+
import { FrozenMiniSearch } from '@yoch/frozenminisearch'
|
|
112
|
+
|
|
113
|
+
// CommonJS
|
|
114
|
+
const FrozenMiniSearch = require('@yoch/frozenminisearch')
|
|
115
|
+
const { FrozenMiniSearch } = require('@yoch/frozenminisearch')
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**Intentionally not drop-in:** live `add` / `remove` / `discard` (frozen is read-only); browser builds; custom `tokenize` / `processTerm` are not stored in JSON or binary snapshots — pass the same functions at load when you customized them.
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
92
122
|
## Migration
|
|
93
123
|
|
|
94
124
|
### From lucaong `minisearch` JSON
|