
Rangefind
io.github.xjodoin由 GitHub 帳號 xjodoin 發布v0.3.2更新於 Oct 24, 2026
Search rangefind static indexes: full-text, geo, autocomplete, facets - no server, just files.
概覽
Rangefind 是靜態搜尋引擎,其 MCP 伺服器讓助理對預先建置的靜態索引檔案執行全文、地理、自動完成與 facet 查詢。
- 可以做什麼
- 對 Rangefind 靜態索引執行全文檢索,支援 BM25F 式欄位評分、片語訊號與拼字修正,可透過 MCP 伺服器與 CLI 所用的 Node 執行環境讀取本機索引目錄或遠端 HTTP(S) 索引。查詢地理檢索通道:邊界框與半徑篩選、最近鄰距離排序、路線走廊搜尋以及靜態路徑規劃與行程規劃。使用自動完成與權威索引,對標題、實體與別名做前綴及詞中比對。依關鍵字 facet、數值、日期與布林 doc-value 篩選與排序結果,並可選在按範圍定址的向量索引上執行混合語意搜尋。取得含摘要與高亮範圍的結果酬載。
- 適用情境
- 當網站或語料已有 Rangefind 靜態索引,並希望助理不必執行搜尋後端即可檢索時使用,例如文件、論文語料或基於 OpenStreetMap 的地點索引。適合對靜態檔案做文字、facet、地理與自動完成查詢。
- 執行需求
- 以本機 stdio 程序執行,透過 npx 從 rangefind-mcp npm 套件啟動,需要 Node.js。它讀取本機 Rangefind 索引目錄或遠端 HTTP(S) 索引;主機必須支援對 .bin.gz 檔案的 HTTP Range 請求。未宣告帳號、API 金鑰、環境變數或標頭。
安裝
在 SourceWeft 中
- 開啟 儀表板中的 Rangefind,將其新增到工作區。
- 為需要使用其工具的對話啟用該服務。
Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。
其他 MCP 客戶端
參照 儲存庫 中的啟動說明。
README
Rangefind
Rangefind is a static search engine for large sites that cannot or should not run a search server.
It builds a sparse inverted index into static files, then lets the browser query
that index with HTTP Range requests. The core idea is simple: keep the logical
search shards small, but pack them into a small number of static files so deploys
and cold starts stay practical.
This repository is the standalone extraction of a production prototype built for a large thesis corpus.
What Is Implemented
The list below is the compact overview. The complete feature guide explains every supported search lane, build mode, runtime, integration, feature combination, fallback, and deliberate boundary with runnable examples.
- JSONL document input.
- Static-site crawler:
rangefind build ./distindexes built HTML directly, withdata-rangefind-*attributes for body scoping, metadata, facets, and sorts. - Schema-driven weighted fields.
- BM25F-style field scoring.
- Phrase signals for title/heading fields.
- Adaptive posting segments.
- Independently compressed posting segments packed into
terms/packs/*.bin.gz. - Single ESM browser runtime bundle at
dist/runtime.browser.js. - Node runtime (
rangefind/node) for MCP servers, CLIs, and SSR: same query engine over local index directories (positional file reads) or remote HTTP(S) indexes, with browser-equivalent caching — immutable content-addressed objects cached on disk and in a memory LRU, manifests revalidated with ETags. - Mobile runtime (
rangefind/mobile) for React Native/Hermes and other embedded JS hosts: fully offline search over a bundled or downloaded index via positional file reads, or remote HTTP(S) indexes with memory + persistent caching — seedocs/mobile.md(covers WebView, Flutter, and native apps too). - Lazy paged binary range directories at
terms/directory-root.<hash>.bin.gzandterms/directory-pages/*.bin.gz. - ZFS-inspired object pointers with SHA-256 verification before decompression.
- Content-addressed immutable pack and directory filenames for CDN caching.
- Exact compressed-object deduplication during index construction.
- Locality-ordered doc packs with a tiny doc-id ordinal table and dense pointer records for low-transfer result fetching.
- Dense binary doc-page payload packs for browse, filter, and sort result pages where original document ids are clustered.
- Range-packed result payloads with capped display fields.
- Range-addressable posting-block sidecar for high-df terms.
- Optional authority sidecar for exact title/entity/alias rescue without changing the main inverted index; a single title authority also supplies bounded prefix autocomplete without a second large build structure.
- Range-packed binary facet dictionaries for high-cardinality metadata.
- File-backed build pipeline with immutable posting segments, selected-term spools, raw/compressed document spools, heap-based segment merge, and sampled build telemetry.
- Minimal runtime manifest with lazy full-manifest and telemetry sidecars.
- Browser runtime with adaptive HTTP
Rangecoalescing and bounded overfetch. - Main-index typo correction that uses bounded vocabulary shard probes and executes only the strongest corrected searches when first-page results are empty or weak.
- Multi-value keyword facets with lazy dictionary loading.
- Range-addressed typed numeric, date, and boolean doc-values for filters and sorting.
- Lazy binary sorted doc-value trees for range-pruned top-k sort and doc-order early-stop browsing.
- Lucene-style geo point fields with a range-addressed static KD tree: bounding-box and radius filters, exact nearest-neighbor distance sort with early-stop proofs (with or without a text query), text-plus-geo filtering, per-cell filter summaries, and distance boosts.
- Optional compact geo result capsules and multi-resolution facet-to-cell indexes for one-range map results and category-aware spatial routing, plus a wildcard occupancy lane for arbitrary names and brands.
- Generic route-corridor search over encoded polylines, coordinate arrays, or GeoJSON: exact point-to-route filtering, multi-resolution corridor cells, progress/direction/viewport ranking, and a rejoin point for every result.
- Static routing and itinerary planning (
rangefind/route): a CRP/MLD route graph built from OSM road networks into range-addressed cell and overlay objects — point-to-point driving routes with geometry and named steps, travel-time matrices, and multi-stop itinerary optimization, all exact versus a full-graph Dijkstra and served from static files with a bounded fetch set per query; sharded builds share one top overlay and route identically to monolithic ones — seedocs/route-graph.md. - Search-as-you-type autocomplete inside the range-addressed authority index: diacritic-folded prefix and mid-label token matching, popularity or custom weights, exact best-first top-k with per-shard weight proofs, and precomputed hot lists so a first keystroke costs one small fetch—without a second suggestion pack family or a corpus-sized heap map.
- Hybrid semantic search from a range-addressed IVF vector index: int8 quantized embeddings, coarse-dimension candidate pages plus a fixed-width full-dimension refine store, cosine top-k, and reciprocal-rank fusion with the text lane — no server, no vector database.
- Analyzer-consistent snippets and highlight ranges on search results.
- Multilingual analysis (
analysisconfig): per-document language detection or an explicit language field, per-language light stemmers and stopwords for 20+ languages, script-aware Unicode folding (Latin, Greek, Cyrillic, Arabic, Hebrew, Devanagari), dictionary-free CJK bigram tokenization that is deterministic across Node and every browser, cross-language query expansion with index-evidence base-plan selection, and the whole profile frozen into the manifest so query analysis always matches the index. - Incremental publishing:
rangefind build --updateadds small delta generations over an existing index — unchanged pack bytes keep their content-addressed names (and CDN cache entries), replaced documents tombstone their old version, and the runtime merges every lane (text, sorted browse, geo, vector, hybrid, suggest, facets) across generations with scores that stay exactly comparable.rangefind build --compactfolds generations back into a single index when they pile up. - Per-query facet counts with exact-or-flagged semantics: dictionary-backed global counts, exact counts over budgeted match sets, and bounded chunk-sampled estimates for very large result sets.
- OpenStreetMap place and address fixture with canonical zero-posting address
lookup, compact
addr:interpolationranges, structured forward and reverse geocoding, bounded multi-provider civic/postal augmentation (including the Québec RQA adapter), reusablerangefind/osmandrangefind/osm/nodeintegration APIs, and exhaustive geo oracles. - OSM typed and natural-language constraints for accessibility, services,
payment, seating, reservations, fees, and open-now; conservative client-side
opening_hoursevaluation; route-aware place search; compact place details; and simplified encoded area geometry for real polygon/line map rendering. - Geographic index sharding for planet-scale corpora: independently built and
updated per-region shards sharing one frozen scoring-stats artifact
(
scoringStatsconfig +rangefind/scoring-stats), a tiny sharded root manifest (rangefind/shards), lazy shard engines with bbox geo routing and expanding nearest-first search, and merged lanes whose rankings match a monolithic build of the same corpus exactly — seedocs/sharded-osm.md. - Link-graph authority (
linkRank): the static-site crawler resolves internal<a href>links into a document graph and folds a build-time PageRank prior into a sortable numeric doc-value. Well-linked pages win near-ties in ranking (an opt-out multiplicative boost,score *= 1 + boost*linkRank, applied as a bounded window rerank with no change to the scoring hot loop), you can sort by authority, and there is zero query-time graph traversal. Any corpus that knows its own edges can opt in with the turnkeyexamples/link-graph-enrich.mjsenricher (or the exportedrangefind/link-graphhelper); seedocs/link-graph.md. - Tiny runnable example.
Why This Exists
Most browser search libraries assume the browser downloads a whole index, or they optimize for smaller sites. Rangefind is for the case where you want:
- no backend service,
- no hosted search provider,
- static hosting compatibility,
- measurable retrieval quality,
- low request count despite many logical shards,
- and an index format designed around top-k retrieval.
Quick Start
Demos: https://rangefind.dev/ — an OpenStreetMap map search backed by the rolling public sharded index (autocomplete, viewport geo queries, and nearest-neighbor) and the minimal example, both served as pure static files.
The already-generated planet-scale OSM index is free to query directly from browsers or Node—no account or API key required:
See its live coverage and freshness at https://osm.rangefind.dev/. It is a
best-effort public service; self-host the index when you need guaranteed
capacity, version pinning, custom fields, or an operational SLA. OSM result
UIs must display
© OpenStreetMap contributors.
Open http://localhost:5178/.
Documentation
Start with the guide that matches the job:
Crawl A Static Site
If you already have a built static site (from any generator), point Rangefind at the output directory and it indexes the HTML directly — no JSONL to author:
This crawls every .html/.htm file under ./dist, extracts the title,
headings, and main body text, and writes the index to ./dist/rangefind (change
it with --output). Result URLs default to site-root paths (--base-url sets a
prefix or origin, e.g. --base-url https://example.com/). Deploy the site and
load the index with createSearch({ baseUrl: "/rangefind/" }).
Content selection follows the document: the crawler indexes <main>, else
<article>, else <body>, and always drops <script>, <style>, <nav>, and
<aside>. <header>/<footer> are dropped only when the fallback <body>
region is used (no <main>/<article>), so an in-article post header and its
<h1> are still indexed. Opt-in data-rangefind-* attributes
(mirroring Pagefind's vocabulary) tune it:
Per-document language comes from <html lang="…"> and the page description from
<meta name="description">. See the
reference guide for the full rules.
Search UI Component
Pair the crawler with a drop-in search box. <rangefind-search> is a
framework-agnostic Web Component: two lines of HTML give any static site a
polished, accessible search box (WAI-ARIA combobox, keyboard navigation,
instant results, autocomplete).
It renders into its light DOM and ships no styling of its own, so it
composes with whatever CSS you already use. Style it three ways: the optional
theme stylesheet, your own CSS via the rf-search* hook classes, or utility
classes passed per part. Here it is styled purely with Tailwind — no theme CSS:
Prefer the batteries-included look? Link the opt-in theme (light + dark) and
skip the *-class attributes:
Works in plain HTML, React, Vue, Svelte, and Angular — Web Components are
universal. It emits rangefind:search, rangefind:select, and
rangefind:error events, and takes .classNames / .searchOptions JS
properties for programmatic use. Build the bundle with npm run build:element;
try it against the basic example (npm run build:example && npm run serve:example) at /component.html (theme) and /component-tailwind.html
(Tailwind). See the
reference guide for every attribute,
the full class-hook list, events, and accessibility notes.
Static Site Generator Adapters
The crawler and the search component compose naturally with any static site generator's own build lifecycle — an adapter runs the crawl right after the generator writes its output and drops the client assets in for you, so there's nothing to wire up by hand beyond installing it.
Astro, Eleventy, and Docusaurus are each real, independently installable
packages under packages/ (built with zero dependencies beyond the target
generator itself); Hugo and MkDocs live under integrations/ since neither
has an npm-based plugin system of its own. Every one of them is verified
end to end against the real tool — a real Astro/Eleventy/Docusaurus build, a
Homebrew-installed Hugo binary, and a pip-installed MkDocs — crawling a
fixture site and confirming the resulting index actually answers a search
query. See each package's own README for install instructions and options.
Full Wikipedia Search Site
The examples/wiki-search project is a fuller static search application for
Wikimedia article dumps. It defaults to the latest English Wikipedia articles
dump and can run on a bounded sample or the full dump:
Use npm run build:wiki-site:full to build the full default dump with the
bounded body cap, or npm run build:wiki-site:fr:full for the full French
Wikipedia dump. The generated site lives at examples/wiki-search/public/ and
keeps the same static hosting requirement as every Rangefind index: the host
must support HTTP Range requests for .bin.gz files.
French Wikipedia Scalability Fixture
Rangefind includes a reproducible French Wikipedia fixture that streams the official Wikimedia article dump, builds a static site, and benchmarks query latency, request count, and transfer size:
For runtime-only changes, reuse the existing generated index and rerun just the request/transfer benchmark:
Use --limit=0 to run against the full dump. The generated site lives at
examples/frwiki/public/. The fixture validates text query top-k against the
exact retrieval path by default and records cold request counts, transfer bytes,
runtime posting-block stats, typed filter/sort validation, and scale reports
across multiple Wikipedia sample sizes.
Extracted JSONL is cached under examples/frwiki/data/, so later runs with the
same dump/body cap and an equal or smaller limit do not stream the dump again.
Each generated index includes manifest.min.json, manifest.full.json, and
debug/build-telemetry.json. The full diagnostic manifest.json is still
written for local inspection and records phase timings, sampled memory peaks,
CPU time, disk byte deltas, and segment counters.
Build A Custom Index
For the complete configuration schema, every tuning knob, the full runtime API, and deployment requirements, see the reference guide. The walkthrough below is the quick version.
Create newline-delimited JSON:
Create rangefind.config.json:
display controls only the payload returned with search results. Indexed fields
can stay long while returned fields are capped, for example:
For large static corpora, targetPostingsPerDoc is the body-term budget.
bodyIndexChars caps only the text considered by the indexer, while display
payload size stays controlled by display entries. Terms from
alwaysIndexFields are indexed before the body budget is applied.
typoMode: "main-index" uses the normal term vocabulary for typo candidates
instead of building a separate typo sidecar. Use typoMode: "off" to disable
correction.
authority fields build a packed lexicon for canonical labels such as
titles, entity names, product names, slugs, and aliases. The runtime first tries
a diacritic-preserving surface-exact key, then falls back to folded exact and
token keys only when needed, so common title rescue stays precise and cheap
without forcing all label logic into the BM25 posting lists. suggest fields
stream into the same external-run reducer under an autocomplete namespace, so
multi-million-document builds never create a duplicate in-memory title map or
a separate suggest/ pack family.
Build:
Query in the browser:
Filters and sort use range-addressed doc-value columns:
Geo fields index one point per document into a range-addressed static KD tree
(Lucene LatLonPoint-style, E7 fixed precision):
Results include distanceMeters whenever geo.near is present. Radius and
box filters are exact (bounding-box prune plus Haversine verification), and
stats reports the tree traversal (geoLane, geoLeavesVisited,
geoPointsScanned, ...). See examples/osm-geo/ for an OpenStreetMap-scale
example and benchmark.
Weighted and mid-label search-as-you-type suggestions use the authority lexicon:
Matching is prefix-based over diacritic-folded keys ("montre" finds
"Montréal") and covers mid-label tokens ("eiffel" finds "Tour Eiffel").
Ranking uses an optional weightPath (for example population or importance)
and falls back to direct-prefix priority plus popularity — how many documents
share the surface. Each keystroke costs at most a few small range requests;
repeat keystrokes in a session are usually served entirely from cache.
Suggestions also carry the best documents behind each surface (doc/docs),
and hydrate: true resolves them into real search hits — the same display
payloads search() returns — so a dropdown can show result cards and a
selected suggestion renders instantly instead of re-running the query as a
search (measured 0.5 KB and 4 ms, versus 215 KB and 32 ms re-searching its
text). The autocomplete guide covers the patterns,
what each costs per keystroke, and when to prefer focused previews over
hydrating every row.
For title-prefix completion on an older index, a single
authority: [{ "name": "title", "path": "title" }] field is also sufficient.
The runtime walks the first matching authority shards in key order and hydrates
only the requested titles. New builds should configure suggest to get custom
weights, popularity fallback, mid-label completion, and hot-prefix lists in the
same authority packs.
Facet counts for filter UIs come back with the search response:
Hybrid semantic search takes a query embedding from the host (for example transformers.js in the browser) and fuses it with the text lane:
Typo fallback is automatic. For example, if statik search has no exact
first-page hits but static search does, the response includes:
Static Hosting Requirement
The runtime expects the host to support HTTP Range requests for .bin.gz files.
GitHub Pages supports this. The included local server also supports it.
Development
The unit tests cover analyzer normalization, binary varint/fixed-width codecs,
config resolution, shard/range planning, term/code binary round-trips, and an
end-to-end build plus browser-runtime query against a local HTTP Range server.
The end-to-end build test also verifies emitted build telemetry and file-backed
spool counters in the manifest.
The benchmark scripts are dependency-free and run against the example static
site. bench:quality reports known-item and typo-recovery Hit@k/MRR plus
structured filter/sort checks for facets, dates, booleans, and signed numbers.
bench:performance reports query latency, HTTP request count, and transfer size.
bench:directories compares global, naive prefix, and paged range-directory
layouts against an existing built index.
bench:osm-maps runs the weighted common map-search workload documented in
docs/osm-maps-benchmark.md, including locality,
nearest-first, viewport, shard fan-out, and phone-budget checks.
docs/performance-research.md tracks the top-k retrieval papers currently
guiding format decisions.
Project Direction
Planned next milestones:
- Pagefind/Lucene/SQLite benchmark package,
- build-time sparse expansion hooks,
- WASM-free and WASM-assisted runtime comparisons,
- CI release workflow + published npm package.
Contributions are welcome — see CONTRIBUTING.md.
License
MIT © Xavier Jodoin
來源:README.md,提交 c2ee5d2
工具
0版本歷史
1- v0.3.2最新Sep 16, 2026
評分
已滿足適用檢查項的 50%
該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。
- 近 30 天內可連通25 分
請保持端點能夠回應 MCP 握手;SourceWeft 每 30 天探測一次。
- 已宣告認證方式10 分
請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。
- 已列出工具15 分
請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。
- 描述必需15 分
- 圖示10 分
- 文件15 分
- 授權條款10 分