use crate::index::fuse::DEFAULT_RRF_K;
use crate::index::meta::{DocMeta, Filter};
use crate::resource::{DocId, ResourceKind};
use compact_str::CompactString;
#[derive(Clone, Copy, Debug)]
pub enum Fusion {
Rrf {
k: u32,
},
}
impl Default for Fusion {
fn default() -> Self {
Self::Rrf { k: DEFAULT_RRF_K }
}
}
#[derive(Clone, Copy, Debug)]
pub struct RankParams {
pub dense_weight: f32,
pub sparse_weight: f32,
pub fusion: Fusion,
pub candidate_multiplier: usize,
pub graph_boost: f32,
}
impl Default for RankParams {
fn default() -> Self {
Self {
dense_weight: 1.0,
sparse_weight: 1.0,
fusion: Fusion::default(),
candidate_multiplier: 10,
graph_boost: 0.0,
}
}
}
#[derive(Debug)]
pub struct PreparedQuery<'a> {
pub vector: &'a [f32],
pub terms: &'a [CompactString],
pub filter: &'a Filter,
pub limit: usize,
pub rank: RankParams,
}
#[derive(Clone, Copy, Debug)]
pub struct Hit<'a> {
pub url: &'a str,
pub score: f32,
pub title: Option<&'a str>,
pub snippet: &'a str,
pub kind: ResourceKind,
doc: &'a DocMeta,
}
impl<'a> Hit<'a> {
pub fn tags(&self) -> impl Iterator<Item = &'a str> {
self.doc.tags.iter().map(CompactString::as_str)
}
}
#[derive(Debug)]
pub struct Hits<'a> {
docs: &'a [DocMeta],
ranked: Vec<(DocId, f32)>,
}
impl<'a> Hits<'a> {
#[must_use]
pub(crate) fn new(docs: &'a [DocMeta], ranked: Vec<(DocId, f32)>) -> Self {
Self { docs, ranked }
}
#[must_use]
pub fn len(&self) -> usize {
self.ranked.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.ranked.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = Hit<'a>> + '_ {
let docs = self.docs;
self.ranked.iter().map(move |&(id, score)| {
let doc = &docs[id as usize];
Hit {
url: &doc.url,
score,
title: doc.title.as_deref(),
snippet: &doc.snippet,
kind: doc.kind,
doc,
}
})
}
}
impl<'a> IntoIterator for &Hits<'a> {
type Item = Hit<'a>;
type IntoIter = std::vec::IntoIter<Hit<'a>>;
fn into_iter(self) -> Self::IntoIter {
self.iter().collect::<Vec<_>>().into_iter()
}
}