#[cfg(feature = "api")]
mod conversions;
pub mod formula;
pub mod mmr;
pub mod planned_query;
pub mod query_enum;
pub mod scroll;
mod validation;
pub mod query_context;
#[cfg(test)]
mod tests;
use crate::common::types::ScoreType;
use ordered_float::OrderedFloat;
use crate::segment::data_types::order_by::OrderBy;
use crate::segment::data_types::vectors::VectorInternal;
use crate::segment::index::query_optimization::rescore_formula::parsed_formula::ParsedFormula;
use crate::segment::types::*;
use serde::Serialize;
use self::query_enum::*;
use crate::shard::search::CoreSearchRequest;
pub type ShardQueryResponse = Vec<Vec<ScoredPoint>>;
#[derive(Clone, Debug, Hash, Serialize)]
pub struct ShardQueryRequest {
pub prefetches: Vec<ShardPrefetch>,
#[serde(skip_serializing_if = "Option::is_none")]
pub query: Option<ScoringQuery>,
#[serde(skip_serializing_if = "Option::is_none")]
pub filter: Option<Filter>,
#[serde(skip_serializing_if = "Option::is_none")]
pub score_threshold: Option<OrderedFloat<ScoreType>>,
pub limit: usize,
pub offset: usize,
#[serde(skip_serializing_if = "Option::is_none")]
pub params: Option<SearchParams>,
pub with_vector: WithVector,
pub with_payload: WithPayloadInterface,
}
impl ShardQueryRequest {
pub fn prefetches_depth(&self) -> usize {
self.prefetches
.iter()
.map(ShardPrefetch::depth)
.max()
.unwrap_or(0)
}
pub fn filter_refs(&self) -> Vec<Option<&Filter>> {
let mut filters = vec![];
filters.push(self.filter.as_ref());
for prefetch in &self.prefetches {
filters.extend(prefetch.filter_refs())
}
filters
}
}
#[derive(Clone, Debug, Hash, Serialize)]
pub struct ShardPrefetch {
pub prefetches: Vec<ShardPrefetch>,
#[serde(skip_serializing_if = "Option::is_none")]
pub query: Option<ScoringQuery>,
pub limit: usize,
#[serde(skip_serializing_if = "Option::is_none")]
pub params: Option<SearchParams>,
#[serde(skip_serializing_if = "Option::is_none")]
pub filter: Option<Filter>,
#[serde(skip_serializing_if = "Option::is_none")]
pub score_threshold: Option<OrderedFloat<ScoreType>>,
}
impl ShardPrefetch {
pub fn depth(&self) -> usize {
let mut depth = 1;
for prefetch in &self.prefetches {
depth = depth.max(prefetch.depth() + 1);
}
depth
}
fn filter_refs(&self) -> Vec<Option<&Filter>> {
let mut filters = vec![];
filters.push(self.filter.as_ref());
for prefetch in &self.prefetches {
filters.extend(prefetch.filter_refs())
}
filters
}
}
#[derive(Clone, Debug, PartialEq, Hash, Serialize)]
pub enum ScoringQuery {
Vector(QueryEnum),
Fusion(FusionInternal),
OrderBy(OrderBy),
Formula(ParsedFormula),
Sample(SampleInternal),
Mmr(MmrInternal),
}
impl ScoringQuery {
pub fn get_vector_name(&self) -> Option<&VectorName> {
match self {
ScoringQuery::Vector(query) => Some(query.get_vector_name()),
ScoringQuery::Mmr(mmr) => Some(&mmr.using),
ScoringQuery::Fusion(_)
| ScoringQuery::OrderBy(_)
| ScoringQuery::Formula(_)
| ScoringQuery::Sample(_) => None,
}
}
}
pub fn query_result_order<E>(
query: Option<&ScoringQuery>,
get_distance: impl FnOnce(&VectorName) -> Result<Distance, E>,
) -> Result<Option<Order>, E> {
let order = match query {
Some(scoring_query) => match scoring_query {
ScoringQuery::Vector(query_enum) => {
if query_enum.is_distance_scored() {
Some(get_distance(query_enum.get_vector_name())?.distance_order())
} else {
Some(Order::LargeBetter)
}
}
ScoringQuery::Fusion(fusion) => match fusion {
FusionInternal::Rrf { k: _, weights: _ } | FusionInternal::Dbsf => {
Some(Order::LargeBetter)
}
},
ScoringQuery::Formula(_formula) => Some(Order::LargeBetter),
ScoringQuery::OrderBy(order_by) => Some(Order::from(order_by.direction())),
ScoringQuery::Sample(SampleInternal::Random) => None,
ScoringQuery::Mmr(_) => None,
},
None => {
Some(Order::SmallBetter)
}
};
Ok(order)
}
#[derive(Clone, Debug, PartialEq, Hash, Serialize)]
pub enum FusionInternal {
Rrf {
k: usize,
weights: Option<Vec<ordered_float::OrderedFloat<f32>>>,
},
Dbsf,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
pub enum SampleInternal {
Random,
}
#[derive(Clone, Debug, PartialEq, Hash, Serialize)]
pub struct MmrInternal {
pub vector: VectorInternal,
pub using: VectorNameBuf,
pub lambda: OrderedFloat<f32>,
pub candidates_limit: usize,
}
impl From<CoreSearchRequest> for ShardQueryRequest {
fn from(value: CoreSearchRequest) -> Self {
let CoreSearchRequest {
query,
filter,
score_threshold,
limit,
offset,
params,
with_vector,
with_payload,
} = value;
Self {
prefetches: vec![],
query: Some(ScoringQuery::Vector(query)),
filter,
score_threshold: score_threshold.map(OrderedFloat),
limit,
offset,
params,
with_vector: with_vector.unwrap_or_default(),
with_payload: with_payload.unwrap_or_default(),
}
}
}