use std::ops::Deref;
use ahash::AHashSet;
use crate::common::types::PointOffsetType;
use crate::segment::types::{Condition, FieldCondition, PointIdType, VectorNameBuf};
pub mod bool_index;
mod deleted_mask;
pub(super) mod facet_index;
mod field_index_base;
pub mod full_text_index;
pub mod geo_hash;
pub mod geo_index;
mod histogram;
mod immutable_point_to_values;
pub mod index_selector;
pub mod map_index;
mod memory_reporter;
pub mod null_index;
pub mod numeric_index;
mod numeric_point;
mod on_disk_point_to_values;
pub mod schema_transition;
mod stat_tools;
#[cfg(test)]
mod tests;
mod utils;
pub use facet_index::FacetIndex;
pub use field_index_base::*;
use crate::segment::utils::maybe_arc::MaybeArc;
#[derive(Debug, Clone, PartialEq)]
pub struct ResolvedHasId {
pub point_ids: MaybeArc<AHashSet<PointIdType>>,
pub resolved_point_offsets: Vec<PointOffsetType>,
}
#[derive(Debug, Clone, PartialEq)]
pub enum PrimaryCondition {
Condition(Box<FieldCondition>),
Ids(ResolvedHasId),
HasVector(VectorNameBuf),
}
impl From<FieldCondition> for PrimaryCondition {
fn from(condition: FieldCondition) -> Self {
PrimaryCondition::Condition(Box::new(condition))
}
}
#[derive(Debug, Clone)]
pub struct PayloadBlockCondition {
pub condition: FieldCondition,
pub cardinality: usize,
}
#[derive(Debug, Clone, PartialEq)]
pub struct CardinalityEstimation {
pub primary_clauses: Vec<PrimaryCondition>,
pub min: usize,
pub exp: usize,
pub max: usize,
}
impl CardinalityEstimation {
pub const fn exact(count: usize) -> Self {
CardinalityEstimation {
primary_clauses: vec![],
min: count,
exp: count,
max: count,
}
}
pub const fn unknown(total: usize) -> Self {
CardinalityEstimation {
primary_clauses: vec![],
min: 0,
exp: total / 2,
max: total,
}
}
pub fn with_primary_clause(mut self, clause: PrimaryCondition) -> Self {
self.primary_clauses.push(clause);
self
}
#[cfg(test)]
pub const fn equals_min_exp_max(&self, other: &Self) -> bool {
self.min == other.min && self.exp == other.exp && self.max == other.max
}
pub fn is_primary(&self, condition: &Condition) -> bool {
self.primary_clauses
.iter()
.any(|primary_condition| match primary_condition {
PrimaryCondition::Condition(primary_field_condition) => match condition {
Condition::Field(field_condition) => {
primary_field_condition.as_ref() == field_condition
}
Condition::IsEmpty(_)
| Condition::IsNull(_)
| Condition::HasId(_)
| Condition::HasVector(_)
| Condition::Slice(_)
| Condition::Nested(_)
| Condition::Filter(_)
| Condition::CustomIdChecker(_) => false,
},
PrimaryCondition::Ids(ids) => match condition {
Condition::HasId(has_id) => ids.point_ids.deref() == has_id.has_id.deref(),
Condition::Field(_)
| Condition::IsEmpty(_)
| Condition::IsNull(_)
| Condition::HasVector(_)
| Condition::Slice(_)
| Condition::Nested(_)
| Condition::Filter(_)
| Condition::CustomIdChecker(_) => false,
},
PrimaryCondition::HasVector(has_vector) => match condition {
Condition::HasVector(vector_condition) => {
has_vector == &vector_condition.has_vector
}
Condition::Field(_)
| Condition::IsEmpty(_)
| Condition::IsNull(_)
| Condition::HasId(_)
| Condition::Slice(_)
| Condition::Nested(_)
| Condition::Filter(_)
| Condition::CustomIdChecker(_) => false,
},
})
}
pub fn full_scan_evals(&self, available_points: usize) -> usize {
if self.primary_clauses.is_empty() {
available_points
} else {
self.exp
}
}
}
pub trait EstimationMerge: Iterator<Item = CardinalityEstimation> {
fn merge_independent(self) -> CardinalityEstimation
where
Self: Sized,
{
self.fold(CardinalityEstimation::exact(0), |acc, x| {
CardinalityEstimation {
primary_clauses: vec![],
min: acc.min + x.min,
exp: acc.exp + x.exp,
max: acc.max + x.max,
}
})
}
}
impl<I> EstimationMerge for I where I: Iterator<Item = CardinalityEstimation> {}