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/// A search query (async)
39#[cfg(not(target_arch = "wasm32"))]
40pub trait Query: Send + Sync {
41    /// Create a scorer for this query against a single segment (async)
42    fn scorer<'a>(&'a self, reader: &'a SegmentReader) -> ScorerFuture<'a>;
43
44    /// Estimated number of matching documents in a segment (async)
45    fn count_estimate<'a>(&'a self, reader: &'a SegmentReader) -> CountFuture<'a>;
46}
47
48/// A search query (async) - WASM version without Send bounds
49#[cfg(target_arch = "wasm32")]
50pub trait Query {
51    /// Create a scorer for this query against a single segment (async)
52    fn scorer<'a>(&'a self, reader: &'a SegmentReader) -> ScorerFuture<'a>;
53
54    /// Estimated number of matching documents in a segment (async)
55    fn count_estimate<'a>(&'a self, reader: &'a SegmentReader) -> CountFuture<'a>;
56}
57
58impl Query for Box<dyn Query> {
59    fn scorer<'a>(&'a self, reader: &'a SegmentReader) -> ScorerFuture<'a> {
60        (**self).scorer(reader)
61    }
62
63    fn count_estimate<'a>(&'a self, reader: &'a SegmentReader) -> CountFuture<'a> {
64        (**self).count_estimate(reader)
65    }
66}
67
68/// Scorer that iterates over matching documents and computes scores
69#[cfg(not(target_arch = "wasm32"))]
70pub trait Scorer: Send {
71    /// Current document ID, or TERMINATED if exhausted
72    fn doc(&self) -> DocId;
73
74    /// Score for current document
75    fn score(&self) -> Score;
76
77    /// Advance to next document
78    fn advance(&mut self) -> DocId;
79
80    /// Seek to first doc >= target
81    fn seek(&mut self, target: DocId) -> DocId;
82
83    /// Size hint for remaining documents
84    fn size_hint(&self) -> u32;
85}
86
87/// Scorer that iterates over matching documents and computes scores (WASM version)
88#[cfg(target_arch = "wasm32")]
89pub trait Scorer {
90    /// Current document ID, or TERMINATED if exhausted
91    fn doc(&self) -> DocId;
92
93    /// Score for current document
94    fn score(&self) -> Score;
95
96    /// Advance to next document
97    fn advance(&mut self) -> DocId;
98
99    /// Seek to first doc >= target
100    fn seek(&mut self, target: DocId) -> DocId;
101
102    /// Size hint for remaining documents
103    fn size_hint(&self) -> u32;
104}
105
106/// Empty scorer for terms that don't exist
107pub struct EmptyScorer;
108
109impl Scorer for EmptyScorer {
110    fn doc(&self) -> DocId {
111        crate::structures::TERMINATED
112    }
113
114    fn score(&self) -> Score {
115        0.0
116    }
117
118    fn advance(&mut self) -> DocId {
119        crate::structures::TERMINATED
120    }
121
122    fn seek(&mut self, _target: DocId) -> DocId {
123        crate::structures::TERMINATED
124    }
125
126    fn size_hint(&self) -> u32 {
127        0
128    }
129}