use std::any::Any;
use std::sync::{Arc, RwLock};
use roaring::RoaringTreemap;
use crate::error::Result;
use crate::lexical::core::document::Document;
use crate::lexical::index::inverted::reader::SegmentReader;
use crate::lexical::index::structures::bkd_tree::BKDTree;
use crate::lexical::query::Query;
use crate::lexical::reader::{FieldStats, LexicalIndexReader, PostingIterator, ReaderTermInfo};
type GlobalTermInfoFn = dyn Fn(&str, &str) -> Result<Option<ReaderTermInfo>> + Send + Sync;
type GlobalMatchingDocIdsFn = dyn Fn(&dyn Query) -> Result<Arc<RoaringTreemap>> + Send + Sync;
pub(crate) struct PerSegmentReaderView {
segment: Arc<RwLock<SegmentReader>>,
global_doc_count: u64,
global_max_doc: u64,
global_term_info_fn: Arc<GlobalTermInfoFn>,
global_matching_doc_ids_fn: Arc<GlobalMatchingDocIdsFn>,
}
impl PerSegmentReaderView {
pub fn new(
segment: Arc<RwLock<SegmentReader>>,
global_doc_count: u64,
global_max_doc: u64,
global_term_info_fn: Arc<GlobalTermInfoFn>,
global_matching_doc_ids_fn: Arc<GlobalMatchingDocIdsFn>,
) -> Self {
PerSegmentReaderView {
segment,
global_doc_count,
global_max_doc,
global_term_info_fn,
global_matching_doc_ids_fn,
}
}
pub fn matching_doc_ids(&self, query: &dyn Query) -> Result<Arc<RoaringTreemap>> {
(self.global_matching_doc_ids_fn)(query)
}
pub fn field_length(&self, doc_id: u64, field: &str) -> Result<Option<u32>> {
let seg = self.segment.read().unwrap();
seg.field_length(doc_id, field)
}
}
impl std::fmt::Debug for PerSegmentReaderView {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("PerSegmentReaderView")
.field("global_doc_count", &self.global_doc_count)
.field("global_max_doc", &self.global_max_doc)
.finish_non_exhaustive()
}
}
impl LexicalIndexReader for PerSegmentReaderView {
fn doc_count(&self) -> u64 {
self.global_doc_count
}
fn max_doc(&self) -> u64 {
self.global_max_doc
}
fn is_deleted(&self, doc_id: u64) -> bool {
let seg = self.segment.read().unwrap();
seg.is_deleted(doc_id).unwrap_or(false)
}
fn document(&self, doc_id: u64) -> Result<Option<Document>> {
let seg = self.segment.read().unwrap();
seg.document(doc_id)
}
fn term_info(&self, field: &str, term: &str) -> Result<Option<ReaderTermInfo>> {
let local_opt = {
let seg = self.segment.read().unwrap();
seg.term_info(field, term)?
};
let local = match local_opt {
Some(li) => li,
None => return Ok(None),
};
let global = (self.global_term_info_fn)(field, term)?;
let global = match global {
Some(gi) => gi,
None => {
return Ok(Some(ReaderTermInfo {
field: field.to_string(),
term: term.to_string(),
doc_freq: local.doc_frequency,
total_freq: local.total_frequency,
posting_offset: local.posting_offset,
posting_size: local.posting_length,
max_score_factor: local.max_score_factor,
block_max: local.block_max,
}));
}
};
Ok(Some(ReaderTermInfo {
field: field.to_string(),
term: term.to_string(),
doc_freq: global.doc_freq,
total_freq: global.total_freq,
posting_offset: local.posting_offset,
posting_size: local.posting_length,
max_score_factor: local.max_score_factor,
block_max: local.block_max,
}))
}
fn postings(&self, field: &str, term: &str) -> Result<Option<Box<dyn PostingIterator>>> {
let seg = self.segment.read().unwrap();
seg.postings(field, term)
}
fn field_stats(&self, field: &str) -> Result<Option<FieldStats>> {
let seg = self.segment.read().unwrap();
seg.field_stats(field)
}
fn get_bkd_tree(&self, field: &str) -> Result<Option<Arc<dyn BKDTree>>> {
let seg = self.segment.read().unwrap();
seg.get_filtered_bkd_tree(field)
}
fn close(&mut self) -> Result<()> {
Ok(())
}
fn is_closed(&self) -> bool {
false
}
fn as_any(&self) -> &dyn Any {
self
}
}