postings
Inverted-index postings lists and codecs.
Supports u32 term frequencies for classical IR and f32 weights for learned
sparse retrieval.
Data Model & Invariants
- Doc IDs:
u32. Sparse ids are supported; smaller gaps compress better and dense ids keep dense scratch paths cheap. - Ordering: Postings lists are always sorted by Doc ID.
- Updates:
PostingsIndexsupports in-memory add/delete. Raw file segments are immutable; a store or application manifest owns deletes and compaction. - Storage: In-memory by default; optional persistence and raw file-backed segment readers.
Usage
[]
= "0.2"
Example (index + candidates):
use ;
let mut idx = new;
idx.add_document
.unwrap;
idx.add_document
.unwrap;
// Conjunctive (AND) candidates.
assert_eq!;
let cfg = default;
let plan = idx.plan_candidates;
assert!;
Example (learned-sparse top-k):
use PostingsIndex;
let mut idx: = new;
idx.add_weighted_document
.unwrap;
idx.add_weighted_document
.unwrap;
let ranking = idx.top_k_weighted;
assert_eq!;
Examples
Runnable examples live in examples/:
durable_roundtrippairspostingswithdurabilityto build a crash-recoverable inverted index: update events go to a record log, snapshots to a checkpoint, and the index rebuilds from both, the persistence pattern a search engine needs to survive restarts.raw_segment_filewrites immutable raw impact files and queries them with file-backed top-k search. Run with--features raw-segment.splade_weightedscores a small learned-sparse collection withf32weights and verifies top-k sparse inner-product search.
File-backed segments
The raw-segment feature exposes postings::raw, a numeric-term segment format
with a byte-backed reader and a file-backed reader. The file reader keeps the
fixed directories in memory and range-reads posting payloads for the query terms.
New raw files carry directory and posting-block checksums; legacy unchecked raw
files remain readable.
It is the path intended for large lexical and learned-sparse indexes whose
posting payloads should not be rebuilt into a full PostingsIndex on every
open.
RawSegmentFile::resident_metadata_len and
RawSegmentFile::posting_payload_len report that split for callers that enforce
per-generation or per-query memory budgets.
RawSegment::for_each_term_id and RawSegmentFile::for_each_term_id stream the
term directory when callers need generation-level statistics without allocating
a full term-id list.
RawSegment::for_each_term_meta and RawSegmentFile::for_each_term_meta also
stream document frequency, maximum weight, and total weight from the same
directory pass.
Raw segments can be encoded from a slice, document iterator, sorted document
iterator, or term-major posting lists into a Vec<u8>, caller-provided Write
sink, or seekable writer. The writer API avoids requiring the final segment as
one contiguous allocation when the caller wants to stream bytes into its own
durability layer. When document ids are already strictly increasing, the
sorted-iterator writer also avoids the encoder's whole-corpus document map
before postings are written. When an external sorter or merge already has
term-major lists, the term-major writer avoids doc-to-term transposition too;
the seekable term-major writer also avoids a second payload pass for local-file
style sinks.
RawSegmentFile::top_k_weighted_u32 scores one raw file by sparse inner product;
top_k_weighted_u32_files merges exact top-k results across raw files when
document ids are globally unique. The file-backed scorer uses block metadata for
bounded reads and safe top-k pruning where the query weights make that possible.
top_k_weighted_u32_files_and_index fuses sealed files with one live
PostingsIndex<u64, u32> shard and uses the live shard's current top-k
threshold to skip low-bound sealed files.
Use top_k_weighted_u32_files_with_stats when you need searched/pruned segment
counts for profiling. Segment pruning is layout-sensitive, so measure it against
representative segment construction before treating it as a storage win.
Use lexir::raw for BM25 over one or more raw files.
This is not a full index lifecycle by itself: callers still own term-id mapping,
commit publication, deletes, compaction, and crash-safety policy. Pair raw files
with durability, segstore sidecars, or an application manifest when those
guarantees are needed.
Features
serde: enable serde for the in-memory structures.persistence: enable save/load helpers viadurability+postcard.sbits: enable succinct monotone sequences (Elias-Fano) underpostings::codec::ef.positional: enable positional postings (postings::positional::PositionalIndex).cnk-compression: enable optional compressed-candidate helpers underpostings::positional::cnk_candidates.raw-segment: enable the experimental checked byte- and file-backed raw segment reader.
Optional: positional postings
Enable positional postings behind a feature flag:
[]
= { = "0.2", = ["positional"] }
Then use postings::positional::PositionalIndex for phrase/proximity
evaluation. phrase_match_strs and near_match_terms_strs accept borrowed
query terms when a parser already holds &strs. PosingsIndex remains as the
historical name from the older posings crate.
cnk-compression is a helper for sorted candidate doc-id sets produced by
positional workflows. It is not a storage backend, postings codec, or lifecycle
layer.
Development
License
MIT OR Apache-2.0