@statewalker/indexer-mem-minisearch 0.1.2 → 0.1.3

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.
Files changed (2) hide show
  1. package/README.md +75 -26
  2. package/package.json +12 -8
package/README.md CHANGED
@@ -1,53 +1,102 @@
1
1
  # @statewalker/indexer-mem-minisearch
2
2
 
3
- In-memory implementation of `@statewalker/indexer-api` combining [MiniSearch](https://github.com/lucaong/minisearch) for full-text search with `@statewalker/indexer-mem`'s `MemVectorIndex` for embeddings. Optional streaming persistence via `IndexerPersistence`.
3
+ ## What it is
4
4
 
5
- ## Installation
5
+ An in-memory `Indexer` that uses [MiniSearch](https://github.com/lucaong/minisearch) for full-text sub-indexes and `MemVectorIndex` from `@statewalker/indexer-mem` for vector sub-indexes. State can be saved and restored through an `IndexerPersistence` port you provide (files, IndexedDB, a blob store, ...).
6
+
7
+ ## Why it exists
8
+
9
+ It needs no database and no native code, so it runs in the browser, in Node and in workers, and starts instantly. Use it for small and medium collections, tests, and offline apps. `@statewalker/indexer-mem-flexsearch` is the same indexer with a different full-text engine; see "How the two in-memory engines differ" below.
10
+
11
+ ## How to use
6
12
 
7
13
  ```sh
8
14
  pnpm add @statewalker/indexer-mem-minisearch
9
15
  ```
10
16
 
11
- ## Usage
17
+ One entry point, `@statewalker/indexer-mem-minisearch`:
18
+
19
+ - `createMiniSearchIndexer(options?)` returns an `Indexer`. `options.persistence?: IndexerPersistence`.
20
+ - `miniSearchFullTextProvider` — the `FullTextProvider`, for building your own indexer with `createPersistenceBackedIndexer`.
21
+ - `MiniSearchFullTextIndex` — the full-text sub-index class.
22
+ - `MiniSearchIndexerOptions` — the options type.
23
+
24
+ Add `@statewalker/indexer-fulltext` and `@statewalker/indexer-vector` for the access handles used below.
25
+
26
+ ## Examples
12
27
 
13
28
  ```ts
14
29
  import { createMiniSearchIndexer } from "@statewalker/indexer-mem-minisearch";
30
+ import { newFullTextAccess, setFullTextConfig } from "@statewalker/indexer-fulltext";
31
+ import { newVectorAccess, setVectorConfig } from "@statewalker/indexer-vector";
15
32
 
16
33
  const indexer = createMiniSearchIndexer();
17
- const index = await indexer.createIndex({
18
- name: "docs",
19
- fulltext: { language: "en" },
20
- vector: { dimensionality: 384, model: "all-MiniLM-L6-v2" },
21
- });
22
-
23
- await index.addDocument([
24
- { path: "/docs/a", blockId: "1", content: "hello world" },
25
- ]);
26
-
27
- for await (const hit of index.search({ queries: ["hello"], topK: 10 })) {
28
- console.log(hit.path, hit.blockId, hit.score);
34
+
35
+ const params = { name: "docs" };
36
+ setFullTextConfig(params, "q", { language: "en" });
37
+ setVectorConfig(params, "semantic", { dimensionality: 384, model: "all-MiniLM-L6-v2" });
38
+ const index = await indexer.createIndex(params);
39
+
40
+ const fts = newFullTextAccess("q");
41
+ await fts.get(index).addDocument([{ path: "/docs/a", blockId: "1", content: "hello world" }]);
42
+
43
+ const request = { topK: 10 };
44
+ fts.setQuery(request, { queries: ["hello"] });
45
+ for await (const r of index.search(request)) {
46
+ console.log(r.path, r.blockId, r.score, fts.getResult(r)?.score);
29
47
  }
30
48
  ```
31
49
 
32
- ### With persistence
50
+ With persistence:
33
51
 
34
52
  ```ts
35
- import { createMiniSearchIndexer } from "@statewalker/indexer-mem-minisearch";
36
53
  import type { IndexerPersistence } from "@statewalker/indexer-api";
54
+ import { createMiniSearchIndexer } from "@statewalker/indexer-mem-minisearch";
55
+
56
+ const persistence: IndexerPersistence = {
57
+ async save(entries) {
58
+ for await (const entry of entries) {
59
+ // write entry.name; read bytes from entry.content (AsyncIterable<Uint8Array>)
60
+ }
61
+ },
62
+ async *load() {
63
+ // yield { name, content } for every saved entry
64
+ },
65
+ };
37
66
 
38
- const persistence: IndexerPersistence = /* … your save/load adapter … */;
39
67
  const indexer = createMiniSearchIndexer({ persistence });
68
+ // ... createIndex / getIndex, add documents ...
69
+ await indexer.flush(); // writes everything; close() also saves
70
+ ```
71
+
72
+ ## Internals
73
+
74
+ ### When state is saved
75
+
76
+ Saved state is read on the first indexer call and written on `indexer.flush()` and `indexer.close()`, never in between. A process that exits without one of them loses its changes. `save` receives the whole state each time:
77
+
78
+ ```
79
+ __manifest__ JSON array of index names
80
+ <index>/__manifest__ JSON { name, subIndexes }
81
+ <index>/<sub>/json full-text sub-index (MiniSearch state, format version 3)
82
+ <index>/<sub>/arrow vector sub-index (Arrow IPC from MemVectorIndex)
40
83
  ```
41
84
 
42
- Wire format (stable across releases): `__manifest__` (JSON array of index names), `${name}/__config__`, `${name}/fts` (MiniSearch `toJSON()`), `${name}/vec` (Arrow IPC from `MemVectorIndex`).
85
+ Loading a saved full-text entry with another format version throws `MiniSearchFullTextIndex: unsupported serialised version <n> (expected 3)`.
86
+
87
+ ### How the two in-memory engines differ
88
+
89
+ | | FlexSearch | MiniSearch |
90
+ | --- | --- | --- |
91
+ | Matching | `tokenize: "forward"` (prefix matching), multi-word queries with `suggest: true` so partial matches are returned | `prefix: true`, `fuzzy: 0.2`; if nothing matches, retries without fuzzy, then with `combineWith: "OR"` |
92
+ | `score` in `subResults` | rank-based: `1 - rank / hits` per query | MiniSearch relevance score |
93
+
94
+ In both, a sub-query with several `queries` adds up per-query scores, so blocks matching more queries rank higher. `snippet` is the whole block content. `language` is stored but not used: there is no stemming or stop-word list. Default retrieval depth is `topK = 100` per sub-query.
43
95
 
44
- ## API
96
+ ### Dependencies
45
97
 
46
- - `createMiniSearchIndexer(options?)` — returns an `Indexer`. Options: `persistence?: IndexerPersistence`.
47
- - `MiniSearchIndexerOptions` — option type.
98
+ `minisearch` (full-text engine), `@statewalker/indexer-mem` (vectors), `@statewalker/indexer-core` (indexer builder), `@statewalker/indexer-api`, `@statewalker/indexer-fulltext`.
48
99
 
49
- ## Related
100
+ ## License
50
101
 
51
- - `@statewalker/indexer-api` — the pluggable contract.
52
- - `@statewalker/indexer-mem-flexsearch` — drop-in alternative using FlexSearch.
53
- - `@statewalker/indexer-mem` — provides the vector sub-index (`MemVectorIndex`).
102
+ MIT
package/package.json CHANGED
@@ -1,10 +1,13 @@
1
1
  {
2
2
  "name": "@statewalker/indexer-mem-minisearch",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "In-memory indexer implementation backed by MiniSearch for full-text search.",
7
- "homepage": "https://github.com/statewalker/statewalker-indexer",
7
+ "bugs": {
8
+ "url": "https://github.com/statewalker/statewalker-search/issues"
9
+ },
10
+ "homepage": "https://github.com/statewalker/statewalker-search/tree/main/packages/indexer-mem-minisearch#readme",
8
11
  "author": {
9
12
  "name": "Mikhail Kotelnikov",
10
13
  "email": "mikhail.kotelnikov@gmail.com"
@@ -12,7 +15,8 @@
12
15
  "license": "MIT",
13
16
  "repository": {
14
17
  "type": "git",
15
- "url": "git+ssh://git@github.com/statewalker/statewalker-indexer.git"
18
+ "url": "git+https://github.com/statewalker/statewalker-search.git",
19
+ "directory": "packages/indexer-mem-minisearch"
16
20
  },
17
21
  "exports": {
18
22
  ".": {
@@ -28,10 +32,10 @@
28
32
  ],
29
33
  "dependencies": {
30
34
  "minisearch": "^7.2.0",
31
- "@statewalker/indexer-core": "^0.1.1",
32
- "@statewalker/indexer-api": "^0.1.1",
33
- "@statewalker/indexer-fulltext": "^0.1.1",
34
- "@statewalker/indexer-mem": "^0.1.2"
35
+ "@statewalker/indexer-api": "^0.1.2",
36
+ "@statewalker/indexer-core": "^0.1.2",
37
+ "@statewalker/indexer-mem": "^0.1.3",
38
+ "@statewalker/indexer-fulltext": "^0.1.2"
35
39
  },
36
40
  "devDependencies": {
37
41
  "rimraf": "^6.1.3",
@@ -39,7 +43,7 @@
39
43
  "typescript": "^7.0.2",
40
44
  "vitest": "^5.0.3",
41
45
  "@statewalker/indexer-tests": "^0.0.0",
42
- "@statewalker/indexer-vector": "^0.1.1"
46
+ "@statewalker/indexer-vector": "^0.1.2"
43
47
  },
44
48
  "sideEffects": false,
45
49
  "publishConfig": {