1use crate::core::{DocId, FieldId, NO_MORE_DOCS, Result, ScoreMode, Scorer, TwoPhaseIterator};
8
9use crate::query::{BoundQuery, Query, ScorerSupplier};
10use crate::search::searcher::Searcher;
11use crate::segment::reader::SegmentReader;
12
13pub struct ExistsQuery {
14 pub field: String,
15}
16
17impl Query for ExistsQuery {
18 fn bind(&self, _searcher: &Searcher, _score_mode: ScoreMode) -> Result<Box<dyn BoundQuery>> {
19 Ok(Box::new(BoundExistsQuery {
20 field: self.field.clone(),
21 }))
22 }
23}
24
25struct BoundExistsQuery {
26 field: String,
27}
28
29impl BoundQuery for BoundExistsQuery {
30 fn scorer_supplier(&self, reader: &SegmentReader) -> Result<Option<Box<dyn ScorerSupplier>>> {
31 let field_id = match reader
32 .header()
33 .fields
34 .iter()
35 .find(|f| f.field_name == self.field)
36 .map(|f| f.field_id)
37 {
38 Some(id) => id,
39 None => return Ok(None),
40 };
41
42 if reader.norms(field_id).is_none() {
44 return Ok(None);
45 }
46
47 Ok(Some(Box::new(ExistsScorerSupplier {
48 field_id,
49 doc_count: reader.doc_count(),
50 segment_data: reader as *const SegmentReader,
51 })))
52 }
53}
54
55struct ExistsScorerSupplier {
56 field_id: FieldId,
57 doc_count: u32,
58 segment_data: *const SegmentReader,
59}
60
61unsafe impl Send for ExistsScorerSupplier {}
62
63impl ScorerSupplier for ExistsScorerSupplier {
64 fn cost(&self) -> u64 {
65 self.doc_count as u64
66 }
67
68 fn scorer(self: Box<Self>) -> Result<Box<dyn Scorer>> {
69 let reader = unsafe { &*self.segment_data };
70 let norms = reader.norms(self.field_id).unwrap();
71 Ok(Box::new(ExistsScorer {
72 doc_count: self.doc_count,
73 current: 0,
74 norms_fn: Box::new(move |doc_id: DocId| norms.norm(doc_id) > 0.0),
75 }))
76 }
77}
78
79struct ExistsScorer {
80 doc_count: u32,
81 current: u32,
82 norms_fn: Box<dyn Fn(DocId) -> bool + Send>,
83}
84
85impl ExistsScorer {
86 fn advance_to_existing(&mut self) {
87 while self.current < self.doc_count {
88 if (self.norms_fn)(DocId::new(self.current)) {
89 return;
90 }
91 self.current += 1;
92 }
93 }
94}
95
96impl Scorer for ExistsScorer {
97 fn doc_id(&self) -> DocId {
98 if self.current < self.doc_count {
99 DocId::new(self.current)
100 } else {
101 NO_MORE_DOCS
102 }
103 }
104
105 fn next(&mut self) -> DocId {
106 self.current += 1;
107 self.advance_to_existing();
108 self.doc_id()
109 }
110
111 fn advance(&mut self, target: DocId) -> DocId {
112 self.current = target.as_u32();
113 self.advance_to_existing();
114 self.doc_id()
115 }
116
117 fn score(&mut self) -> f32 {
118 1.0
119 }
120 fn two_phase(&mut self) -> Option<&mut dyn TwoPhaseIterator> {
121 None
122 }
123}