use crate::core::{DocId, FieldId, NO_MORE_DOCS, Result, Scorer, TwoPhaseIterator};
use crate::query::ScorerSupplier;
use crate::query::term::FilterScorer;
use crate::search::buffered_union::BufferedUnionScorer;
use crate::segment::reader::SegmentReader;
pub(crate) struct ConstantScoreMultiTermSupplier {
field_id: FieldId,
terms: Vec<(String, u32)>,
cost: u64,
segment_data: *const SegmentReader,
}
unsafe impl Send for ConstantScoreMultiTermSupplier {}
impl ConstantScoreMultiTermSupplier {
pub(crate) fn new(
reader: &SegmentReader,
field_id: FieldId,
terms: Vec<(String, u32)>,
) -> Self {
let cost: u64 = terms.iter().map(|(_, df)| *df as u64).sum();
Self {
field_id,
terms,
cost,
segment_data: reader as *const SegmentReader,
}
}
}
impl ScorerSupplier for ConstantScoreMultiTermSupplier {
fn cost(&self) -> u64 {
self.cost
}
fn scorer(self: Box<Self>) -> Result<Box<dyn Scorer>> {
let reader = unsafe { &*self.segment_data };
let mut scorers: Vec<Box<dyn Scorer>> = Vec::with_capacity(self.terms.len());
for (term, _) in &self.terms {
if let Some(postings) = reader.postings(self.field_id, term) {
scorers.push(Box::new(FilterScorer::new(postings)));
}
}
if scorers.is_empty() {
return Ok(Box::new(EmptyScorer));
}
if scorers.len() == 1 {
return Ok(scorers.pop().unwrap());
}
Ok(Box::new(BufferedUnionScorer::new(scorers)))
}
}
pub(crate) struct EmptyScorer;
impl Scorer for EmptyScorer {
fn doc_id(&self) -> DocId {
NO_MORE_DOCS
}
fn next(&mut self) -> DocId {
NO_MORE_DOCS
}
fn advance(&mut self, _: DocId) -> DocId {
NO_MORE_DOCS
}
fn score(&mut self) -> f32 {
0.0
}
fn two_phase(&mut self) -> Option<&mut dyn TwoPhaseIterator> {
None
}
}