@delali/narsil 0.2.4-next.51 → 0.2.4-next.52
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 +27 -25
- package/dist/{capabilities-BWm4IITU.d.ts → capabilities-CuTSXvbN.d.ts} +2 -2
- package/dist/{chunk-BEIK3EOZ.mjs → chunk-2FO7KZ6K.mjs} +5468 -3837
- package/dist/{chunk-XE6XR2OE.mjs → chunk-3GWP2TO6.mjs} +1 -1
- package/dist/{chunk-KMMJMDUA.mjs → chunk-3L4U6EJQ.mjs} +15 -10
- package/dist/{chunk-MHE7YWAU.mjs → chunk-72AXTIBW.mjs} +2 -2
- package/dist/{chunk-CV5H7XL7.mjs → chunk-EY2ULUMT.mjs} +30 -7
- package/dist/chunk-IFBKLBGB.mjs +7 -0
- package/dist/{chunk-WYJXSLER.mjs → chunk-POWOTUKJ.mjs} +7 -1
- package/dist/chunk-T62YOSGS.mjs +4280 -0
- package/dist/chunk-U36IDJN7.mjs +366 -0
- package/dist/{chunk-ND34I3SV.mjs → chunk-ULJ36FK4.mjs} +3502 -2383
- package/dist/{chunk-RP23PWMV.mjs → chunk-WFKIGEBY.mjs} +3 -3
- package/dist/{chunk-CMVG2UEF.mjs → chunk-WM7IS45M.mjs} +55 -517
- package/dist/chunk-Y3L5MDRV.mjs +96 -0
- package/dist/{chunk-ZHUQKZBE.mjs → chunk-YPYULM5E.mjs} +20 -4
- package/dist/chunk-ZJ4CSAB2.mjs +13 -0
- package/dist/chunk-ZT5BRDFW.mjs +513 -0
- package/dist/{client-B_X6_AbT.d.ts → client-BMJWVxOP.d.ts} +3 -3
- package/dist/client.d.ts +8 -8
- package/dist/{config-OON7IJ_B.d.ts → config-BcYZkdMw.d.ts} +2 -2
- package/dist/{config-Czh2YNDi.d.ts → config-qMLpi5T4.d.ts} +2 -2
- package/dist/direct-executor-UJC36S2D.mjs +12 -0
- package/dist/distribution/coordinator/etcd.d.ts +2 -2
- package/dist/distribution/coordinator/in-memory.d.ts +2 -2
- package/dist/distribution.d.ts +8 -8
- package/dist/distribution.mjs +30 -15
- package/dist/{engine-9PtFY50q.d.ts → engine-zhms1qId.d.ts} +2 -2
- package/dist/index.browser.mjs +12845 -7766
- package/dist/index.d.ts +9 -21
- package/dist/index.mjs +13 -12
- package/dist/{memory-Bzd5xcEW.d.ts → memory-OmgkX_Z2.d.ts} +11 -1
- package/dist/persistence/durability/checkpoint-worker.d.ts +138 -3
- package/dist/persistence/durability/checkpoint-worker.mjs +31 -17
- package/dist/react.d.ts +6 -6
- package/dist/{schema-BqRx9t4E.d.ts → schema-OSWaaZzx.d.ts} +30 -6
- package/dist/serialization/crc32-worker.mjs +2 -1
- package/dist/server.d.ts +10 -10
- package/dist/server.mjs +75 -34
- package/dist/simd-DW5AtJ6B.d.ts +41 -0
- package/dist/{tasks-DT7L1p6w.d.ts → tasks-DiF1c9v2.d.ts} +1 -1
- package/dist/{thread-PZLEO6JL.mjs → thread-TLCX43WV.mjs} +129 -41
- package/dist/{types-DXPxaXPO.d.ts → types-LEzMyjVX.d.ts} +1 -1
- package/dist/vector/search-worker.d.ts +292 -128
- package/dist/vector/search-worker.mjs +70 -54
- package/dist/workers/entry.mjs +10 -7
- package/package.json +52 -31
- package/dist/brute-force-DbHYCTc3.d.ts +0 -8
- package/dist/chunk-CBLS46IE.mjs +0 -10
- package/dist/chunk-PIWKZPP7.mjs +0 -64
- package/dist/chunk-PMBHH44R.mjs +0 -492
- package/dist/chunk-X6YZO4MQ.mjs +0 -1572
- package/dist/direct-executor-OREXU72C.mjs +0 -12
- package/dist/vector/hnsw-build-worker.d.ts +0 -105
- package/dist/vector/hnsw-build-worker.mjs +0 -123
package/README.md
CHANGED
|
@@ -10,13 +10,13 @@
|
|
|
10
10
|
|
|
11
11
|
Distributed search, reforged.
|
|
12
12
|
|
|
13
|
-
Narsil is a distributed search engine with full-text, vector, hybrid, and geosearch.
|
|
13
|
+
Narsil is a distributed search engine with full-text, vector, hybrid, and geosearch. You can embed Narsil in your application process, where the engine searches without a network hop, or deploy it as a standalone search server with a REST API, a write-ahead log, and bulk NDJSON ingest. Both forms contain the same engine, which stores indexes in one cross-language binary format (`.nrsl`), so you can load an index from one form into the other.
|
|
14
14
|
|
|
15
|
-
The engine partitions large indexes across workers and merges
|
|
15
|
+
The engine partitions large indexes across workers and merges the results of the partitions into a single ranked list. Its BM25 nDCG@10 is within 0.006 of the Anserini reference on BEIR SciFact and NFCorpus. On SciFact, Narsil scores 0.681 nDCG@10, ahead of Elasticsearch and OpenSearch at 0.679. At its peak, it also serves 958 keyword queries per second on SciFact, while Elasticsearch serves 841 and OpenSearch serves 878 ([benchmarks](https://github.com/assetcorp/narsil/blob/main/BENCHMARKS.md)). This TypeScript package is the reference implementation of the `.nrsl` format, so a second implementation in Go or Rust is the headline item on the [roadmap](https://github.com/assetcorp/narsil/blob/main/ROADMAP.md).
|
|
16
16
|
|
|
17
17
|
Try it in your browser at [narsil.sondelali.com/demo](https://narsil.sondelali.com/demo). Read the full documentation at [narsil.sondelali.com/docs](https://narsil.sondelali.com/docs).
|
|
18
18
|
|
|
19
|
-
> *narsil* is the sword of Elendil in Tolkien's Lord of the Rings, shattered into shards and later reforged. The name
|
|
19
|
+
> *narsil* is the sword of Elendil in Tolkien's Lord of the Rings, shattered into shards and later reforged. The name fits the design, because the engine splits your data into partitions that it persists one by one, then merges their results into one ranked list for each query.
|
|
20
20
|
|
|
21
21
|
## Contents
|
|
22
22
|
|
|
@@ -36,7 +36,9 @@ Try it in your browser at [narsil.sondelali.com/demo](https://narsil.sondelali.c
|
|
|
36
36
|
pnpm add @delali/narsil
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
Narsil
|
|
39
|
+
Narsil works in Node.js 22 or newer, and in Bun, Deno, and browsers. The [Runtime support](#runtime-support) table covers each runtime.
|
|
40
|
+
|
|
41
|
+
On an arm64 or x64 machine under macOS, Linux, or Windows, the package manager also installs Narsil's native search core as an optional dependency, and the engine searches vector graphs through it. If you omit optional dependencies, Narsil searches those graphs through WebAssembly, with the same results, as it always does in a browser.
|
|
40
42
|
|
|
41
43
|
## Quick start
|
|
42
44
|
|
|
@@ -79,21 +81,21 @@ const results = await narsil.query('products', {
|
|
|
79
81
|
})
|
|
80
82
|
```
|
|
81
83
|
|
|
82
|
-
Every hit holds the document, its id, and its BM25 score. `results.count`
|
|
84
|
+
Every hit holds the document, its id, and its BM25 score. Beside the hits, `results.count` holds the total number of matching documents, `results.elapsed` holds the query time in milliseconds, and `results.coverage` counts the partitions that the search covered, so you can tell when a cluster returns results from part of its data.
|
|
83
85
|
|
|
84
86
|
## Features
|
|
85
87
|
|
|
86
|
-
**Search.** [
|
|
88
|
+
**Search.** For [full-text search](https://github.com/assetcorp/narsil/blob/main/docs/full-text-search.md), the engine scores with BM25 and supports field boosting, fuzzy matching through bounded Levenshtein distance, search as you type through last-word prefix matching, and term-coverage and score thresholds. You can combine a query with [filters, facets, sorting, grouping, cursor pagination, and pinned results](https://github.com/assetcorp/narsil/blob/main/docs/filters-facets-and-pagination.md).
|
|
87
89
|
|
|
88
|
-
**Vector and hybrid retrieval.** [
|
|
90
|
+
**Vector and hybrid retrieval.** For [vector search](https://github.com/assetcorp/narsil/blob/main/docs/vector-search.md), the engine compares vectors by cosine similarity, dot product, or Euclidean distance. It scans a field exactly until the field holds 1,024 vectors, a count that you can change, after which it builds an HNSW graph with optimised scalar quantization on by default. Outside a browser, on an arm64 or x64 machine under macOS, Linux, or Windows, the engine searches that graph through a [native core in C](https://github.com/assetcorp/narsil/blob/main/docs/vector-search.md#native-search-core), which returns the same results as its WebAssembly search. For [hybrid search](https://github.com/assetcorp/narsil/blob/main/docs/hybrid-search.md), the engine fuses BM25 and vector rankings through reciprocal rank fusion or linear blending. [Embedding adapters](https://github.com/assetcorp/narsil/blob/main/docs/embedding-adapters.md) turn text into vectors on insert and query, through OpenAI, local Transformers.js models, or an adapter of your own.
|
|
89
91
|
|
|
90
|
-
**Geosearch.** [Geo filters](https://github.com/assetcorp/narsil/blob/main/docs/geosearch.md) match by radius, using Haversine or Vincenty distance, or by polygon containment
|
|
92
|
+
**Geosearch.** [Geo filters](https://github.com/assetcorp/narsil/blob/main/docs/geosearch.md) match documents by radius, using Haversine or Vincenty distance, or by polygon containment. You can combine a geo filter with every other query feature.
|
|
91
93
|
|
|
92
|
-
**Storage.** [Persistence adapters](https://github.com/assetcorp/narsil/blob/main/docs/persistence-and-durability.md)
|
|
94
|
+
**Storage.** [Persistence adapters](https://github.com/assetcorp/narsil/blob/main/docs/persistence-and-durability.md) store indexes on the filesystem, in IndexedDB, in memory, or in a backend of your own. With durability on, the engine keeps a write-ahead log with periodic checkpoints and recovers on its own after a crash. A snapshot captures a whole index as one portable byte array.
|
|
93
95
|
|
|
94
|
-
**Scale.** [
|
|
96
|
+
**Scale.** The engine routes each document to a [partition](https://github.com/assetcorp/narsil/blob/main/docs/partitions-and-workers.md) by a deterministic hash. When you call `rebalance()`, the engine reshapes the partitions online and buffers incoming writes in a write-ahead queue. Once an index holds 1,000 documents, the engine serves keyword queries from worker copies on half its worker threads, while the HTTP server receives requests on the threads that hold those copies.
|
|
95
97
|
|
|
96
|
-
**Operations.** The [HTTP server](https://github.com/assetcorp/narsil/blob/main/docs/http-server.md) subpath wraps an engine in a REST API with health probes, bulk NDJSON import, snapshot and restore endpoints, and task-based long operations. The [client](https://github.com/assetcorp/narsil/blob/main/docs/client.md) subpath
|
|
98
|
+
**Operations.** The [HTTP server](https://github.com/assetcorp/narsil/blob/main/docs/http-server.md) subpath wraps an engine in a REST API with health probes, bulk NDJSON import, snapshot and restore endpoints, and task-based long operations. The [client](https://github.com/assetcorp/narsil/blob/main/docs/client.md) subpath calls every one of those routes from a browser or from Node under the engine's own method names. The [React](https://github.com/assetcorp/narsil/blob/main/docs/react.md) subpath exposes those methods to components as hooks. For observability, you get [events, plugins, and memory reporting](https://github.com/assetcorp/narsil/blob/main/docs/observability.md). [Language modules](https://github.com/assetcorp/narsil/blob/main/docs/language-support.md) cover 107 languages as separate entry points, including 20 African languages.
|
|
97
99
|
|
|
98
100
|
## Documentation
|
|
99
101
|
|
|
@@ -103,7 +105,7 @@ Every hit holds the document, its id, and its BM25 score. `results.count` report
|
|
|
103
105
|
| [Indexes and documents](../../docs/indexes-and-documents.md) | Schemas, index management, inserts, reads, updates, removals, and batch operations |
|
|
104
106
|
| [Full-text search](../../docs/full-text-search.md) | Term queries, fuzzy matching, prefix completion, thresholds, highlighting, scoring modes, and suggestions |
|
|
105
107
|
| [Filters, facets, and pagination](../../docs/filters-facets-and-pagination.md) | Field, array, presence, and geo filters, facet counts, sorting, grouping, cursors, and pinning |
|
|
106
|
-
| [Vector search](../../docs/vector-search.md) | Vector fields, distance metrics, HNSW promotion, quantization, and graph maintenance |
|
|
108
|
+
| [Vector search](../../docs/vector-search.md) | Vector fields, distance metrics, HNSW promotion, quantization, the native search core, and graph maintenance |
|
|
107
109
|
| [Hybrid search](../../docs/hybrid-search.md) | Reciprocal rank fusion and linear blending of text and vector rankings |
|
|
108
110
|
| [Geosearch](../../docs/geosearch.md) | Radius and polygon filters, and the two distance formulas |
|
|
109
111
|
| [Embedding adapters](../../docs/embedding-adapters.md) | Automatic embedding on insert and query, named adapters, the bundled ones, and custom ones |
|
|
@@ -111,42 +113,42 @@ Every hit holds the document, its id, and its BM25 score. `results.count` report
|
|
|
111
113
|
| [Partitions and workers](../../docs/partitions-and-workers.md) | Partition routing, online rebalancing, worker copies, and multi-instance invalidation |
|
|
112
114
|
| [Language support](../../docs/language-support.md) | The 107 language modules, analysis revisions and rebuilds, and named tokenizers and stop words |
|
|
113
115
|
| [HTTP server](../../docs/http-server.md) | Wrapping an engine in a REST API, every route it serves, and long-running tasks |
|
|
114
|
-
| [Cluster mode](../../docs/cluster.md) | Multi-node indexes: nodes and roles, replication, routed writes, distributed searches and reads, and
|
|
116
|
+
| [Cluster mode](../../docs/cluster.md) | Multi-node indexes: nodes and roles, replication, routed writes, distributed searches and reads, and the calls that fail in a cluster |
|
|
115
117
|
| [Client](../../docs/client.md) | Reaching a server from a browser or Node, following a task, and the codes it raises |
|
|
116
118
|
| [React](../../docs/react.md) | The hooks over the client, one shared request per key, and loading a corpus from a component |
|
|
117
119
|
| [Observability](../../docs/observability.md) | Plugin hooks, engine events, and memory reporting |
|
|
118
120
|
| [Errors](../../docs/errors.md) | Every error code and what throws it |
|
|
119
121
|
|
|
120
|
-
The [specification](../spec/) defines the `.nrsl` format, the analysis pipeline, and the replication invariants that every implementation
|
|
122
|
+
The [specification](../spec/) defines the `.nrsl` format, the analysis pipeline, and the replication invariants that every implementation must uphold.
|
|
121
123
|
|
|
122
124
|
## Examples
|
|
123
125
|
|
|
124
126
|
| Example | What it shows |
|
|
125
127
|
| --- | --- |
|
|
126
|
-
| [HTTP server](examples/http-server/README.md) | The launcher
|
|
128
|
+
| [HTTP server](examples/http-server/README.md) | The launcher serves the engine as a REST service with durability, API-key auth, and Docker packaging, and every setting comes from the environment. |
|
|
127
129
|
| [Browser](examples/browser/README.md) | The app embeds the engine in a browser with IndexedDB persistence and Web Worker search. |
|
|
128
|
-
| [Server app](examples/server-app/README.md) | The app
|
|
130
|
+
| [Server app](examples/server-app/README.md) | The app calls the HTTP server through the client SDK and the React hooks to load corpora as import tasks. In its Ask view, you can ask questions about those corpora. |
|
|
129
131
|
|
|
130
132
|
## Distribution
|
|
131
133
|
|
|
132
|
-
`@delali/narsil/distribution` holds Narsil's multi-node cluster mode: nodes and roles, replication, coordinator adapters for etcd and in-process testing, TCP and gRPC transports with mutual TLS, and distributed query routing. A cluster node
|
|
134
|
+
`@delali/narsil/distribution` holds Narsil's multi-node cluster mode: nodes and roles, replication, coordinator adapters for etcd and in-process testing, TCP and gRPC transports with mutual TLS, and distributed query routing. A cluster node can create, drop, clear, write, update, search, list, count, and suggest across every partition. The [cluster dashboard example](examples/cluster-dashboard) starts three nodes against etcd and shows the state of each partition while you cut the network links. Because the layer is experimental and we may change its APIs without notice, pin an exact version before you depend on it. The [cluster guide](../../docs/cluster.md) covers the API. For the contract that every implementation must uphold, read [`packages/spec/distribution`](../spec/distribution).
|
|
133
135
|
|
|
134
136
|
## Search quality
|
|
135
137
|
|
|
136
|
-
|
|
138
|
+
We measure ranking quality on the [BEIR](https://github.com/beir-cellar/beir) SciFact corpus, which holds 5,183 documents and 300 queries with human relevance judgements. We compare Narsil with Orama and MiniSearch in one process. All three use the same 33 Lucene English stop words and default BM25 parameters, although each one stems English in its own way. Narsil has the top nDCG@10 of the three.
|
|
137
139
|
|
|
138
140
|
**What these metrics mean:**
|
|
139
141
|
|
|
140
|
-
- **nDCG@10** measures whether the most relevant documents appear near the top of the results. A score of 1.0 means perfect ranking,
|
|
142
|
+
- **nDCG@10** measures whether the most relevant documents appear near the top of the results. A score of 1.0 means a perfect ranking, while 0.0 means that no relevant document appears in the top 10.
|
|
141
143
|
- **P@10** is the fraction of the top 10 results that are relevant.
|
|
142
|
-
- **MAP** tracks precision at every rank where a relevant document appears. A higher MAP means relevant documents cluster near the top of the ranking.
|
|
143
|
-
- **MRR** measures how soon the first relevant result appears. A higher
|
|
144
|
+
- **MAP** tracks precision at every rank where a relevant document appears. A higher MAP means that relevant documents cluster near the top of the ranking.
|
|
145
|
+
- **MRR** measures how soon the first relevant result appears. A higher MRR means that the first relevant document appears nearer the top.
|
|
144
146
|
|
|
145
|
-
|
|
147
|
+
Continuous integration executes a separate [SciFact regression test](src/__tests__/relevance/scifact.test.ts) on the same corpus. That test fails the build when ranking quality drops below calibrated thresholds.
|
|
146
148
|
|
|
147
|
-
Reproduce these scores with `pnpm --filter benchmarks bench -- --tiers relevance`.
|
|
149
|
+
Reproduce these scores with `pnpm --filter benchmarks bench -- --tiers relevance`. [BENCHMARKS.md](https://github.com/assetcorp/narsil/blob/main/BENCHMARKS.md) holds the full quality, throughput, and latency tables for all three engines.
|
|
148
150
|
|
|
149
|
-
Narsil also
|
|
151
|
+
Narsil also works as a search server. On the BEIR datasets, we compare the server with Elasticsearch, OpenSearch, Qdrant, Weaviate, Typesense, and Meilisearch across keyword, vector, and hybrid retrieval. See [the full benchmarks](https://github.com/assetcorp/narsil/blob/main/BENCHMARKS.md) for those results.
|
|
150
152
|
|
|
151
153
|
## Runtime support
|
|
152
154
|
|
|
@@ -157,7 +159,7 @@ Narsil also runs as a search server. On the BEIR information-retrieval datasets
|
|
|
157
159
|
| Deno | Web Workers | Filesystem | BroadcastChannel |
|
|
158
160
|
| Browser | Web Workers | IndexedDB | BroadcastChannel |
|
|
159
161
|
|
|
160
|
-
The [browser example](examples/browser/README.md) shows an embedded engine with IndexedDB persistence,
|
|
162
|
+
The [browser example](examples/browser/README.md) shows an embedded engine with IndexedDB persistence, while the [server app example](examples/server-app/README.md) shows the same interface over the client SDK and the React hooks.
|
|
161
163
|
|
|
162
164
|
## License
|
|
163
165
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { E as EmbeddingAdapter } from './adapters-79OIa4xm.js';
|
|
2
|
-
import { C as ClusterNamespace } from './config-
|
|
3
|
-
import { h as TaskStore } from './tasks-
|
|
2
|
+
import { C as ClusterNamespace } from './config-qMLpi5T4.js';
|
|
3
|
+
import { h as TaskStore } from './tasks-DiF1c9v2.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Context handed to {@link OnRequestHook} for every inbound request, captured
|