Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions proto/points.proto
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,9 @@ message Vector {
}

message VectorOutput {
repeated float data = 1; // Vector data (flatten for multi vectors), deprecated
optional SparseIndices indices = 2; // Sparse indices for sparse vectors, deprecated
optional uint32 vectors_count = 3; // Number of vectors per multi vector, deprecated
repeated float data = 1 [deprecated=true]; // Vector data (flatten for multi vectors), deprecated
optional SparseIndices indices = 2 [deprecated=true]; // Sparse indices for sparse vectors, deprecated
optional uint32 vectors_count = 3 [deprecated=true]; // Number of vectors per multi vector, deprecated
oneof vector {
DenseVector dense = 101; // Dense vector
SparseVector sparse = 102; // Sparse vector
Expand Down
11 changes: 11 additions & 0 deletions src/builders/multi_dense_vector_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,17 @@ impl From<Vec<Vec<f32>>> for MultiDenseVector {
}
}

impl From<Vec<&[f32]>> for MultiDenseVector {
fn from(vectors: Vec<&[f32]>) -> Self {
Self::from(
vectors
.into_iter()
.map(|subvector| DenseVector::from(subvector.to_vec()))
.collect::<Vec<_>>(),
)
}
}

impl From<Vec<DenseVector>> for MultiDenseVector {
fn from(vectors: Vec<DenseVector>) -> Self {
MultiDenseVectorBuilder::new(vectors).build()
Expand Down
8 changes: 4 additions & 4 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ impl Debug for NotA<bool> {

impl Display for NotA<bool> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(concat!("not a bool"))
f.write_str("not a bool")
}
}

Expand All @@ -87,7 +87,7 @@ impl Debug for NotA<i64> {

impl Display for NotA<i64> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(concat!("not an i64"))
f.write_str("not an i64")
}
}

Expand All @@ -114,7 +114,7 @@ impl Debug for NotA<f64> {

impl Display for NotA<f64> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(concat!("not a f64"))
f.write_str("not a f64")
}
}

Expand All @@ -141,7 +141,7 @@ impl Debug for NotA<String> {

impl Display for NotA<String> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(concat!("not a String"))
f.write_str("not a String")
}
}

Expand Down
1 change: 1 addition & 0 deletions src/grpc_conversions/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mod extensions;
mod primitives;
pub mod vectors;

use crate::client::Payload;
use crate::qdrant::point_id::PointIdOptions;
Expand Down
73 changes: 73 additions & 0 deletions src/grpc_conversions/vectors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
use crate::qdrant::vector_output::Vector;
use crate::qdrant::vectors_output::VectorsOptions;
use crate::qdrant::{MultiDenseVector, SparseVector, VectorOutput, VectorsOutput};

impl VectorOutput {
#[allow(deprecated)]
pub fn into_vector(self) -> Vector {
let VectorOutput {
data,
indices,
vectors_count,
vector,
} = self;

if let Some(v) = vector {
return v;
}

if let Some(indices) = indices {
return Vector::Sparse(SparseVector::from((indices.data, data)));
}

if let Some(vectors_count) = vectors_count {
let vectors: Vec<_> = data
.chunks(data.len() / vectors_count as usize)
.collect::<Vec<_>>();

return Vector::MultiDense(MultiDenseVector::from(vectors));
}

Vector::Dense(crate::qdrant::DenseVector { data })
}
}

impl VectorsOutput {
/// Get default (unnamed) vector from VectorsOutput.
///
/// Return `None` if the default vector is not present.
///
/// Use `Self::get_vector_by_name` to get named vectors from VectorsOutput.
pub fn get_vector(&self) -> Option<Vector> {
self.vectors_options
.as_ref()
.and_then(|option| match option {
VectorsOptions::Vector(vector) => Some(vector.clone().into_vector()),
VectorsOptions::Vectors(_) => None,
})
}

/// Get vector by name from VectorsOutput.
///
/// Return `None` if the named vector is not present or is a default (unnamed) vector.
///
/// Use `Self::get_vector` to get the default (unnamed) vector from VectorsOutput.
pub fn get_vector_by_name(&self, name: &str) -> Option<Vector> {
self.vectors_options
.as_ref()
.and_then(|option| match option {
VectorsOptions::Vector(vector) => {
if name.is_empty() {
Some(vector.clone().into_vector())
} else {
None
}
}
VectorsOptions::Vectors(vectors) => vectors
.vectors
.get(name)
.cloned()
.map(|vector| vector.into_vector()),
})
}
}
12 changes: 10 additions & 2 deletions src/qdrant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,8 @@ pub struct OptimizersConfigDiff {
#[prost(uint64, optional, tag = "3")]
pub default_segment_number: ::core::option::Option<u64>,
///
/// Deprecated:
///
/// Do not create segments larger this size (in kilobytes).
/// Large segments might require disproportionately long indexation times,
/// therefore it makes sense to limit the size of segments.
Expand Down Expand Up @@ -557,7 +559,7 @@ pub struct CreateCollection {
/// How many replicas should apply the operation for us to consider it successful, default = 1
#[prost(uint32, optional, tag = "12")]
pub write_consistency_factor: ::core::option::Option<u32>,
/// Specify name of the other collection to copy data from
/// Deprecated: specify name of the other collection to copy data from
#[prost(string, optional, tag = "13")]
pub init_from_collection: ::core::option::Option<::prost::alloc::string::String>,
/// Quantization configuration of vector
Expand Down Expand Up @@ -3167,13 +3169,19 @@ pub mod vector {
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct VectorOutput {
/// Vector data (flatten for multi vectors), deprecated
#[prost(float, repeated, tag = "1")]
#[deprecated]
#[prost(float, repeated, packed = "false", tag = "1")]
///This field is deprecated since 1.16.0, use `into_vector` method instead
pub data: ::prost::alloc::vec::Vec<f32>,
/// Sparse indices for sparse vectors, deprecated
#[deprecated]
#[prost(message, optional, tag = "2")]
///This field is deprecated since 1.16.0, use `into_vector` method instead
pub indices: ::core::option::Option<SparseIndices>,
/// Number of vectors per multi vector, deprecated
#[deprecated]
#[prost(uint32, optional, tag = "3")]
///This field is deprecated since 1.16.0, use `into_vector` method instead
pub vectors_count: ::core::option::Option<u32>,
#[prost(oneof = "vector_output::Vector", tags = "101, 102, 103")]
pub vector: ::core::option::Option<vector_output::Vector>,
Expand Down
14 changes: 14 additions & 0 deletions tests/protos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ trait BuilderExt {

impl BuilderExt for Builder {
fn configure_deprecations(self) -> Self {
// Clear deprecated field for VectorOutput.data

self.field_attribute(
"PointsUpdateOperation.operation.delete_deprecated",
"#[deprecated(since = \"1.7.0\", note = \"use `DeletePoints` instead\")]",
Expand All @@ -59,6 +61,18 @@ impl BuilderExt for Builder {
"PointsUpdateOperation.operation.clear_payload_deprecated",
"#[deprecated(since = \"1.7.0\", note = \"use `ClearPayload` instead\")]",
)
.field_attribute(
"VectorOutput.data",
"#[doc = \"This field is deprecated since 1.16.0, use `into_vector` method instead\"]",
)
.field_attribute(
"VectorOutput.indices",
"#[doc = \"This field is deprecated since 1.16.0, use `into_vector` method instead\"]",
)
.field_attribute(
"VectorOutput.vectors_count",
"#[doc = \"This field is deprecated since 1.16.0, use `into_vector` method instead\"]",
)
}
}

Expand Down
1 change: 1 addition & 0 deletions tests/snippet_tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ mod test_recommend_batch_points;
mod test_recommend_point_groups;
mod test_recommend_points;
mod test_scroll_points;
mod test_scroll_points_with_vectors;
mod test_search_batch_points;
mod test_search_matrix_offsets;
mod test_search_matrix_pairs;
Expand Down
32 changes: 32 additions & 0 deletions tests/snippet_tests/test_scroll_points_with_vectors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@

#[tokio::test]
async fn test_scroll_points_with_vectors() {
async fn scroll_points_with_vectors() -> Result<(), Box<dyn std::error::Error>> {
// WARNING: This is a generated test snippet.
// Please, modify the snippet in the `../snippets/scroll_points_with_vectors.rs` file
use qdrant_client::qdrant::{Condition, Filter, ScrollPointsBuilder};
use qdrant_client::Qdrant;

let client = Qdrant::from_url("http://localhost:6334").build()?;

let scroll_response = client
.scroll(
ScrollPointsBuilder::new("{collection_name}")
.filter(Filter::must([Condition::matches(
"color",
"red".to_string(),
)]))
.limit(1)
.with_payload(true)
.with_vectors(true),
)
.await?;

for point in scroll_response.result {
let vector = point.vectors.unwrap().get_vector();
println!("vector: {vector:?}");
}
Ok(())
}
let _ = scroll_points_with_vectors().await;
}
22 changes: 22 additions & 0 deletions tests/snippets/scroll_points_with_vectors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use qdrant_client::qdrant::{Condition, Filter, ScrollPointsBuilder};
use qdrant_client::Qdrant;

let client = Qdrant::from_url("http://localhost:6334").build()?;

let scroll_response = client
.scroll(
ScrollPointsBuilder::new("{collection_name}")
.filter(Filter::must([Condition::matches(
"color",
"red".to_string(),
)]))
.limit(1)
.with_payload(true)
.with_vectors(true),
)
.await?;

for point in scroll_response.result {
let vector = point.vectors.unwrap().get_vector();
println!("vector: {vector:?}");
}