postings 0.2.0

Inverted-index postings lists with segment-style updates. Supports u32 TF (classical) and f32 weights (SPLADE/learned sparse).
Documentation

postings

crates.io Documentation CI

Inverted-index postings lists with segment-style updates. Supports u32 term frequencies (classical IR) and f32 weights (SPLADE / learned-sparse retrieval).

Data Model & Invariants

  • Doc IDs: u32. Must be dense/contiguous for optimal compression.
  • Ordering: Postings lists are always sorted by Doc ID.
  • Updates: Segment-based. Deletions are tombstones; updates are delete+add.
  • Storage: In-memory by default. Persistence via durability (optional).

Usage

[dependencies]
postings = "0.2"

Example (index + candidates):

use postings::{PostingsIndex, PlannerConfig};

let mut idx = PostingsIndex::new();
idx.add_document(0, &["the".to_string(), "quick".to_string(), "fox".to_string()])
    .unwrap();
idx.add_document(1, &["quick".to_string(), "brown".to_string(), "dog".to_string()])
    .unwrap();

// Conjunctive (AND) candidates.
assert_eq!(
    idx.candidates_all_terms(&["quick".to_string(), "dog".to_string()]),
    vec![1]
);

let cfg = PlannerConfig::default();
let plan = idx.plan_candidates(&["quick".to_string()], cfg);
assert!(matches!(plan, postings::CandidatePlan::Candidates(_)));

Example (learned-sparse top-k):

use postings::PostingsIndex;

let mut idx: PostingsIndex<String, f32> = PostingsIndex::new();
idx.add_weighted_document(
    0,
    &[
        ("neural".to_string(), 1.8),
        ("retrieval".to_string(), 0.4),
    ],
)
.unwrap();
idx.add_weighted_document(
    1,
    &[
        ("retrieval".to_string(), 2.6),
        ("search".to_string(), 2.2),
    ],
)
.unwrap();

let ranking = idx.top_k_weighted(&[("neural", 1.5), ("retrieval", 2.0)], 10);
assert_eq!(ranking[0].0, 1);

Examples

Runnable examples live in examples/:

  • durable_roundtrip pairs postings with durability to 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.

Features

  • postings/serde: enable serde for the in-memory structures.
  • postings/persistence: enable save/load helpers via durability + postcard.
  • postings/sbits: enable succinct monotone sequences (Elias–Fano) under postings::codec::ef.
  • postings/positional: enable positional postings (postings::positional::PosingsIndex).
  • postings/cnk-compression: enable optional compressed-candidate helpers under postings::positional::cnk_candidates.
  • postings/raw-segment: enable the experimental byte- and file-backed raw segment reader.

Optional: positional postings

Enable positional postings behind a feature flag:

[dependencies]
postings = { version = "0.2", features = ["positional"] }

Then use postings::positional::PosingsIndex for phrase/proximity evaluation.

Development

cargo test