lb_tantivy/query/
const_score_query.rs1use std::fmt;
2
3use crate::docset::COLLECT_BLOCK_BUFFER_LEN;
4use crate::query::{EnableScoring, Explanation, Query, Scorer, Weight};
5use crate::{DocId, DocSet, Score, SegmentReader, TantivyError, Term};
6
7pub struct ConstScoreQuery {
13 query: Box<dyn Query>,
14 score: Score,
15}
16
17impl ConstScoreQuery {
18 pub fn new(query: Box<dyn Query>, score: Score) -> ConstScoreQuery {
20 ConstScoreQuery { query, score }
21 }
22}
23
24impl Clone for ConstScoreQuery {
25 fn clone(&self) -> Self {
26 ConstScoreQuery {
27 query: self.query.box_clone(),
28 score: self.score,
29 }
30 }
31}
32
33impl fmt::Debug for ConstScoreQuery {
34 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
35 write!(f, "Const(score={}, query={:?})", self.score, self.query)
36 }
37}
38
39impl Query for ConstScoreQuery {
40 fn weight(&self, enable_scoring: EnableScoring<'_>) -> crate::Result<Box<dyn Weight>> {
41 let inner_weight = self.query.weight(enable_scoring)?;
42 Ok(if enable_scoring.is_scoring_enabled() {
43 Box::new(ConstWeight::new(inner_weight, self.score))
44 } else {
45 inner_weight
46 })
47 }
48
49 fn query_terms<'a>(&'a self, visitor: &mut dyn FnMut(&'a Term, bool)) {
50 self.query.query_terms(visitor);
51 }
52}
53
54struct ConstWeight {
55 weight: Box<dyn Weight>,
56 score: Score,
57}
58
59impl ConstWeight {
60 pub fn new(weight: Box<dyn Weight>, score: Score) -> Self {
61 ConstWeight { weight, score }
62 }
63}
64
65impl Weight for ConstWeight {
66 fn scorer(&self, reader: &SegmentReader, boost: Score) -> crate::Result<Box<dyn Scorer>> {
67 let inner_scorer = self.weight.scorer(reader, boost)?;
68 Ok(Box::new(ConstScorer::new(inner_scorer, boost * self.score)))
69 }
70
71 fn explain(&self, reader: &SegmentReader, doc: u32) -> crate::Result<Explanation> {
72 let mut scorer = self.scorer(reader, 1.0)?;
73 if scorer.seek(doc) != doc {
74 return Err(TantivyError::InvalidArgument(format!(
75 "Document #({doc}) does not match"
76 )));
77 }
78 let mut explanation = Explanation::new("Const", self.score);
79 let underlying_explanation = self.weight.explain(reader, doc)?;
80 explanation.add_detail(underlying_explanation);
81 Ok(explanation)
82 }
83
84 fn count(&self, reader: &SegmentReader) -> crate::Result<u32> {
85 self.weight.count(reader)
86 }
87}
88
89pub struct ConstScorer<TDocSet: DocSet> {
96 docset: TDocSet,
97 score: Score,
98}
99
100impl<TDocSet: DocSet> ConstScorer<TDocSet> {
101 pub fn new(docset: TDocSet, score: Score) -> ConstScorer<TDocSet> {
103 ConstScorer { docset, score }
104 }
105}
106
107impl<TDocSet: DocSet> From<TDocSet> for ConstScorer<TDocSet> {
108 fn from(docset: TDocSet) -> Self {
109 ConstScorer::new(docset, 1.0)
110 }
111}
112
113impl<TDocSet: DocSet> DocSet for ConstScorer<TDocSet> {
114 fn advance(&mut self) -> DocId {
115 self.docset.advance()
116 }
117
118 fn seek(&mut self, target: DocId) -> DocId {
119 self.docset.seek(target)
120 }
121
122 fn fill_buffer(&mut self, buffer: &mut [DocId; COLLECT_BLOCK_BUFFER_LEN]) -> usize {
123 self.docset.fill_buffer(buffer)
124 }
125
126 fn doc(&self) -> DocId {
127 self.docset.doc()
128 }
129
130 fn size_hint(&self) -> u32 {
131 self.docset.size_hint()
132 }
133}
134
135impl<TDocSet: DocSet + 'static> Scorer for ConstScorer<TDocSet> {
136 fn score(&mut self) -> Score {
137 self.score
138 }
139}
140
141#[cfg(test)]
142mod tests {
143 use super::ConstScoreQuery;
144 use crate::query::{AllQuery, Query};
145 use crate::schema::Schema;
146 use crate::{DocAddress, Index, IndexWriter, TantivyDocument};
147
148 #[test]
149 fn test_const_score_query_explain() -> crate::Result<()> {
150 let schema = Schema::builder().build();
151 let index = Index::create_in_ram(schema);
152 let mut index_writer: IndexWriter = index.writer_for_tests()?;
153 index_writer.add_document(TantivyDocument::new())?;
154 index_writer.commit()?;
155 let reader = index.reader()?;
156 let searcher = reader.searcher();
157 let query = ConstScoreQuery::new(Box::new(AllQuery), 0.42);
158 let explanation = query.explain(&searcher, DocAddress::new(0, 0u32)).unwrap();
159 assert_eq!(
160 explanation.to_pretty_json(),
161 r#"{
162 "value": 0.42,
163 "description": "Const",
164 "details": [
165 {
166 "value": 1.0,
167 "description": "AllQuery"
168 }
169 ]
170}"#
171 );
172 Ok(())
173 }
174}