Expand description
Sparse n-gram extraction from byte slices.
Sparse grams are a way of selecting variable-length n-grams (longer than 2 bytes) without extracting all possible n-grams. The algorithm is deterministic: the same extraction logic works for every substring, so that substring searches are supported.
§How it works
Each consecutive byte pair (bigram) is assigned a priority based on how frequently it occurs
in a large code corpus (see bigram_priority). A monotone deque tracks potential n-gram
boundaries: an n-gram boundary occurs wherever a bigram has lower priority than the bigrams
between it and the previous boundary.
A substring of length 3..=MAX_SPARSE_GRAM_SIZE is emitted as a sparse n-gram when both its
left and right boundary bigrams have a priority strictly below every interior bigram. All
bigrams are always emitted.
For a document of N bytes, this produces at most 3(N-1) n-grams: all bigrams plus algorithmically
selected longer n-grams (up to MAX_SPARSE_GRAM_SIZE bytes).
§Normalization
The bigram priority model only scores ASCII byte pairs; any byte with the high bit set resolves
to priority 0. Callers building a case-insensitive index should normalize input first (fold
uppercase to lowercase, map multi-byte UTF-8 to high-bit-set bytes) before extraction.
§Example
use sparse_ngrams::{NGram, collect_sparse_grams, MAX_SPARSE_GRAM_SIZE};
let input = b"hello world";
let grams = collect_sparse_grams(input);
assert!(grams.len() > input.len() - 1);
for gram in &grams {
assert!(gram.len() >= 2);
assert!(gram.len() <= MAX_SPARSE_GRAM_SIZE);
}Structs§
- NGram
- A compact n-gram identifier. See the module-level documentation for the bit layout.
- Query
Grams - Streaming query n-gram state.
Constants§
- MAX_
SPARSE_ GRAM_ SIZE - Maximum length (in bytes) of a sparse n-gram.
Functions§
- bigram_
priority - Reconstructs the frequency-ranking priority of the ascii bigram
(a, b). Absent or non-ascii bigrams resolve to0; present bigrams get a strictly positive, unique priority where a higher value means a more frequent bigram. This priority is used to split strings into smaller n-grams. - collect_
sparse_ grams - Collect all sparse n-grams from the input byte slice into a new
Vec. - collect_
sparse_ grams_ deque - Monotone-deque extraction, with the deque held in fixed ring buffers. Calls
emitonce for every sparse n-gram, in emission order (all bigrams, plus algorithmically selected longer grams), as(gram, idx)whereidxis the position of the character just aftergramincontent.emitdecides what to do with each gram — push it into aVec, write it into a pre-sized slice, feed it straight into an index, etc. — so no output buffer needs to be sized or allocated up front. - collect_
sparse_ grams_ scan - Queue-free scan-based extraction. Calls
emitonce for every sparse n-gram, in the same order ascollect_sparse_grams_deque, as(gram, idx)whereidxis the position of the character just aftergramincontent. - index_
fold_ char - Re-export of the index-folding used internally by
QueryGrams::append_char, so callers that buffer already-folded bytes (and feed them viaQueryGrams::append_byte) fold identically. Folds a singlecharto its one-byteindex_foldrepresentation. - max_
sparse_ grams - Returns the maximum number of sparse n-grams that can be produced from
content_lenbytes of input. Use this to reserve capacity for the output (e.g. aVecthe emit closure pushes into, or a pre-sized slice it writes).