MoonSearch

A MoonBit-native embedded full-text search kernel

search
full-text-search
inverted-index
moon add Lucius646/MoonSearch@0.9.0
Download zip
Author
Version
0.9.0
License
Apache-2.0
Last updated
12 hours ago
Downloads
8

Dependencies

README

#MoonSearch

CI Pages MoonBit License

MoonSearch is a MoonBit-native embedded full-text search kernel. It follows the component boundaries popularized by Tantivy and the inverted-index semantics of Lucene, while keeping the implementation, storage format, analyzers, query engine, CLI, benchmarks, and browser Wasm bridge in MoonBit.

The project is designed for learning, experimentation, and applications that want a compact search engine embedded in the same process. It currently ships a schema-aware inverted index, pluggable text analysis, optional Chinese analysis, BM25 search, immutable multi-segment storage, result highlighting, a JSONL CLI, a deterministic benchmark suite, and an in-browser WasmGC demo.

[!IMPORTANT] MoonSearch source metadata is currently at 0.9.0 and is still evolving. Read Current limitations before adopting it for production data or a long-lived persistence contract.

#Contents

#Highlights

  • MoonBit-native core — the indexing, storage, query, scoring, analysis, highlighting, CLI, and benchmark paths are implemented in MoonBit.
  • Typed Schema and Fast Fields — text, keyword, i64/u64/f64, bool, date, and bytes fields independently declare indexed, stored, fast, and cardinality behavior; fast columns are addressable by docID.
  • Pluggable analysis — lazy TokenStream, open Tokenizer and TokenFilter traits, composed TextAnalyzer pipelines, and snapshot-based TokenizerManager registries.
  • English and Unicode analysis — raw, whitespace, default lowercase, n-gram, stop-word, long-token, and Porter2 English stemming components.
  • Optional Chinese analysis — injected dictionaries, longest matching, weighted frequency-DAG routing, optional B/M/E/S HMM recognition, and dictionary-gated search-mode expansion.
  • Full-text queries — Term/Boolean/Phrase, prefix/wildcard/regex/fuzzy and range queries, compound scoring, phrase slop/prefix, and graph-aware analysis.
  • BM25 and global Top-K — snapshot-wide statistics are shared across immutable Segments before one global result selection.
  • Filtering, sorting, and analytics — exact/range/exists filters, deterministic multi-field sorting, Count/TopDocs/MultiCollector, terms/range facets, and numeric/date aggregations.
  • Durable index lifecycle — Directory v2 atomic publication and capability detection, two-phase commits, native OS writer locks, Reader reload, atomic updates, integrity checking, recovery/GC, and merge scheduling.
  • UTF-8-safe highlighting — persisted postings offsets, structured source byte ranges, query-tree-aware highlighting, and caller-defined markers.
  • Practical tooling — a UTF-8 JSONL CLI, machine-readable JSON output, four-target CI, release-mode benchmarks, and a browser WasmGC demo.

#Installation

Add the package from Mooncakes:

moon add Lucius646/MoonSearch@0.9.0

Import the root compatibility facade from your package:

///|
import {
"Lucius646/MoonSearch",
}

The root package re-exports the supported public API. Advanced users may import the focused core, schema, analysis, analysis/chinese, index, query, or store packages directly when they need tighter dependency boundaries.

#Library quick start

The smallest useful flow is:

Schema → Documents → SegmentWriter → Segment → QueryParser → Searcher → Top-K

///|
fn main {
let tokenizers = @MoonSearch.TokenizerManager::with_defaults()

let builder = @MoonSearch.SchemaBuilder::new()
let title = builder.add_text_field(
"title",
@MoonSearch.TextOptions::new(true, true).with_tokenizer("default"),
)
let body = builder.add_text_field(
"body",
@MoonSearch.TextOptions::new(true, true).with_tokenizer("en_stem"),
)
let schema = builder.build()

let writer = @MoonSearch.SegmentWriter::with_schema_and_tokenizers(
schema, tokenizers,
) catch {
error => abort(error.to_string())
}

let first = @MoonSearch.Document::new()
first.add_text(title, "MoonSearch")
first.add_text(body, "A MoonBit full-text search engine")
ignore(writer.add_document(first))

let second = @MoonSearch.Document::new()
second.add_text(title, "Language guide")
second.add_text(body, "MoonBit language documentation")
ignore(writer.add_document(second))

let searcher = @MoonSearch.Searcher::new(writer.finish())
let parser = @MoonSearch.QueryParser::new(schema, tokenizers)
let query = parser.parse_query(body, "SEARCHES") catch {
error => abort(error.to_string())
}

let hits = searcher.search(query, @MoonSearch.TopKCollector::new(10))
for hit in hits {
match searcher.doc(hit.address) {
Some(document) => {
let titles = document.texts_for(title)
println("score=\{hit.score} title=\{titles[0]}")
}
None => ()
}
}
}

en_stem lowercases and stems both indexed text and raw query text, so the query above resolves to the same analyzed term as the indexed word search.

For a complete multi-segment lifecycle with committed snapshots, deletion, and Merge, run the retained example:

moon run cmd/main --frozen

#CLI quick start

MoonSearch includes a real moonsearch executable with three subcommands:

moonsearch index append UTF-8 JSONL documents as one immutable Segment moonsearch search search one indexed field moonsearch inspect show snapshot and Schema metadata

Display the full help:

moon run cmd/moonsearch --frozen -- --help

#1. Prepare JSONL

Each non-empty line must be a JSON object. Configured fields accept a string or an array of strings. Other keys are ignored.

{"title":"MoonSearch","body":"MoonBit full text search engine"} {"title":"MoonBit Guide","body":["language documentation","MoonBit basics"]} {"title":"Search Notes","body":"UTF-8 indexing and highlighting"}

The repository contains the same shape at cmd/moonsearch/testdata/documents.jsonl.

#2. Build an index

moon run cmd/moonsearch --frozen -- index \ --index .moonsearch-index \ --input cmd/moonsearch/testdata/documents.jsonl \ --field title \ --field body \ --tokenizer default

Every listed field is indexed and stored. Re-running index appends another immutable Segment. The field names, field order, and tokenizer name must match the Schema already persisted in the index directory.

The CLI accepts the built-in tokenizer names default, whitespace, raw, and en_stem.

Terms are ORed by default. Use --operator and to require every analyzed term, or --phrase for an exact positional Phrase query.

moon run cmd/moonsearch --frozen -- search \ --index .moonsearch-index \ --field body \ --query "moonbit search" \ --operator and \ --limit 10

Enable highlighting and JSON output:

moon run cmd/moonsearch --frozen -- search \ --index .moonsearch-index \ --field body \ --query "full text" \ --phrase \ --highlight \ --fragment-size 160 \ --json

Text output wraps matches in [[ and ]]. JSON output keeps stored fields unchanged and adds structured highlights containing the source value index, fragment range, omission flags, and match byte offsets.

Parse a strict field-aware Query-string, using --field as the default for unqualified literals:

moon run cmd/moonsearch --frozen -- search \ --index .moonsearch-index \ --field body \ --query 'title:MoonSearch OR body:"full text"' \ --query-string \ --json

Query-string highlighting is deliberately rejected in v1 because a structured query can contain different fields, negative clauses, and nested Boolean semantics. The raw Term/Boolean/Phrase modes retain structured highlighting.

#4. Inspect

moon run cmd/moonsearch --frozen -- inspect \ --index .moonsearch-index \ --json

inspect reports the current manifest generation, immutable Segment count, live document count, and every field's indexed/stored/tokenizer options.

All commands use human-readable text by default. Pass --json or --format json for machine-readable output. The native executable returns:

  • 0 for success;
  • 1 for input, I/O, index, or query failures;
  • 2 for invalid arguments.

moon run may normalize a child executable's non-zero status. Build or install the native executable when an automation needs the exact process exit code.

The CLI intentionally loads only built-in tokenizer pipelines. Applications using injected Chinese dictionaries, HMM models, or other custom registry names should open the index through the library API.

#Browser Wasm Demo

Open the hosted Browser Wasm Demo or run the same static application locally. Documents and queries stay inside the browser; no search backend is contacted.

The browser-facing WasmGC foreign library runs in a dedicated Web Worker. The worker loads same-origin offline JSONL/Gzip and Analyzer resources, parses documents, builds an in-memory Segment, constructs Term/Boolean/Phrase/Query-string queries, and calculates BM25 scores. Raw query modes also return structured UTF-8 highlight ranges. The main thread only manages input, progress, cancellation, and safe result rendering; it does not implement a second search engine.

Build and serve the demo from the repository root:

npm run demo:build npm run demo:serve

Open http://127.0.0.1:4173. The page starts with four mixed English/Chinese documents and can switch to offline Chinese Wikipedia 4,000, English Wikipedia 4,000, the combined 8,000 article corpus, pasted JSONL, or a local .jsonl / .jsonl.gz file. Dataset defaults select zh_search_v1, en_stem_v1, or multilingual_v1; the page previews query tokens and allows an explicit override. Each line must contain title or body; either value may be a string or an array of strings.

The query selector exposes:

  • Term, requiring exactly one analyzed term;
  • Boolean · OR and Boolean · AND;
  • positional Phrase matching;
  • strict Query-string expressions with fields, grouping, Boolean operators, quoted phrases/slop, ranges, wildcard/regex/fuzzy terms, +/-, boosts, and escaping.

Browser source text is inserted as text nodes, while structured byte ranges are mapped to <mark> elements. Invalid JSONL, empty queries, unsupported inputs, no-result searches, and Wasm loading failure all produce explicit UI states. Query-string results currently render safe stored text without marks until a query-tree-aware highlighting contract is added.

Install the browser test dependency and run both integration layers:

npm install npm run test:data npm run test:wasm npm run test:browser npm run benchmark:browser

These optional suites validate offline data integrity, the release WasmGC ABI, sample and 4,000-document browser paths, main-thread responsiveness, cancellation, and runtime failures. The opt-in benchmark records 500/4,000/8,000-document loading and query timings. See demo/browser/README.md for the full runtime contract and scope.

#Architecture

MoonSearch separates the search lifecycle into responsibility-focused packages:

Document │ ▼ Schema ──→ TokenizerManager ──→ TokenStream / TokenFilter │ │ └──────────────────────────────────┘ │ ▼ SegmentWriter │ ▼ immutable Segment + stored fields │ ▼ Directory + generation manifest │ ▼ IndexReader snapshot → Searcher │ │ │ ▼ │ Query → Weight → Scorer │ │ └──────────────┴─→ TopKCollector │ ▼ StoredDocument + Highlighter

The package dependency direction is acyclic:

core ──→ schema ──→ analysis ──→ index ──→ query ──→ store │ └─→ analysis/chinese internal/codec shared binary primitives used by index and store benchmarks deterministic public-API performance fixtures cmd/main embedded lifecycle example cmd/moonsearch JSONL command-line application tests/integration root-facade cross-package tests

The arrows show responsibility flow rather than a requirement that every package import its immediate neighbor.

#Text analysis

All token offsets are UTF-8 byte offsets. Positions are zero-based graph nodes, and position_length describes how many input positions a token spans.

TokenizerManager::with_defaults() registers these ready-to-use pipelines:

NamePipelineTypical use
rawEntire input as one tokenIdentifiers or exact whole-value matching
whitespaceUnicode whitespace splittingPre-tokenized or case-sensitive text
defaultSimpleTokenizer → remove tokens over 40 UTF-8 bytes → lowercaseGeneral Unicode text
en_stemSimple tokenization → length filter → lowercase → Porter2 stemmingEnglish full-text search

NgramTokenizer remains opt-in because the application must choose its minimum size, maximum size, and prefix-only policy. It is a generic recall tool, not a replacement for linguistic Chinese segmentation.

Applications can implement the open Tokenizer, TokenStream, and TokenFilter traits, compose them with TextAnalyzer, and register the result under a Schema tokenizer name. Writers, parsers, and highlighters capture registry snapshots when constructed, so later registry mutation cannot change their behavior unexpectedly.

TokenGraph validates analyzed streams and expands at most 256 finite strings by default. Boolean and Phrase parsing consume those paths, which supports stacked alternatives and multi-position tokens while bounding accidental graph explosion.

#Chinese analysis

Chinese support lives in the optional analysis/chinese package and is re-exported by the root facade. MoonSearch does not bundle a large dictionary or an HMM model; applications inject the resources they intend to ship.

Available policies include:

  • longest dictionary matching with mixed-script fallback;
  • weighted frequency-DAG route selection;
  • optional B/M/E/S Viterbi recognition for unknown Han runs;
  • dictionary-gated two- and three-character search-mode subwords;
  • separate precise query and flattened index pipelines.

A minimal dictionary can be constructed from words, weighted entries, or a line-oriented UTF-8 resource:

///|
let lexicon = @MoonSearch.ChineseLexicon::from_dictionary_text(
(
#|月兔 100
#|全文 80
#|搜索 120
#|搜索引擎 200
#|中文 100
#|分词 90
#|
),
) catch {
error => abort(error.to_string())
}

For search-mode recall, use the flat search expansion while indexing and the matching precise analyzer while querying. Register both under the same Schema name in separate manager snapshots:

///|
let index_tokenizers = @MoonSearch.TokenizerManager::with_defaults()
index_tokenizers.register(
"zh_search",
@MoonSearch.chinese_dag_search_index_analyzer(lexicon),
) catch {
error => abort(error.to_string())
}

///|
let query_tokenizers = @MoonSearch.TokenizerManager::with_defaults()
query_tokenizers.register(
"zh_search",
@MoonSearch.chinese_dag_analyzer(lexicon),
) catch {
error => abort(error.to_string())
}

The flattened index form stacks a primary word and its dictionary subwords at one ordinal position. The precise query form preserves graph structure. This policy keeps cross-word phrases exact without changing the current postings format.

#Queries and scoring

MoonSearch exposes composable low-level queries and a field-aware parser:

ComponentBehavior
TermQueryMatches one already analyzed field term
BooleanQueryCombines Must, Should, and MustNot clauses
BoostQueryMultiplies a child query's score
PhraseQuery / PhrasePrefixQueryPositional phrase, configurable slop, and prefix completion
PrefixQuery / WildcardQuery / RegexQuery / FuzzyQueryBounded multi-term expansion
RangeQuery / TermRangeQueryTyped and lexical ranges
MatchAllQuery / ExistsQuery / TermSetQueryMatch-all, field existence, and constant-score term sets
DisjunctionMaxQuery / ConstantScoreQuery / FunctionScoreQueryCompound scoring
QueryParserAnalyzes raw text and builds Term/Boolean/Phrase queries
QueryStringParserStrict or lenient field-aware parsing, binding, and highlighting
Bm25ScorerScores postings with snapshot-wide BM25 statistics
TopKCollectorSelects one globally ordered Top-K across Segments

QueryParser::parse_query uses OR semantics by default. Call set_conjunction_by_default(true) for AND semantics, or use parse_phrase to preserve analyzed gaps and Token Graph paths in an exact Phrase query.

QueryStringParser keeps syntax parsing separate from semantic binding:

///|
let parser = @MoonSearch.QueryStringParser::new(schema, tokenizers, [
title, body,
])

///|
let ast = parser.parse_ast("title:MoonBit AND body:\"full text\"") catch {
error => abort(error.to_string())
}

///|
let query = parser.build_query_from_ast(ast) catch {
error => abort(error.to_string())
}

The grammar supports unqualified terms, phrases and phrase slop, field scopes, inclusive/exclusive/open ranges, wildcard and regex patterns, fuzzy terms, parentheses, uppercase AND/OR/NOT, +/- modifiers, boosts, and escaping. AND binds more tightly than OR; adjacent clauses use configurable OR or AND semantics. Strict errors carry half-open UTF-8 byte spans, while parse_query_lenient returns the recovered query and warnings. Input size, nesting, AST nodes, Boolean clauses, and multi-term expansion are bounded.

Multi-field weighting is expressed through normal query composition:

///|
let query = @MoonSearch.BooleanQuery::new([
@MoonSearch.BooleanClause::new(
@MoonSearch.Occur::Should,
@MoonSearch.BoostQuery::new(title_query, 3.0),
),
@MoonSearch.BooleanClause::new(
@MoonSearch.Occur::Should,
@MoonSearch.BoostQuery::new(body_query, 1.0),
),
])

#Highlighting

Highlighter supports the re-analysis convenience path and a postings path backed by Segment v5 offsets. QueryStringParser::highlight_query expands the field-aware query tree and ignores prohibited clauses.

It returns a HighlightFragment rather than HTML:

  • text is a valid UTF-8 fragment of the original stored value;
  • fragment and match offsets are source-relative UTF-8 byte ranges;
  • prefix_omitted and suffix_omitted describe truncation;
  • Terms mode highlights normalized term matches;
  • Phrase mode highlights only real positional phrase occurrences;
  • Token Graph paths and multi-position tokens remain phrase-aware.

The default fragment limit is 160 Unicode scalars. The window maximizes the number of complete matches, breaks ties toward the earliest window, and never splits UTF-8. A single match longer than the configured limit remains whole.

///|
let highlighter = @MoonSearch.Highlighter::new(schema, tokenizers)

///|
let fragment = highlighter.highlight(
body,
"MOONBIT SEARCH",
stored_body,
@MoonSearch.HighlightOptions::new()
.with_mode(@MoonSearch.HighlightMode::Phrase)
.with_max_chars(160),
) catch {
error => abort(error.to_string())
}

///|
match fragment {
Some(fragment) => println(fragment.render("<mark>", "</mark>"))
None => ()
}

render inserts caller-provided markers but performs no HTML or terminal escaping. Escape untrusted source text for the target output context before using markup delimiters.

#Index lifecycle and persistence

MoonSearch writes immutable Segments and publishes them through a generation-based manifest:

SegmentWriter.finish() │ ▼ IndexWriter.commit(segment) │ ▼ published generation ──→ IndexReader snapshot ──→ Searcher

Key behaviors:

  • MemoryDirectory provides an in-process backend for tests and embedded use.
  • FsDirectory persists Segment and manifest data beneath an application-owned directory.
  • prepare_commit persists and syncs immutable data without changing readers; commit_prepared atomically replaces the visible manifest, and rollback removes an unpublished Segment;
  • native filesystem writers use crash-released OS file locks; portable targets expose weaker guarantees through DirectoryCapabilities;
  • IndexReader.reload/open_if_changed adopts a later generation while Searchers created before reload retain their previous immutable snapshot;
  • check_index validates manifest references, Segment checksums, tombstones, and Schema compatibility while reporting orphan and temporary files;
  • MergePolicy and MergeScheduler provide deterministic count thresholds and a hard input-byte budget;
  • each IndexReader observes the generation it opened; publishing a later generation does not mutate the existing reader snapshot;
  • term deletion records deleted document IDs without rewriting immutable Segment postings;
  • Merge copies live index structures into one new Segment and does not re-analyze stored documents;
  • stored text preserves multiple values per field and their insertion order;
  • Segment v5 stores block postings/positions, skip metadata, front-coded terms, compressed lazy stored fields, typed/Fast Field values, source offsets, position length, and value index;
  • the decoder retains compatibility with earlier Segment v1/v2/v3/v4 files.

Applications reopening a custom-analyzer index must register a compatible Tokenizer implementation under every persisted Schema name. Executable tokenizer code and external dictionaries are not embedded in Segment files.

#Benchmarks

M6c adds deterministic benchmarks under benchmarks/. They use MoonBit's built-in benchmark harness and exercise only public MoonSearch APIs.

The current suite measures:

  • default mixed-UTF-8, English stemming, and Chinese DAG analysis;
  • schema-aware construction of a 256-document Segment;
  • Term, Boolean AND, and Phrase Top-K search over 2,048 documents;
  • Terms and Phrase highlighting over mixed UTF-8 source text.

Run the primary benchmark on an otherwise idle machine:

moon bench benchmarks \ --release \ --target native \ --deny-warn \ --frozen \ --no-parallelize

Compile the suite for every supported target without collecting timing data:

moon bench benchmarks --build-only --target all --deny-warn --frozen

Search and Highlight setup happens outside timed closures. Segment construction stays inside the Index benchmark's timed closure, and pure results are passed to b.keep to prevent dead-code elimination.

Normal CI runs only the four-target build-only check. The manually dispatched Benchmark workflow runs native release measurements and uploads runner, CPU, MoonBit version, and console logs for 30 days. The project intentionally defines no absolute timing threshold and commits no machine-specific result as a universal baseline.

#Package layout

PathResponsibility
core/IDs, Documents, stored fields, Terms, shared errors
schema/field options, Schema, SchemaBuilder
analysis/Tokenizers, TokenStreams, filters, Token Graph, registry, English stemming
analysis/chinese/dictionary, DAG, HMM, and search-mode Chinese analysis
index/Segment writing, postings, positions, codec, snapshots, Merge
query/queries, weights, scorers, BM25, collector, parser, search, highlighting
store/Directory abstraction, manifests, IndexWriter, IndexReader
internal/codec/shared binary encoding and validation primitives
cmd/main/embedded API lifecycle example
cmd/moonsearch/JSONL CLI application
demo/browser/WasmGC bridge, static browser UI, sample JSONL, and contract tests
benchmarks/deterministic benchmark fixtures and scenarios
tests/integration/public behavior through the root facade

#Development

Requirements:

  • a current MoonBit toolchain;
  • Git;
  • Node.js 22 and a modern Chromium browser for the Browser Demo tests;
  • no external service is required for the test suite, benchmarks, or demo.

On a fresh clone, run moon build once to synchronize the explicitly versioned MoonBit dependencies before using the --frozen verification commands below.

Common commands:

# Format MoonBit sources moon fmt # Refresh generated public interfaces moon info # Check every supported backend and reject warnings moon check --target all --deny-warn --frozen # Run the full test suite on every backend moon test --target all --deny-warn --frozen # Run the embedded example moon run cmd/main --frozen # Build benchmarks on every backend without measuring moon bench benchmarks --build-only --target all --deny-warn --frozen # Measure the native release build moon bench benchmarks --release --target native --deny-warn --frozen --no-parallelize # Build the WasmGC demo artifact and inspect its ABI npm run test:wasm # Execute browser query and load-failure smoke tests npm run test:browser

The supported CI targets are:

  • WebAssembly (wasm);
  • WebAssembly GC (wasm-gc);
  • JavaScript (js);
  • native C backend (native).

Generated pkg.generated.mbti files are committed so public API changes remain visible in code review.

#Current limitations

  • The Schema supports typed fields and Fast Fields, but not dynamic JSON, IP, vector, or geo fields.
  • QueryStringParser supports fields, grouping, Boolean operators, ranges, wildcard/regex/fuzzy terms, phrase slop, boosts, escaping, and lenient recovery, but is not a complete syntax clone of every Lucene query feature.
  • Highlighting supports re-analysis and Segment v5 postings offsets; query-string highlighting is field-aware and ignores prohibited clauses.
  • The CLI loads only built-in tokenizers and cannot directly load application dictionaries, HMM tables, or arbitrary tokenizer plugins.
  • Chinese dictionaries and HMM models are injected by the application; no large language resource is bundled.
  • Segment v5 reads v1/v2/v3/v4, but remains a project format rather than a Tantivy or Lucene index format.
  • The Browser Demo uses fixed title and body fields with one explicit Analyzer Profile and keeps only one replaceable in-memory Worker index. Its 137-term project-authored lexicon demonstrates DAG/search-mode behavior but is not a production Chinese dictionary.
  • Benchmark numbers are comparable only across equivalent hardware, runtime, power mode, fixture version, and MoonBit toolchain.
  • The API and persistence format may evolve before a stable release.

#Roadmap

Completed foundations:

  • document model, Schema, inverted index, postings, stored text, and BM25;
  • immutable multi-segment storage, manifest generations, deletion, and Merge;
  • streaming analysis, English stemming, Token Graph queries, and Chinese DAG/HMM/search-mode analysis;
  • JSONL CLI, UTF-8-safe highlighting, and deterministic benchmarks;
  • M6d Browser Demo with WasmGC execution and structured BM25/highlight results;
  • M6e offline corpus Demo with bilingual Wikipedia snapshots, Worker isolation, progress/cancellation, and large-corpus browser baselines.
  • M6f bilingual Analyzer Profiles with Chinese DAG/search-mode, English Porter2 stemming, mixed-script processing, and query-token previews.
  • M7 strict Query-string v1 with a Schema-independent AST, field/Analyzer binding, UTF-8-spanned errors, CLI integration, and Browser/Wasm execution.
  • M8 scalable execution core with an ordered term dictionary, seekable posting cursors and Scorers, bounded Top-K collection, cached snapshot statistics, and Segment v3 delta/varint postings.
  • M9 durable index lifecycle with Directory v2, two-phase commit/rollback, native writer locks, Reader reload, atomic updates, recovery, CheckIndex, garbage collection, and merge scheduling.
  • M10 typed fields and collectors with Fast Fields, Segment v4, typed filtering/ranges, stable multi-field sorting, facets, and aggregations.
  • M11 advanced execution and storage with Segment v5 block postings/skip, front-coded terms, compressed lazy stored fields, safe WAND, memory-budgeted flush, cooperative segment execution plans, and merge backpressure.
  • M12 query and analysis completeness with multi-term/compound queries, phrase slop/prefix, scoring explanations, lenient Query-string recovery, persisted-offset highlighting, char filters, synonym graphs, and analyzer resource fingerprints.

The next milestone is v1.0 stabilization. Native thread-pool integration and fresh million-document benchmark reports remain explicit follow-up work. See docs/TANTIVY_PARITY_PLAN.md for the concrete acceptance criteria.

#Contributing

Issues and focused pull requests are welcome. Before submitting a change:

  1. keep package dependencies acyclic and responsibility-focused;
  2. add integration tests for public behavior and white-box tests for local invariants;
  3. run moon info and inspect generated interface changes;
  4. run formatting, four-target checks, and four-target tests;
  5. build the benchmark package when changing a measured path.

Please avoid committing downloaded corpora, generated machine-specific benchmark results, bundled dictionary data without clear licensing, or changes that silently break Segment compatibility.

#Design references

MoonSearch learns from Tantivy's engineering boundaries and Lucene's indexing semantics. It is an independent MoonBit implementation and does not read or write Tantivy or Lucene index directories.

#License

Licensed under the Apache License 2.0.

#
AnalysisError

Stable root-package facade for text analysis.

#
AnalysisResource

Stable root-package facade for text analysis.

#
BlockMaxWandQuery

Stable root-package facade for query construction, scoring, and search.

#
Bm25Config

Stable root-package facade for query construction, scoring, and search.

#
Bm25Scorer

Stable root-package facade for query construction, scoring, and search.

#
BooleanClause

Stable root-package facade for query construction, scoring, and search.

#
BooleanQuery

Stable root-package facade for query construction, scoring, and search.

#
BoostQuery

Stable root-package facade for query construction, scoring, and search.

#
BudgetedSegmentWriter

Stable root-package facade for immutable Segment construction and access.

#
BudgetedWriterStats

Stable root-package facade for immutable Segment construction and access.

#
CharFilter

Stable root-package facade for text analysis.

#
CharFilterResult

Stable root-package facade for text analysis.

#
CharacterMapping

Stable root-package facade for text analysis.

#
ChineseDictionary

Stable root-package facade for optional dictionary-backed Chinese analysis.

#
ChineseDictionaryResourceError

Stable root-package facade for optional dictionary-backed Chinese analysis.

#
ChineseHmmModel

Stable root-package facade for optional dictionary-backed Chinese analysis.

#
ChineseHmmModelError

Stable root-package facade for optional dictionary-backed Chinese analysis.

#
ChineseHmmState

Stable root-package facade for optional dictionary-backed Chinese analysis.

#
ChineseLexicon

Stable root-package facade for optional dictionary-backed Chinese analysis.

#
ChineseLexiconEntry

Stable root-package facade for optional dictionary-backed Chinese analysis.

#
ChineseLexiconError

Stable root-package facade for optional dictionary-backed Chinese analysis.

#
ChineseSearchModeFilter

Stable root-package facade for optional dictionary-backed Chinese analysis.

#
ChineseTokenizer

Stable root-package facade for optional dictionary-backed Chinese analysis.

#
ChineseWordMatch

Stable root-package facade for optional dictionary-backed Chinese analysis.

#
CompatibilityNormalizationCharFilter

Stable root-package facade for text analysis.

#
ConfiguredTermQuery

Stable root-package facade for query construction, scoring, and search.

#
ConstantScoreQuery

Stable root-package facade for query construction, scoring, and search.

#
CountCollector

Stable root-package facade for query construction, scoring, and search.

#
Directory

Stable root-package facade for directory-backed index lifecycle APIs.

#
DirectoryCapabilities

Stable root-package facade for directory-backed index lifecycle APIs.

#
DirectoryV2

Stable root-package facade for directory-backed index lifecycle APIs.

#
DisjunctionMaxQuery

Stable root-package facade for query construction, scoring, and search.

#
DocAddress

Stable root-package facade for MoonSearch's foundational value types.

#
DocId

Stable root-package facade for MoonSearch's foundational value types.

#
Document

Stable root-package facade for MoonSearch's foundational value types.

#
EnglishStemmerFilter

Stable root-package facade for text analysis.

#
ExactQuery

Stable root-package facade for query construction, scoring, and search.

#
ExistsQuery

Stable root-package facade for query construction, scoring, and search.

#
Explanation

Stable root-package facade for query construction, scoring, and search.

#
FacetCount

Stable root-package facade for query construction, scoring, and search.

#
FastFieldColumn

Stable root-package facade for immutable Segment construction and access.

#
FaultInjectingDirectory

Stable root-package facade for directory-backed index lifecycle APIs.

#
FieldId

Stable root-package facade for MoonSearch's foundational value types.

#
FieldOptions

Stable root-package facade for schema construction and field options.

#
FieldType

Stable root-package facade for schema construction and field options.

#
FieldValue

Stable root-package facade for MoonSearch's foundational value types.

#
FieldValueEntry

Stable root-package facade for immutable Segment construction and access.

#
FsDirectory

Stable root-package facade for directory-backed index lifecycle APIs.

#
FunctionScoreQuery

Stable root-package facade for query construction, scoring, and search.

#
FuzzyQuery

Stable root-package facade for query construction, scoring, and search.

#
HighlightFragment

Stable root-package facade for query construction, scoring, and search.

#
HighlightMode

Stable root-package facade for query construction, scoring, and search.

#
HighlightOptions

Stable root-package facade for query construction, scoring, and search.

#
HighlightSpan

Stable root-package facade for query construction, scoring, and search.

#
Highlighter

Stable root-package facade for query construction, scoring, and search.

#
HistogramBucket

Stable root-package facade for query construction, scoring, and search.

#
IndexCheckReport

Stable root-package facade for directory-backed index lifecycle APIs.

#
IndexReader

Stable root-package facade for directory-backed index lifecycle APIs.

#
IndexWriter

Stable root-package facade for directory-backed index lifecycle APIs.

#
IndexingExecutionPlan

Stable root-package facade for immutable Segment construction and access.

#
LenientQueryResult

Stable root-package facade for query construction, scoring, and search.

#
LowerCaseFilter

Stable root-package facade for text analysis.

#
MappingCharFilter

Stable root-package facade for text analysis.

#
MatchAllQuery

Stable root-package facade for query construction, scoring, and search.

#
MemoryDirectory

Stable root-package facade for directory-backed index lifecycle APIs.

#
MergePolicy

Stable root-package facade for directory-backed index lifecycle APIs.

#
MergeScheduler

Stable root-package facade for directory-backed index lifecycle APIs.

#
MissingValueOrder

Stable root-package facade for query construction, scoring, and search.

#
MmapDirectory

Stable root-package facade for directory-backed index lifecycle APIs.

#
MultiCollector

Stable root-package facade for query construction, scoring, and search.

#
MultiCollectorResult

Stable root-package facade for query construction, scoring, and search.

#
MultiTermRewrite

Stable root-package facade for query construction, scoring, and search.

#
NgramTokenizer

Stable root-package facade for text analysis.

#
NumericAggregation

Stable root-package facade for query construction, scoring, and search.

#
Occur

Stable root-package facade for query construction, scoring, and search.

#
PersistenceError

Stable root-package facade for MoonSearch's foundational value types.

#
PhrasePrefixQuery

Stable root-package facade for query construction, scoring, and search.

#
PhraseQuery

Stable root-package facade for query construction, scoring, and search.

#
Posting

Stable root-package facade for immutable Segment construction and access.

#
PostingCursor

Stable root-package facade for immutable Segment construction and access.

#
PostingOccurrence

Stable root-package facade for immutable Segment construction and access.

#
PostingSkipBlock

Stable root-package facade for immutable Segment construction and access.

#
PrefixQuery

Stable root-package facade for query construction, scoring, and search.

#
Query

Stable root-package facade for query construction, scoring, and search.

#
QueryLiteralMode

Stable root-package facade for query construction, scoring, and search.

#
QueryParser

Stable root-package facade for query construction, scoring, and search.

#
QueryStringError

Stable root-package facade for query construction, scoring, and search.

#
QueryStringErrorKind

Stable root-package facade for query construction, scoring, and search.

#
QueryStringParser

Stable root-package facade for query construction, scoring, and search.

#
RangeFacet

Stable root-package facade for query construction, scoring, and search.

#
RangeFacetCount

Stable root-package facade for query construction, scoring, and search.

#
RangeQuery

Stable root-package facade for query construction, scoring, and search.

#
RawTokenizer

Stable root-package facade for text analysis.

#
RegexQuery

Stable root-package facade for query construction, scoring, and search.

#
RemoveLongFilter

Stable root-package facade for text analysis.

#
Schema

Stable root-package facade for schema construction and field options.

#
SchemaBuilder

Stable root-package facade for schema construction and field options.

#
ScoreFunction

Stable root-package facade for query construction, scoring, and search.

#
Scorer

Stable root-package facade for query construction, scoring, and search.

#
SearchHit

Stable root-package facade for query construction, scoring, and search.

#
SearchStatistics

Stable root-package facade for query construction, scoring, and search.

#
Searcher

Stable root-package facade for query construction, scoring, and search.

#
Segment

Stable root-package facade for immutable Segment construction and access.

#
SegmentSearchExecutor

Stable root-package facade for query construction, scoring, and search.

#
SegmentWriter

Stable root-package facade for immutable Segment construction and access.

#
SimpleTokenizer

Stable root-package facade for text analysis.

#
Sort

Stable root-package facade for query construction, scoring, and search.

#
SortField

Stable root-package facade for query construction, scoring, and search.

#
SortOrder

Stable root-package facade for query construction, scoring, and search.

#
StopWordFilter

Stable root-package facade for text analysis.

#
StoredDocument

Stable root-package facade for MoonSearch's foundational value types.

#
StoredFieldsReader

Stable root-package facade for immutable Segment construction and access.

#
SynonymGraphFilter

Stable root-package facade for text analysis.

#
SynonymRule

Stable root-package facade for text analysis.

#
TableChineseHmmModel

Stable root-package facade for optional dictionary-backed Chinese analysis.

#
Term

Stable root-package facade for MoonSearch's foundational value types.

#
TermDictionary

Stable root-package facade for immutable Segment construction and access.

#
TermQuery

Stable root-package facade for query construction, scoring, and search.

#
TermRangeQuery

Stable root-package facade for query construction, scoring, and search.

#
TermSetQuery

Stable root-package facade for query construction, scoring, and search.

#
TextAnalyzer

Stable root-package facade for text analysis.

#
TextOptions

Stable root-package facade for schema construction and field options.

#
Token

Stable root-package facade for text analysis.

#
TokenFilter

Stable root-package facade for text analysis.

#
TokenGraph

Stable root-package facade for text analysis.

#
TokenGraphPath

Stable root-package facade for text analysis.

#
TokenStream

Stable root-package facade for text analysis.

#
Tokenizer

Stable root-package facade for text analysis.

#
TokenizerManager

Stable root-package facade for text analysis.

#
TopDocsCollector

Stable root-package facade for query construction, scoring, and search.

#
TopKCollector

Stable root-package facade for query construction, scoring, and search.

#
UserQueryAst

Stable root-package facade for query construction, scoring, and search.

#
WandSearchResult

Stable root-package facade for query construction, scoring, and search.

#
Weight

Stable root-package facade for query construction, scoring, and search.

#
WhitespaceAnalyzer

Stable root-package facade for text analysis.

#
WhitespaceTokenizer

Stable root-package facade for text analysis.

#
WildcardQuery

Stable root-package facade for query construction, scoring, and search.

#
check_index

Validates the current manifest, every referenced Segment, tombstones, checksums, and cross-Segment Schema compatibility. Orphans and temporary files are reported without making the otherwise valid snapshot unreadable.

#
chinese_analyzer

Creates a lowercase Chinese analyzer around an injected dictionary.

#
chinese_dag_analyzer

Creates a lowercase Chinese analyzer using frequency-DAG routing.

#
chinese_dag_hmm_analyzer

Creates a lowercase Chinese DAG analyzer with injected HMM recognition.

#
chinese_dag_hmm_search_analyzer

Creates a Chinese DAG/HMM analyzer with search-mode subwords.

#
chinese_dag_hmm_search_index_analyzer

Creates a Chinese DAG/HMM search expansion for indexing.

#
chinese_dag_search_analyzer

Creates a Chinese DAG analyzer with search-mode subwords.

#
chinese_dag_search_index_analyzer

Creates a Chinese DAG search expansion for indexing.

#
chinese_search_analyzer

Creates a longest-match Chinese analyzer with search-mode subwords.

#
chinese_search_index_analyzer

Creates a longest-match Chinese search expansion for indexing.

#
english_stem_analyzer

Creates the English stemming pipeline exposed as the en_stem preset.

Source Files