use crate::collection::expiry::{is_payload_expired, now_unix_secs};
use crate::error::Error;
use crate::point::{Point, SearchResult};
use crate::scored_result::ScoredResult;
use crate::storage::{PayloadStorage, VectorStorage};
#[inline]
pub(crate) fn hydrate_point(
id: u64,
score: f32,
now_secs: u64,
vector_storage: &dyn VectorStorage,
payload_storage: &dyn PayloadStorage,
) -> Option<SearchResult> {
let vector = vector_storage.retrieve(id).ok().flatten()?;
let payload = payload_storage.retrieve(id).ok().flatten();
if is_payload_expired(payload.as_ref(), now_secs) {
return None;
}
let point = Point {
id,
vector,
payload,
sparse_vectors: None,
};
Some(SearchResult::new(point, score))
}
pub(crate) fn resolve_id_score_pairs(
pairs: &[(u64, f32)],
limit: usize,
vector_storage: &dyn VectorStorage,
payload_storage: &dyn PayloadStorage,
) -> Vec<SearchResult> {
let now_secs = now_unix_secs();
pairs
.iter()
.take(limit)
.filter_map(|&(id, score)| {
hydrate_point(id, score, now_secs, vector_storage, payload_storage)
})
.collect()
}
pub(crate) fn resolve_scored_results(
results: &[ScoredResult],
vector_storage: &dyn VectorStorage,
payload_storage: &dyn PayloadStorage,
) -> Vec<SearchResult> {
let now_secs = now_unix_secs();
results
.iter()
.filter_map(|sr| hydrate_point(sr.id, sr.score, now_secs, vector_storage, payload_storage))
.collect()
}
pub(crate) fn sort_results_by_metric(results: &mut [SearchResult], higher_is_better: bool) {
results.sort_unstable_by(|a, b| {
if higher_is_better {
b.score.partial_cmp(&a.score).unwrap_or_else(|| {
match (a.score.is_nan(), b.score.is_nan()) {
(true, false) => std::cmp::Ordering::Greater,
(false, true) => std::cmp::Ordering::Less,
_ => std::cmp::Ordering::Equal,
}
})
} else {
a.score.total_cmp(&b.score)
}
});
}
pub(crate) fn sort_scored_by_metric(results: &mut [ScoredResult], higher_is_better: bool) {
results.sort_unstable_by(|a, b| {
if higher_is_better {
b.score.partial_cmp(&a.score).unwrap_or_else(|| {
match (a.score.is_nan(), b.score.is_nan()) {
(true, false) => std::cmp::Ordering::Greater,
(false, true) => std::cmp::Ordering::Less,
_ => std::cmp::Ordering::Equal,
}
})
} else {
a.score.total_cmp(&b.score)
}
});
}
#[allow(dead_code)] pub(crate) fn sort_results_descending(results: &mut [SearchResult]) {
results.sort_unstable_by(|a, b| {
b.score.partial_cmp(&a.score).unwrap_or_else(|| {
match (a.score.is_nan(), b.score.is_nan()) {
(true, false) => std::cmp::Ordering::Greater,
(false, true) => std::cmp::Ordering::Less,
_ => std::cmp::Ordering::Equal,
}
})
});
}
pub(crate) fn sparse_index_not_found(index_name: &str) -> Error {
Error::Config(format!(
"Sparse index '{}' not found",
if index_name.is_empty() {
"<default>"
} else {
index_name
}
))
}
#[cfg(test)]
#[path = "resolve_tests.rs"]
mod tests;