Skip to main content

kevy_text/
segment_opts.rs

1//! What a query asks for, beyond its text and result limit — the clause
2//! options and the shapes they answer in. A child module of `segment`
3//! (declared via `#[path]`), re-exported from it, so the crate's public
4//! surface is unchanged by the split.
5
6use super::{CorpusStats, Filter, TextMatch};
7
8/// An order to select the top hits by, other than the score.
9///
10/// The key function maps a stored value's raw bytes to an
11/// order-preserving encoding, computed once per candidate; the segment
12/// then compares bytes and never learns what a number is. `None` from it
13/// means the document has no usable value for the field, which sorts
14/// **last in both directions** — missing is not a value, and placing it
15/// at one end or the other by direction would make "the oldest" and "the
16/// newest" disagree about where the unknowns went.
17#[derive(Clone, Copy)]
18pub struct Sort<'a> {
19    /// Which declared value field orders the result.
20    pub field: usize,
21    /// Descending when true.
22    pub desc: bool,
23    /// The order-preserving encoding of one stored value.
24    pub key: &'a dyn Fn(&[u8]) -> Option<Vec<u8>>,
25}
26
27/// Collapse the page so only the best document per value of a stored
28/// field appears.
29///
30/// The key is the value's *identity*, coerced — so `1` and `1.0` in a
31/// field declared `f64` are one value rather than two. A document with no
32/// value for the field is its own group: `DISTINCT` removes documents
33/// shown to share a value, and one that has none has not been shown to
34/// share anything.
35#[derive(Clone, Copy)]
36pub struct Distinct<'a> {
37    /// Which declared value field identifies a group.
38    pub field: usize,
39    /// The identity of one stored value.
40    pub key: &'a dyn Fn(&[u8]) -> Option<Vec<u8>>,
41}
42
43/// Count the values of a stored field over the whole match set.
44///
45/// Buckets are keyed by the value's *identity* — the same coerced key
46/// `DISTINCT` groups by, so `1` and `1.0` in a field declared `f64` are
47/// one bucket — while the reported label is a spelling that really occurs
48/// in the corpus rather than a re-serialisation.
49#[derive(Clone, Copy)]
50pub struct Facet<'a> {
51    /// Which declared value field to count.
52    pub field: usize,
53    /// The identity of one stored value.
54    pub key: &'a dyn Fn(&[u8]) -> Option<Vec<u8>>,
55}
56
57/// One value bucket: the identity a cross-shard merge sums by, a spelling
58/// of it that occurs in the corpus, and how many documents matched with
59/// it.
60pub type Bucket = (Vec<u8>, Vec<u8>, u64);
61
62/// One faceted query's answer: the page, and a count per value for each
63/// requested field.
64pub struct FacetedMatches {
65    /// The ranked page, exactly what an unfaceted query would return.
66    pub hits: Vec<TextMatch>,
67    /// Per requested facet field, `(identity, label, count)` over the
68    /// whole match set. The identity is what a cross-shard merge sums by;
69    /// the label is what it reports.
70    pub facets: Vec<Vec<Bucket>>,
71}
72
73/// Everything a MATCH query carries beyond its text and result limit.
74///
75/// Grouping them keeps the query entry point from growing a parameter per
76/// clause, and gives every clause one place to be defaulted from
77/// ([`QueryOpts::default`] is the plain, exact, unscoped query).
78#[derive(Clone, Copy, Default)]
79pub struct QueryOpts<'a> {
80    /// Corpus-wide BM25 statistics — the second pass of a cross-shard
81    /// query. `None` scores against this segment's own slice.
82    pub stats: Option<&'a CorpusStats>,
83    /// Edit distance allowed on bare terms (`TYPO n`); 0 = exact.
84    pub typo: u32,
85    /// Field positions the query is restricted to (`IN <field…>`); empty
86    /// = every field.
87    pub fields: &'a [usize],
88    /// `FILTER`: non-scoring predicates, ANDed. Applied before the top-K
89    /// — filtering afterwards would return fewer hits than exist.
90    pub filter: &'a [Filter<'a>],
91    /// `SORT`: select by a stored value instead of by score. Selecting,
92    /// not re-ordering: a document that wins on the sort key must be
93    /// chosen even when its score would never have reached the page.
94    pub sort: Option<Sort<'a>>,
95    /// `DISTINCT`: at most one hit per value of a stored field. Applied
96    /// during selection, so the page is filled with `limit` DISTINCT
97    /// documents rather than `limit` documents that then collapse.
98    pub distinct: Option<Distinct<'a>>,
99}