hermes_core/query/
traits.rs

1//! Query and Scorer traits with async support
2//!
3//! Provides the core abstractions for search queries and document scoring.
4
5use std::future::Future;
6use std::pin::Pin;
7
8use crate::segment::SegmentReader;
9use crate::{DocId, Result, Score};
10
11/// BM25 parameters
12#[derive(Debug, Clone, Copy)]
13pub struct Bm25Params {
14    /// Term frequency saturation parameter (typically 1.2-2.0)
15    pub k1: f32,
16    /// Length normalization parameter (typically 0.75)
17    pub b: f32,
18}
19
20impl Default for Bm25Params {
21    fn default() -> Self {
22        Self { k1: 1.2, b: 0.75 }
23    }
24}
25
26/// Future type for scorer creation
27#[cfg(not(target_arch = "wasm32"))]
28pub type ScorerFuture<'a> = Pin<Box<dyn Future<Output = Result<Box<dyn Scorer + 'a>>> + Send + 'a>>;
29#[cfg(target_arch = "wasm32")]
30pub type ScorerFuture<'a> = Pin<Box<dyn Future<Output = Result<Box<dyn Scorer + 'a>>> + 'a>>;
31
32/// Future type for count estimation
33#[cfg(not(target_arch = "wasm32"))]
34pub type CountFuture<'a> = Pin<Box<dyn Future<Output = Result<u32>> + Send + 'a>>;
35#[cfg(target_arch = "wasm32")]
36pub type CountFuture<'a> = Pin<Box<dyn Future<Output = Result<u32>> + 'a>>;
37
38/// Info for WAND-optimizable term queries
39#[derive(Debug, Clone)]
40pub struct TermQueryInfo {
41    /// Field being searched
42    pub field: crate::dsl::Field,
43    /// Term bytes (lowercase)
44    pub term: Vec<u8>,
45}
46
47/// A search query (async)
48#[cfg(not(target_arch = "wasm32"))]
49pub trait Query: Send + Sync {
50    /// Create a scorer for this query against a single segment (async)
51    ///
52    /// The `limit` parameter specifies the maximum number of results to return.
53    /// This is passed from the top-level search limit.
54    fn scorer<'a>(&'a self, reader: &'a SegmentReader, limit: usize) -> ScorerFuture<'a>;
55
56    /// Estimated number of matching documents in a segment (async)
57    fn count_estimate<'a>(&'a self, reader: &'a SegmentReader) -> CountFuture<'a>;
58
59    /// Return term info if this is a simple term query eligible for WAND optimization
60    ///
61    /// Returns None for complex queries (boolean, phrase, etc.)
62    fn as_term_query_info(&self) -> Option<TermQueryInfo> {
63        None
64    }
65}
66
67/// A search query (async) - WASM version without Send bounds
68#[cfg(target_arch = "wasm32")]
69pub trait Query {
70    /// Create a scorer for this query against a single segment (async)
71    ///
72    /// The `limit` parameter specifies the maximum number of results to return.
73    /// This is passed from the top-level search limit.
74    fn scorer<'a>(&'a self, reader: &'a SegmentReader, limit: usize) -> ScorerFuture<'a>;
75
76    /// Estimated number of matching documents in a segment (async)
77    fn count_estimate<'a>(&'a self, reader: &'a SegmentReader) -> CountFuture<'a>;
78
79    /// Return term info if this is a simple term query eligible for WAND optimization
80    fn as_term_query_info(&self) -> Option<TermQueryInfo> {
81        None
82    }
83}
84
85impl Query for Box<dyn Query> {
86    fn scorer<'a>(&'a self, reader: &'a SegmentReader, limit: usize) -> ScorerFuture<'a> {
87        (**self).scorer(reader, limit)
88    }
89
90    fn count_estimate<'a>(&'a self, reader: &'a SegmentReader) -> CountFuture<'a> {
91        (**self).count_estimate(reader)
92    }
93
94    fn as_term_query_info(&self) -> Option<TermQueryInfo> {
95        (**self).as_term_query_info()
96    }
97}
98
99/// Scorer that iterates over matching documents and computes scores
100#[cfg(not(target_arch = "wasm32"))]
101pub trait Scorer: Send {
102    /// Current document ID, or TERMINATED if exhausted
103    fn doc(&self) -> DocId;
104
105    /// Score for current document
106    fn score(&self) -> Score;
107
108    /// Advance to next document
109    fn advance(&mut self) -> DocId;
110
111    /// Seek to first doc >= target
112    fn seek(&mut self, target: DocId) -> DocId;
113
114    /// Size hint for remaining documents
115    fn size_hint(&self) -> u32;
116}
117
118/// Scorer that iterates over matching documents and computes scores (WASM version)
119#[cfg(target_arch = "wasm32")]
120pub trait Scorer {
121    /// Current document ID, or TERMINATED if exhausted
122    fn doc(&self) -> DocId;
123
124    /// Score for current document
125    fn score(&self) -> Score;
126
127    /// Advance to next document
128    fn advance(&mut self) -> DocId;
129
130    /// Seek to first doc >= target
131    fn seek(&mut self, target: DocId) -> DocId;
132
133    /// Size hint for remaining documents
134    fn size_hint(&self) -> u32;
135}
136
137/// Empty scorer for terms that don't exist
138pub struct EmptyScorer;
139
140impl Scorer for EmptyScorer {
141    fn doc(&self) -> DocId {
142        crate::structures::TERMINATED
143    }
144
145    fn score(&self) -> Score {
146        0.0
147    }
148
149    fn advance(&mut self) -> DocId {
150        crate::structures::TERMINATED
151    }
152
153    fn seek(&mut self, _target: DocId) -> DocId {
154        crate::structures::TERMINATED
155    }
156
157    fn size_hint(&self) -> u32 {
158        0
159    }
160}