use crate::core::{DocId, FieldId, NO_MORE_DOCS, Result, ScoreMode, Scorer, TwoPhaseIterator};
use crate::query::{BoundQuery, Query, ScorerSupplier};
use crate::search::searcher::Searcher;
use crate::segment::reader::SegmentReader;
pub struct ExistsQuery {
pub field: String,
}
impl Query for ExistsQuery {
fn bind(&self, _searcher: &Searcher, _score_mode: ScoreMode) -> Result<Box<dyn BoundQuery>> {
Ok(Box::new(BoundExistsQuery {
field: self.field.clone(),
}))
}
}
struct BoundExistsQuery {
field: String,
}
impl BoundQuery for BoundExistsQuery {
fn scorer_supplier(&self, reader: &SegmentReader) -> Result<Option<Box<dyn ScorerSupplier>>> {
let field_id = match reader
.header()
.fields
.iter()
.find(|f| f.field_name == self.field)
.map(|f| f.field_id)
{
Some(id) => id,
None => return Ok(None),
};
if reader.norms(field_id).is_none() {
return Ok(None);
}
Ok(Some(Box::new(ExistsScorerSupplier {
field_id,
doc_count: reader.doc_count(),
segment_data: reader as *const SegmentReader,
})))
}
}
struct ExistsScorerSupplier {
field_id: FieldId,
doc_count: u32,
segment_data: *const SegmentReader,
}
unsafe impl Send for ExistsScorerSupplier {}
impl ScorerSupplier for ExistsScorerSupplier {
fn cost(&self) -> u64 {
self.doc_count as u64
}
fn scorer(self: Box<Self>) -> Result<Box<dyn Scorer>> {
let reader = unsafe { &*self.segment_data };
let norms = reader.norms(self.field_id).unwrap();
Ok(Box::new(ExistsScorer {
doc_count: self.doc_count,
current: 0,
norms_fn: Box::new(move |doc_id: DocId| norms.norm(doc_id) > 0.0),
}))
}
}
struct ExistsScorer {
doc_count: u32,
current: u32,
norms_fn: Box<dyn Fn(DocId) -> bool + Send>,
}
impl ExistsScorer {
fn advance_to_existing(&mut self) {
while self.current < self.doc_count {
if (self.norms_fn)(DocId::new(self.current)) {
return;
}
self.current += 1;
}
}
}
impl Scorer for ExistsScorer {
fn doc_id(&self) -> DocId {
if self.current < self.doc_count {
DocId::new(self.current)
} else {
NO_MORE_DOCS
}
}
fn next(&mut self) -> DocId {
self.current += 1;
self.advance_to_existing();
self.doc_id()
}
fn advance(&mut self, target: DocId) -> DocId {
self.current = target.as_u32();
self.advance_to_existing();
self.doc_id()
}
fn score(&mut self) -> f32 {
1.0
}
fn two_phase(&mut self) -> Option<&mut dyn TwoPhaseIterator> {
None
}
}