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.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.
Raw segments can be encoded from a slice, document iterator, or sorted document
iterator into a Vec<u8> or a caller-provided Write sink. 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.
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.
Use top_k_weighted_u32_files_with_stats when you need searched/pruned segment
counts for profiling.
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.
Development
License
MIT OR Apache-2.0