use std::sync::Arc;
use diskann::{graph::DiskANNIndex, provider::DataProvider};
use diskann_benchmark_runner::utils::fmt::{Delimit, Quote};
use diskann_providers::model::graph::provider::DeterminantDiversityParams;
use crate::{
index::result::AggregatedSearchResults,
inputs::graph_index::{SearchPhase, TopkDeterminantDiversityPhase},
};
pub(crate) trait Plugin<DP, Kind, Params>: std::fmt::Debug
where
DP: DataProvider,
{
fn is_match(&self, kind: &Kind) -> bool;
fn kind(&self) -> &'static str;
fn run(
&self,
index: Arc<DiskANNIndex<DP>>,
kind: &Kind,
parameters: &Params,
) -> anyhow::Result<AggregatedSearchResults>;
}
#[derive(Debug)]
pub(crate) struct Plugins<DP, Kind, Params>
where
DP: DataProvider,
{
plugins: Vec<Box<dyn Plugin<DP, Kind, Params>>>,
}
impl<DP, Kind, Params> Plugins<DP, Kind, Params>
where
DP: DataProvider,
{
pub(crate) fn new() -> Self {
Self {
plugins: Vec::new(),
}
}
pub(crate) fn register<T>(&mut self, plugin: T)
where
T: Plugin<DP, Kind, Params> + 'static,
{
self.plugins.push(Box::new(plugin));
}
pub(crate) fn kinds(
&self,
) -> impl ExactSizeIterator<Item = &'static str> + use<'_, DP, Kind, Params> {
self.plugins.iter().map(|p| p.kind())
}
pub(crate) fn is_match(&self, kind: &Kind) -> bool {
self.plugins.iter().any(|p| p.is_match(kind))
}
pub(crate) fn format_kinds(&self) -> impl std::fmt::Display + use<'_, DP, Kind, Params> {
Delimit::new(self.kinds().map(Quote), ", ")
.with_last(", and ")
.with_pair(" and ")
}
pub(crate) fn run(
&self,
index: Arc<DiskANNIndex<DP>>,
kind: &Kind,
parameters: &Params,
) -> anyhow::Result<AggregatedSearchResults>
where
Kind: std::fmt::Debug,
{
match self.plugins.iter().find(|p| p.is_match(kind)) {
Some(plugin) => plugin.run(index, kind, parameters),
None => Err(anyhow::anyhow!(
"INTERNAL ERROR: Could not find a suitable search plugin for {:?}",
kind
)),
}
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct Topk;
impl Topk {
pub(crate) fn is_match(phase: &SearchPhase) -> bool {
phase.as_topk().is_ok()
}
pub(crate) const fn as_str() -> &'static str {
"topk"
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct DeterminantDiversity;
impl DeterminantDiversity {
pub(crate) fn is_match(phase: &SearchPhase) -> bool {
phase.as_topk_determinant_diversity().is_ok()
}
pub(crate) const fn as_str() -> &'static str {
"topk-determinant-diversity"
}
pub(crate) fn get(
phase: &SearchPhase,
) -> anyhow::Result<(&TopkDeterminantDiversityPhase, DeterminantDiversityParams)> {
let phase = phase.as_topk_determinant_diversity()?;
let params = DeterminantDiversityParams::new(phase.power, phase.eta)?;
Ok((phase, params))
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct Range;
impl Range {
pub(crate) fn is_match(phase: &SearchPhase) -> bool {
phase.as_range().is_ok()
}
pub(crate) const fn as_str() -> &'static str {
"range"
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct TopkBetaFilter;
impl TopkBetaFilter {
pub(crate) fn is_match(phase: &SearchPhase) -> bool {
phase.as_topk_beta_filter().is_ok()
}
pub(crate) const fn as_str() -> &'static str {
"topk + beta filter"
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct TopkMultihopFilter;
impl TopkMultihopFilter {
pub(crate) fn is_match(phase: &SearchPhase) -> bool {
phase.as_topk_multihop_filter().is_ok()
}
pub(crate) const fn as_str() -> &'static str {
"topk + multihop filter"
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct TopkInlineFilter;
impl TopkInlineFilter {
pub(crate) fn is_match(phase: &SearchPhase) -> bool {
phase.as_topk_inline_filter().is_ok()
}
pub(crate) const fn as_str() -> &'static str {
"topk + inline filter"
}
}