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}