use serde::{Deserialize, Serialize};
use std::collections::HashMap;
pub type VectorId = String;
pub type Vector = [f32];
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct Metadata {
pub fields: HashMap<String, MetadataValue>,
}
impl Metadata {
pub fn new() -> Self {
Self {
fields: HashMap::new(),
}
}
pub fn insert(&mut self, key: impl Into<String>, value: impl Into<MetadataValue>) -> &mut Self {
self.fields.insert(key.into(), value.into());
self
}
pub fn get(&self, key: &str) -> Option<&MetadataValue> {
self.fields.get(key)
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum MetadataValue {
String(String),
Int(i64),
Float(f64),
Bool(bool),
List(Vec<MetadataValue>),
Map(HashMap<String, MetadataValue>),
}
impl From<String> for MetadataValue {
fn from(s: String) -> Self {
MetadataValue::String(s)
}
}
impl From<&str> for MetadataValue {
fn from(s: &str) -> Self {
MetadataValue::String(s.to_string())
}
}
impl From<i64> for MetadataValue {
fn from(i: i64) -> Self {
MetadataValue::Int(i)
}
}
impl From<f64> for MetadataValue {
fn from(f: f64) -> Self {
MetadataValue::Float(f)
}
}
impl From<bool> for MetadataValue {
fn from(b: bool) -> Self {
MetadataValue::Bool(b)
}
}
impl MetadataValue {
pub fn as_str(&self) -> Option<&str> {
match self {
MetadataValue::String(s) => Some(s.as_str()),
_ => None,
}
}
pub fn as_i64(&self) -> Option<i64> {
match self {
MetadataValue::Int(i) => Some(*i),
_ => None,
}
}
pub fn as_f64(&self) -> Option<f64> {
match self {
MetadataValue::Float(f) => Some(*f),
_ => None,
}
}
pub fn as_bool(&self) -> Option<bool> {
match self {
MetadataValue::Bool(b) => Some(*b),
_ => None,
}
}
}
#[derive(Debug, Clone)]
pub struct SearchResult {
pub id: VectorId,
pub distance: f32,
pub metadata: Option<Metadata>,
}
#[derive(Debug, Clone)]
pub struct Config {
pub dimensions: usize,
pub distance: crate::Distance,
pub index: crate::IndexType,
pub quantization: crate::quantization::QuantizationType,
}
impl Config {
pub fn new(dimensions: usize) -> Self {
Self {
dimensions,
distance: crate::Distance::Cosine,
index: crate::IndexType::Flat,
quantization: crate::quantization::QuantizationType::None,
}
}
pub fn with_distance(mut self, distance: crate::Distance) -> Self {
self.distance = distance;
self
}
pub fn with_index(mut self, index: crate::IndexType) -> Self {
self.index = index;
self
}
pub fn with_quantization(
mut self,
quantization: crate::quantization::QuantizationType,
) -> Self {
self.quantization = quantization;
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StoredVector {
pub id: VectorId,
pub vector: Option<Vec<f32>>,
pub metadata: Option<Metadata>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub quantized: Option<crate::quantization::QuantizedVector>,
}
#[derive(Debug, Clone)]
pub struct HybridSearchResult {
pub id: VectorId,
pub score: f32,
pub vector_distance: Option<f32>,
pub bm25_score: Option<f32>,
pub vector_rank: Option<usize>,
pub keyword_rank: Option<usize>,
pub metadata: Option<Metadata>,
}
#[derive(Debug, Clone)]
pub struct PagedResult<T> {
pub items: Vec<T>,
pub total: usize,
pub offset: usize,
pub limit: usize,
}
impl<T> PagedResult<T> {
pub fn has_more(&self) -> bool {
self.offset + self.items.len() < self.total
}
pub fn total_pages(&self) -> usize {
if self.limit == 0 {
return 0;
}
(self.total + self.limit - 1) / self.limit
}
pub fn current_page(&self) -> usize {
if self.limit == 0 {
return 0;
}
self.offset / self.limit
}
}