use std::collections::HashSet;
use swiftide_core::{
indexing::{EmbeddedField, IndexingStream, Persist, TextNode},
prelude::*,
};
use qdrant_client::qdrant::UpsertPointsBuilder;
use super::{NodeWithVectors, Qdrant};
#[async_trait]
impl Persist for Qdrant {
type Input = String;
type Output = String;
fn batch_size(&self) -> Option<usize> {
self.batch_size
}
#[tracing::instrument(skip_all, err)]
async fn setup(&self) -> Result<()> {
tracing::debug!("Setting up Qdrant storage");
self.create_index_if_not_exists().await
}
#[tracing::instrument(skip_all, err, name = "storage.qdrant.store")]
async fn store(&self, node: TextNode) -> Result<TextNode> {
let node_with_vectors = NodeWithVectors::new(&node, self.vector_fields());
let point = node_with_vectors.try_into()?;
tracing::debug!("Storing node");
self.client
.upsert_points(
UpsertPointsBuilder::new(self.collection_name.clone(), vec![point])
.wait(cfg!(debug_assertions)),
)
.await?;
Ok(node)
}
#[tracing::instrument(skip_all, name = "storage.qdrant.batch_store")]
async fn batch_store(&self, nodes: Vec<TextNode>) -> IndexingStream<String> {
let points = nodes
.iter()
.map(|node| NodeWithVectors::new(node, self.vector_fields()))
.map(NodeWithVectors::try_into)
.collect::<Result<Vec<_>>>();
let Ok(points) = points else {
return vec![Err(points.unwrap_err())].into();
};
tracing::debug!("Storing batch of {} nodes", points.len());
match self
.client
.upsert_points(
UpsertPointsBuilder::new(self.collection_name.clone(), points)
.wait(cfg!(debug_assertions)),
)
.await
{
Ok(_) => IndexingStream::iter(nodes.into_iter().map(Ok)),
Err(err) => vec![Err(err.into())].into(),
}
}
}
impl Qdrant {
fn vector_fields(&self) -> HashSet<&EmbeddedField> {
self.vectors.keys().collect::<HashSet<_>>()
}
}