Spaces:
Build error
Build error
use std::collections::{HashMap, HashSet}; | |
use std::str::FromStr as _; | |
use std::time::Instant; | |
use chrono::{NaiveDateTime, Timelike}; | |
use common::counter::hardware_accumulator::HwMeasurementAcc; | |
use common::counter::hardware_counter::HardwareCounterCell; | |
use itertools::Itertools; | |
use segment::common::operation_error::OperationError; | |
use segment::data_types::index::{ | |
BoolIndexType, DatetimeIndexType, FloatIndexType, GeoIndexType, IntegerIndexType, | |
KeywordIndexType, TextIndexType, UuidIndexType, | |
}; | |
use segment::data_types::{facets as segment_facets, vectors as segment_vectors}; | |
use segment::types::{default_quantization_ignore_value, DateTimePayloadType, FloatPayloadType}; | |
use segment::vector_storage::query as segment_query; | |
use sparse::common::sparse_vector::validate_sparse_vector_impl; | |
use tonic::Status; | |
use uuid::Uuid; | |
use super::qdrant::raw_query::RawContextPair; | |
use super::qdrant::{ | |
raw_query, start_from, BinaryQuantization, BoolIndexParams, CompressionRatio, | |
DatetimeIndexParams, DatetimeRange, Direction, FacetHit, FacetHitInternal, FacetValue, | |
FacetValueInternal, FieldType, FloatIndexParams, GeoIndexParams, GeoLineString, GroupId, | |
HardwareUsage, HasVectorCondition, KeywordIndexParams, LookupLocation, MultiVectorComparator, | |
MultiVectorConfig, OrderBy, OrderValue, Range, RawVector, RecommendStrategy, RetrievedPoint, | |
SearchMatrixPair, SearchPointGroups, SearchPoints, ShardKeySelector, SparseIndices, StartFrom, | |
UuidIndexParams, VectorsOutput, WithLookup, | |
}; | |
use crate::conversions::json; | |
use crate::grpc::qdrant::condition::ConditionOneOf; | |
use crate::grpc::qdrant::payload_index_params::IndexParams; | |
use crate::grpc::qdrant::point_id::PointIdOptions; | |
use crate::grpc::qdrant::r#match::MatchValue; | |
use crate::grpc::qdrant::with_payload_selector::SelectorOptions; | |
use crate::grpc::qdrant::{ | |
shard_key, with_vectors_selector, CollectionDescription, CollectionOperationResponse, | |
Condition, Distance, FieldCondition, Filter, GeoBoundingBox, GeoPoint, GeoPolygon, GeoRadius, | |
HasIdCondition, HealthCheckReply, HnswConfigDiff, IntegerIndexParams, IsEmptyCondition, | |
IsNullCondition, ListCollectionsResponse, Match, MinShould, NamedVectors, NestedCondition, | |
PayloadExcludeSelector, PayloadIncludeSelector, PayloadIndexParams, PayloadSchemaInfo, | |
PayloadSchemaType, PointId, PointStruct, PointsOperationResponse, | |
PointsOperationResponseInternal, ProductQuantization, QuantizationConfig, | |
QuantizationSearchParams, QuantizationType, RepeatedIntegers, RepeatedStrings, | |
ScalarQuantization, ScoredPoint, SearchParams, ShardKey, StrictModeConfig, TextIndexParams, | |
TokenizerType, UpdateResult, UpdateResultInternal, ValuesCount, VectorsSelector, | |
WithPayloadSelector, WithVectorsSelector, | |
}; | |
use crate::rest::models::{CollectionsResponse, VersionInfo}; | |
use crate::rest::schema as rest; | |
pub fn convert_shard_key_to_grpc(value: segment::types::ShardKey) -> ShardKey { | |
match value { | |
segment::types::ShardKey::Keyword(keyword) => ShardKey { | |
key: Some(shard_key::Key::Keyword(keyword)), | |
}, | |
segment::types::ShardKey::Number(number) => ShardKey { | |
key: Some(shard_key::Key::Number(number)), | |
}, | |
} | |
} | |
pub fn convert_shard_key_from_grpc(value: ShardKey) -> Option<segment::types::ShardKey> { | |
match value.key { | |
None => None, | |
Some(key) => match key { | |
shard_key::Key::Keyword(keyword) => Some(segment::types::ShardKey::Keyword(keyword)), | |
shard_key::Key::Number(number) => Some(segment::types::ShardKey::Number(number)), | |
}, | |
} | |
} | |
pub fn convert_shard_key_from_grpc_opt( | |
value: Option<ShardKey>, | |
) -> Option<segment::types::ShardKey> { | |
match value { | |
None => None, | |
Some(key) => match key.key { | |
None => None, | |
Some(key) => match key { | |
shard_key::Key::Keyword(keyword) => { | |
Some(segment::types::ShardKey::Keyword(keyword)) | |
} | |
shard_key::Key::Number(number) => Some(segment::types::ShardKey::Number(number)), | |
}, | |
}, | |
} | |
} | |
impl From<ShardKeySelector> for rest::ShardKeySelector { | |
fn from(value: ShardKeySelector) -> Self { | |
let shard_keys: Vec<_> = value | |
.shard_keys | |
.into_iter() | |
.filter_map(convert_shard_key_from_grpc) | |
.collect(); | |
if shard_keys.len() == 1 { | |
rest::ShardKeySelector::ShardKey(shard_keys.into_iter().next().unwrap()) | |
} else { | |
rest::ShardKeySelector::ShardKeys(shard_keys) | |
} | |
} | |
} | |
impl From<VersionInfo> for HealthCheckReply { | |
fn from(info: VersionInfo) -> Self { | |
HealthCheckReply { | |
title: info.title, | |
version: info.version, | |
commit: info.commit, | |
} | |
} | |
} | |
impl From<(Instant, CollectionsResponse)> for ListCollectionsResponse { | |
fn from(value: (Instant, CollectionsResponse)) -> Self { | |
let (timing, response) = value; | |
let collections = response | |
.collections | |
.into_iter() | |
.map(|desc| CollectionDescription { name: desc.name }) | |
.collect::<Vec<_>>(); | |
Self { | |
collections, | |
time: timing.elapsed().as_secs_f64(), | |
} | |
} | |
} | |
impl From<segment::data_types::index::TokenizerType> for TokenizerType { | |
fn from(tokenizer_type: segment::data_types::index::TokenizerType) -> Self { | |
match tokenizer_type { | |
segment::data_types::index::TokenizerType::Prefix => TokenizerType::Prefix, | |
segment::data_types::index::TokenizerType::Whitespace => TokenizerType::Whitespace, | |
segment::data_types::index::TokenizerType::Multilingual => TokenizerType::Multilingual, | |
segment::data_types::index::TokenizerType::Word => TokenizerType::Word, | |
} | |
} | |
} | |
impl From<segment::data_types::index::KeywordIndexParams> for PayloadIndexParams { | |
fn from(params: segment::data_types::index::KeywordIndexParams) -> Self { | |
PayloadIndexParams { | |
index_params: Some(IndexParams::KeywordIndexParams(KeywordIndexParams { | |
is_tenant: params.is_tenant, | |
on_disk: params.on_disk, | |
})), | |
} | |
} | |
} | |
impl From<segment::data_types::index::IntegerIndexParams> for PayloadIndexParams { | |
fn from(params: segment::data_types::index::IntegerIndexParams) -> Self { | |
PayloadIndexParams { | |
index_params: Some(IndexParams::IntegerIndexParams(IntegerIndexParams { | |
lookup: params.lookup, | |
range: params.range, | |
on_disk: params.on_disk, | |
is_principal: params.is_principal, | |
})), | |
} | |
} | |
} | |
impl From<segment::data_types::index::FloatIndexParams> for PayloadIndexParams { | |
fn from(params: segment::data_types::index::FloatIndexParams) -> Self { | |
PayloadIndexParams { | |
index_params: Some(IndexParams::FloatIndexParams(FloatIndexParams { | |
on_disk: params.on_disk, | |
is_principal: params.is_principal, | |
})), | |
} | |
} | |
} | |
impl From<segment::data_types::index::GeoIndexParams> for PayloadIndexParams { | |
fn from(params: segment::data_types::index::GeoIndexParams) -> Self { | |
PayloadIndexParams { | |
index_params: Some(IndexParams::GeoIndexParams(GeoIndexParams { | |
on_disk: params.on_disk, | |
})), | |
} | |
} | |
} | |
impl From<segment::data_types::index::TextIndexParams> for PayloadIndexParams { | |
fn from(params: segment::data_types::index::TextIndexParams) -> Self { | |
let tokenizer = TokenizerType::from(params.tokenizer); | |
PayloadIndexParams { | |
index_params: Some(IndexParams::TextIndexParams(TextIndexParams { | |
tokenizer: tokenizer as i32, | |
lowercase: params.lowercase, | |
min_token_len: params.min_token_len.map(|x| x as u64), | |
max_token_len: params.max_token_len.map(|x| x as u64), | |
on_disk: params.on_disk, | |
})), | |
} | |
} | |
} | |
impl From<segment::data_types::index::BoolIndexParams> for PayloadIndexParams { | |
fn from(_params: segment::data_types::index::BoolIndexParams) -> Self { | |
PayloadIndexParams { | |
index_params: Some(IndexParams::BoolIndexParams(BoolIndexParams {})), | |
} | |
} | |
} | |
impl From<segment::data_types::index::UuidIndexParams> for PayloadIndexParams { | |
fn from(params: segment::data_types::index::UuidIndexParams) -> Self { | |
PayloadIndexParams { | |
index_params: Some(IndexParams::UuidIndexParams(UuidIndexParams { | |
is_tenant: params.is_tenant, | |
on_disk: params.on_disk, | |
})), | |
} | |
} | |
} | |
impl From<segment::data_types::index::DatetimeIndexParams> for PayloadIndexParams { | |
fn from(params: segment::data_types::index::DatetimeIndexParams) -> Self { | |
PayloadIndexParams { | |
index_params: Some(IndexParams::DatetimeIndexParams(DatetimeIndexParams { | |
on_disk: params.on_disk, | |
is_principal: params.is_principal, | |
})), | |
} | |
} | |
} | |
impl From<segment::types::PayloadIndexInfo> for PayloadSchemaInfo { | |
fn from(schema: segment::types::PayloadIndexInfo) -> Self { | |
PayloadSchemaInfo { | |
data_type: PayloadSchemaType::from(schema.data_type) as i32, | |
params: schema.params.map(|p| p.into()), | |
points: Some(schema.points as u64), | |
} | |
} | |
} | |
impl From<segment::types::PayloadSchemaType> for PayloadSchemaType { | |
fn from(schema_type: segment::types::PayloadSchemaType) -> Self { | |
match schema_type { | |
segment::types::PayloadSchemaType::Keyword => PayloadSchemaType::Keyword, | |
segment::types::PayloadSchemaType::Integer => PayloadSchemaType::Integer, | |
segment::types::PayloadSchemaType::Float => PayloadSchemaType::Float, | |
segment::types::PayloadSchemaType::Geo => PayloadSchemaType::Geo, | |
segment::types::PayloadSchemaType::Text => PayloadSchemaType::Text, | |
segment::types::PayloadSchemaType::Bool => PayloadSchemaType::Bool, | |
segment::types::PayloadSchemaType::Datetime => PayloadSchemaType::Datetime, | |
segment::types::PayloadSchemaType::Uuid => PayloadSchemaType::Uuid, | |
} | |
} | |
} | |
impl From<segment::types::PayloadSchemaType> for FieldType { | |
fn from(schema_type: segment::types::PayloadSchemaType) -> Self { | |
match schema_type { | |
segment::types::PayloadSchemaType::Keyword => FieldType::Keyword, | |
segment::types::PayloadSchemaType::Integer => FieldType::Integer, | |
segment::types::PayloadSchemaType::Float => FieldType::Float, | |
segment::types::PayloadSchemaType::Geo => FieldType::Geo, | |
segment::types::PayloadSchemaType::Text => FieldType::Text, | |
segment::types::PayloadSchemaType::Bool => FieldType::Bool, | |
segment::types::PayloadSchemaType::Datetime => FieldType::Datetime, | |
segment::types::PayloadSchemaType::Uuid => FieldType::Uuid, | |
} | |
} | |
} | |
impl TryFrom<TokenizerType> for segment::data_types::index::TokenizerType { | |
type Error = Status; | |
fn try_from(tokenizer_type: TokenizerType) -> Result<Self, Self::Error> { | |
match tokenizer_type { | |
TokenizerType::Unknown => Err(Status::invalid_argument("unknown tokenizer type")), | |
TokenizerType::Prefix => Ok(segment::data_types::index::TokenizerType::Prefix), | |
TokenizerType::Multilingual => { | |
Ok(segment::data_types::index::TokenizerType::Multilingual) | |
} | |
TokenizerType::Whitespace => Ok(segment::data_types::index::TokenizerType::Whitespace), | |
TokenizerType::Word => Ok(segment::data_types::index::TokenizerType::Word), | |
} | |
} | |
} | |
impl From<segment::types::PayloadSchemaParams> for PayloadIndexParams { | |
fn from(params: segment::types::PayloadSchemaParams) -> Self { | |
match params { | |
segment::types::PayloadSchemaParams::Keyword(p) => p.into(), | |
segment::types::PayloadSchemaParams::Integer(p) => p.into(), | |
segment::types::PayloadSchemaParams::Float(p) => p.into(), | |
segment::types::PayloadSchemaParams::Geo(p) => p.into(), | |
segment::types::PayloadSchemaParams::Text(p) => p.into(), | |
segment::types::PayloadSchemaParams::Bool(p) => p.into(), | |
segment::types::PayloadSchemaParams::Datetime(p) => p.into(), | |
segment::types::PayloadSchemaParams::Uuid(p) => p.into(), | |
} | |
} | |
} | |
impl TryFrom<KeywordIndexParams> for segment::data_types::index::KeywordIndexParams { | |
type Error = Status; | |
fn try_from(params: KeywordIndexParams) -> Result<Self, Self::Error> { | |
Ok(segment::data_types::index::KeywordIndexParams { | |
r#type: KeywordIndexType::Keyword, | |
is_tenant: params.is_tenant, | |
on_disk: params.on_disk, | |
}) | |
} | |
} | |
impl TryFrom<IntegerIndexParams> for segment::data_types::index::IntegerIndexParams { | |
type Error = Status; | |
fn try_from(params: IntegerIndexParams) -> Result<Self, Self::Error> { | |
Ok(segment::data_types::index::IntegerIndexParams { | |
r#type: IntegerIndexType::Integer, | |
lookup: params.lookup, | |
range: params.range, | |
is_principal: params.is_principal, | |
on_disk: params.on_disk, | |
}) | |
} | |
} | |
impl TryFrom<FloatIndexParams> for segment::data_types::index::FloatIndexParams { | |
type Error = Status; | |
fn try_from(params: FloatIndexParams) -> Result<Self, Self::Error> { | |
Ok(segment::data_types::index::FloatIndexParams { | |
r#type: FloatIndexType::Float, | |
on_disk: params.on_disk, | |
is_principal: params.is_principal, | |
}) | |
} | |
} | |
impl TryFrom<GeoIndexParams> for segment::data_types::index::GeoIndexParams { | |
type Error = Status; | |
fn try_from(params: GeoIndexParams) -> Result<Self, Self::Error> { | |
Ok(segment::data_types::index::GeoIndexParams { | |
r#type: GeoIndexType::Geo, | |
on_disk: params.on_disk, | |
}) | |
} | |
} | |
impl TryFrom<TextIndexParams> for segment::data_types::index::TextIndexParams { | |
type Error = Status; | |
fn try_from(params: TextIndexParams) -> Result<Self, Self::Error> { | |
Ok(segment::data_types::index::TextIndexParams { | |
r#type: TextIndexType::Text, | |
tokenizer: TokenizerType::try_from(params.tokenizer) | |
.map(|x| x.try_into()) | |
.unwrap_or_else(|_| Err(Status::invalid_argument("unknown tokenizer type")))?, | |
lowercase: params.lowercase, | |
min_token_len: params.min_token_len.map(|x| x as usize), | |
max_token_len: params.max_token_len.map(|x| x as usize), | |
on_disk: params.on_disk, | |
}) | |
} | |
} | |
impl TryFrom<BoolIndexParams> for segment::data_types::index::BoolIndexParams { | |
type Error = Status; | |
fn try_from(_params: BoolIndexParams) -> Result<Self, Self::Error> { | |
Ok(segment::data_types::index::BoolIndexParams { | |
r#type: BoolIndexType::Bool, | |
}) | |
} | |
} | |
impl TryFrom<DatetimeIndexParams> for segment::data_types::index::DatetimeIndexParams { | |
type Error = Status; | |
fn try_from(params: DatetimeIndexParams) -> Result<Self, Self::Error> { | |
Ok(segment::data_types::index::DatetimeIndexParams { | |
r#type: DatetimeIndexType::Datetime, | |
on_disk: params.on_disk, | |
is_principal: params.is_principal, | |
}) | |
} | |
} | |
impl TryFrom<UuidIndexParams> for segment::data_types::index::UuidIndexParams { | |
type Error = Status; | |
fn try_from(params: UuidIndexParams) -> Result<Self, Self::Error> { | |
Ok(segment::data_types::index::UuidIndexParams { | |
r#type: UuidIndexType::Uuid, | |
is_tenant: params.is_tenant, | |
on_disk: params.on_disk, | |
}) | |
} | |
} | |
impl TryFrom<IndexParams> for segment::types::PayloadSchemaParams { | |
type Error = Status; | |
fn try_from(value: IndexParams) -> Result<Self, Self::Error> { | |
Ok(match value { | |
IndexParams::KeywordIndexParams(p) => { | |
segment::types::PayloadSchemaParams::Keyword(p.try_into()?) | |
} | |
IndexParams::IntegerIndexParams(p) => { | |
segment::types::PayloadSchemaParams::Integer(p.try_into()?) | |
} | |
IndexParams::FloatIndexParams(p) => { | |
segment::types::PayloadSchemaParams::Float(p.try_into()?) | |
} | |
IndexParams::GeoIndexParams(p) => { | |
segment::types::PayloadSchemaParams::Geo(p.try_into()?) | |
} | |
IndexParams::TextIndexParams(p) => { | |
segment::types::PayloadSchemaParams::Text(p.try_into()?) | |
} | |
IndexParams::BoolIndexParams(p) => { | |
segment::types::PayloadSchemaParams::Bool(p.try_into()?) | |
} | |
IndexParams::DatetimeIndexParams(p) => { | |
segment::types::PayloadSchemaParams::Datetime(p.try_into()?) | |
} | |
IndexParams::UuidIndexParams(p) => { | |
segment::types::PayloadSchemaParams::Uuid(p.try_into()?) | |
} | |
}) | |
} | |
} | |
impl TryFrom<PayloadSchemaInfo> for segment::types::PayloadIndexInfo { | |
type Error = Status; | |
fn try_from(schema: PayloadSchemaInfo) -> Result<Self, Self::Error> { | |
let data_type = match PayloadSchemaType::try_from(schema.data_type) { | |
Err(_) => { | |
return Err(Status::invalid_argument( | |
"Malformed payload schema".to_string(), | |
)); | |
} | |
Ok(data_type) => match data_type { | |
PayloadSchemaType::Keyword => segment::types::PayloadSchemaType::Keyword, | |
PayloadSchemaType::Integer => segment::types::PayloadSchemaType::Integer, | |
PayloadSchemaType::Float => segment::types::PayloadSchemaType::Float, | |
PayloadSchemaType::Geo => segment::types::PayloadSchemaType::Geo, | |
PayloadSchemaType::Text => segment::types::PayloadSchemaType::Text, | |
PayloadSchemaType::Bool => segment::types::PayloadSchemaType::Bool, | |
PayloadSchemaType::Datetime => segment::types::PayloadSchemaType::Datetime, | |
PayloadSchemaType::UnknownType => { | |
return Err(Status::invalid_argument( | |
"Malformed payload schema".to_string(), | |
)); | |
} | |
PayloadSchemaType::Uuid => segment::types::PayloadSchemaType::Uuid, | |
}, | |
}; | |
let params = match schema.params { | |
None => None, | |
Some(PayloadIndexParams { index_params: None }) => None, | |
Some(PayloadIndexParams { | |
index_params: Some(index_params), | |
}) => Some(index_params.try_into()?), | |
}; | |
Ok(segment::types::PayloadIndexInfo { | |
data_type, | |
params, | |
points: schema.points.unwrap_or(0) as usize, | |
}) | |
} | |
} | |
impl From<(Instant, bool)> for CollectionOperationResponse { | |
fn from(value: (Instant, bool)) -> Self { | |
let (timing, result) = value; | |
CollectionOperationResponse { | |
result, | |
time: timing.elapsed().as_secs_f64(), | |
} | |
} | |
} | |
impl From<segment::types::GeoPoint> for GeoPoint { | |
fn from(geo: segment::types::GeoPoint) -> Self { | |
Self { | |
lon: geo.lon, | |
lat: geo.lat, | |
} | |
} | |
} | |
impl TryFrom<WithPayloadSelector> for segment::types::WithPayloadInterface { | |
type Error = Status; | |
fn try_from(value: WithPayloadSelector) -> Result<Self, Self::Error> { | |
match value.selector_options { | |
Some(options) => Ok(match options { | |
SelectorOptions::Enable(flag) => segment::types::WithPayloadInterface::Bool(flag), | |
SelectorOptions::Exclude(s) => segment::types::PayloadSelectorExclude::new( | |
s.fields | |
.iter() | |
.map(|i| json::json_path_from_proto(i)) | |
.collect::<Result<_, _>>()?, | |
) | |
.into(), | |
SelectorOptions::Include(s) => segment::types::PayloadSelectorInclude::new( | |
s.fields | |
.iter() | |
.map(|i| json::json_path_from_proto(i)) | |
.collect::<Result<_, _>>()?, | |
) | |
.into(), | |
}), | |
_ => Err(Status::invalid_argument("No PayloadSelector".to_string())), | |
} | |
} | |
} | |
impl From<segment::types::WithPayloadInterface> for WithPayloadSelector { | |
fn from(value: segment::types::WithPayloadInterface) -> Self { | |
let selector_options = match value { | |
segment::types::WithPayloadInterface::Bool(flag) => SelectorOptions::Enable(flag), | |
segment::types::WithPayloadInterface::Fields(fields) => { | |
SelectorOptions::Include(PayloadIncludeSelector { | |
fields: fields.iter().map(|f| f.to_string()).collect(), | |
}) | |
} | |
segment::types::WithPayloadInterface::Selector(selector) => match selector { | |
segment::types::PayloadSelector::Include(s) => { | |
SelectorOptions::Include(PayloadIncludeSelector { | |
fields: s.include.iter().map(|f| f.to_string()).collect(), | |
}) | |
} | |
segment::types::PayloadSelector::Exclude(s) => { | |
SelectorOptions::Exclude(PayloadExcludeSelector { | |
fields: s.exclude.iter().map(|f| f.to_string()).collect(), | |
}) | |
} | |
}, | |
}; | |
WithPayloadSelector { | |
selector_options: Some(selector_options), | |
} | |
} | |
} | |
impl From<QuantizationSearchParams> for segment::types::QuantizationSearchParams { | |
fn from(params: QuantizationSearchParams) -> Self { | |
Self { | |
ignore: params.ignore.unwrap_or(default_quantization_ignore_value()), | |
rescore: params.rescore, | |
oversampling: params.oversampling, | |
} | |
} | |
} | |
impl From<segment::types::QuantizationSearchParams> for QuantizationSearchParams { | |
fn from(params: segment::types::QuantizationSearchParams) -> Self { | |
Self { | |
ignore: Some(params.ignore), | |
rescore: params.rescore, | |
oversampling: params.oversampling, | |
} | |
} | |
} | |
impl From<SearchParams> for segment::types::SearchParams { | |
fn from(params: SearchParams) -> Self { | |
Self { | |
hnsw_ef: params.hnsw_ef.map(|x| x as usize), | |
exact: params.exact.unwrap_or(false), | |
quantization: params.quantization.map(|q| q.into()), | |
indexed_only: params.indexed_only.unwrap_or(false), | |
} | |
} | |
} | |
impl From<segment::types::SearchParams> for SearchParams { | |
fn from(params: segment::types::SearchParams) -> Self { | |
Self { | |
hnsw_ef: params.hnsw_ef.map(|x| x as u64), | |
exact: Some(params.exact), | |
quantization: params.quantization.map(|q| q.into()), | |
indexed_only: Some(params.indexed_only), | |
} | |
} | |
} | |
impl From<segment::types::PointIdType> for PointId { | |
fn from(point_id: segment::types::PointIdType) -> Self { | |
PointId { | |
point_id_options: Some(match point_id { | |
segment::types::PointIdType::NumId(num) => PointIdOptions::Num(num), | |
segment::types::PointIdType::Uuid(uuid) => PointIdOptions::Uuid(uuid.to_string()), | |
}), | |
} | |
} | |
} | |
impl TryFrom<PointStruct> for rest::PointStruct { | |
type Error = Status; | |
fn try_from(value: PointStruct) -> Result<Self, Self::Error> { | |
let PointStruct { | |
id, | |
vectors, | |
payload, | |
} = value; | |
// empty payload means None in PointStruct | |
let converted_payload = if payload.is_empty() { | |
None | |
} else { | |
Some(json::proto_to_payloads(payload)?) | |
}; | |
let vector_struct = match vectors { | |
None => return Err(Status::invalid_argument("Expected some vectors")), | |
Some(vectors) => rest::VectorStruct::try_from(vectors)?, | |
}; | |
Ok(Self { | |
id: id | |
.ok_or_else(|| Status::invalid_argument("Empty ID is not allowed"))? | |
.try_into()?, | |
vector: vector_struct, | |
payload: converted_payload, | |
}) | |
} | |
} | |
impl TryFrom<rest::Record> for RetrievedPoint { | |
type Error = OperationError; | |
fn try_from(record: rest::Record) -> Result<Self, Self::Error> { | |
let retrieved_point = Self { | |
id: Some(PointId::from(record.id)), | |
payload: record | |
.payload | |
.map(json::payload_to_proto) | |
.unwrap_or_default(), | |
vectors: record.vector.map(VectorsOutput::try_from).transpose()?, | |
shard_key: record.shard_key.map(convert_shard_key_to_grpc), | |
order_value: record.order_value.map(From::from), | |
}; | |
Ok(retrieved_point) | |
} | |
} | |
impl From<segment::data_types::order_by::OrderValue> for OrderValue { | |
fn from(value: segment::data_types::order_by::OrderValue) -> Self { | |
use segment::data_types::order_by as segment; | |
use crate::grpc::qdrant::order_value::Variant; | |
let variant = match value { | |
segment::OrderValue::Float(value) => Variant::Float(value), | |
segment::OrderValue::Int(value) => Variant::Int(value), | |
}; | |
Self { | |
variant: Some(variant), | |
} | |
} | |
} | |
impl TryFrom<OrderValue> for segment::data_types::order_by::OrderValue { | |
type Error = Status; | |
fn try_from(value: OrderValue) -> Result<Self, Self::Error> { | |
use segment::data_types::order_by as segment; | |
use crate::grpc::qdrant::order_value::Variant; | |
let variant = value.variant.ok_or_else(|| { | |
Status::invalid_argument("OrderedValue should have a variant".to_string()) | |
})?; | |
let value = match variant { | |
Variant::Float(value) => segment::OrderValue::Float(value), | |
Variant::Int(value) => segment::OrderValue::Int(value), | |
}; | |
Ok(value) | |
} | |
} | |
impl From<segment::types::ScoredPoint> for ScoredPoint { | |
fn from(point: segment::types::ScoredPoint) -> Self { | |
Self { | |
id: Some(PointId::from(point.id)), | |
payload: point | |
.payload | |
.map(json::payload_to_proto) | |
.unwrap_or_default(), | |
score: point.score, | |
version: point.version, | |
vectors: point.vector.map(VectorsOutput::from), | |
shard_key: point.shard_key.map(convert_shard_key_to_grpc), | |
order_value: point.order_value.map(OrderValue::from), | |
} | |
} | |
} | |
impl TryFrom<crate::rest::ScoredPoint> for ScoredPoint { | |
type Error = OperationError; | |
fn try_from(point: crate::rest::ScoredPoint) -> Result<Self, Self::Error> { | |
Ok(Self { | |
id: Some(PointId::from(point.id)), | |
payload: point | |
.payload | |
.map(json::payload_to_proto) | |
.unwrap_or_default(), | |
score: point.score, | |
version: point.version, | |
vectors: point.vector.map(VectorsOutput::try_from).transpose()?, | |
shard_key: point.shard_key.map(convert_shard_key_to_grpc), | |
order_value: point.order_value.map(OrderValue::from), | |
}) | |
} | |
} | |
impl From<segment::data_types::groups::GroupId> for GroupId { | |
fn from(key: segment::data_types::groups::GroupId) -> Self { | |
match key { | |
segment::data_types::groups::GroupId::String(str) => Self { | |
kind: Some(crate::grpc::qdrant::group_id::Kind::StringValue(str)), | |
}, | |
segment::data_types::groups::GroupId::NumberU64(n) => Self { | |
kind: Some(crate::grpc::qdrant::group_id::Kind::UnsignedValue(n)), | |
}, | |
segment::data_types::groups::GroupId::NumberI64(n) => Self { | |
kind: Some(crate::grpc::qdrant::group_id::Kind::IntegerValue(n)), | |
}, | |
} | |
} | |
} | |
impl TryFrom<NamedVectors> for HashMap<String, segment_vectors::VectorInternal> { | |
type Error = Status; | |
fn try_from(vectors: NamedVectors) -> Result<Self, Self::Error> { | |
vectors | |
.vectors | |
.into_iter() | |
.map( | |
|(name, vector)| match segment_vectors::VectorInternal::try_from(vector) { | |
Ok(vector) => Ok((name, vector)), | |
Err(err) => Err(err), | |
}, | |
) | |
.collect::<Result<_, _>>() | |
} | |
} | |
impl From<segment::types::WithVector> for WithVectorsSelector { | |
fn from(with_vectors: segment::types::WithVector) -> Self { | |
let selector_options = match with_vectors { | |
segment::types::WithVector::Bool(enabled) => { | |
with_vectors_selector::SelectorOptions::Enable(enabled) | |
} | |
segment::types::WithVector::Selector(include) => { | |
with_vectors_selector::SelectorOptions::Include(VectorsSelector { names: include }) | |
} | |
}; | |
Self { | |
selector_options: Some(selector_options), | |
} | |
} | |
} | |
impl From<WithVectorsSelector> for segment::types::WithVector { | |
fn from(with_vectors_selector: WithVectorsSelector) -> Self { | |
match with_vectors_selector.selector_options { | |
None => Self::default(), | |
Some(with_vectors_selector::SelectorOptions::Enable(enabled)) => Self::Bool(enabled), | |
Some(with_vectors_selector::SelectorOptions::Include(include)) => { | |
Self::Selector(include.names) | |
} | |
} | |
} | |
} | |
impl TryFrom<PointId> for segment::types::PointIdType { | |
type Error = Status; | |
fn try_from(value: PointId) -> Result<Self, Self::Error> { | |
match value.point_id_options { | |
Some(PointIdOptions::Num(num_id)) => Ok(segment::types::PointIdType::NumId(num_id)), | |
Some(PointIdOptions::Uuid(uui_str)) => Uuid::parse_str(&uui_str) | |
.map(segment::types::PointIdType::Uuid) | |
.map_err(|_err| { | |
Status::invalid_argument(format!("Unable to parse UUID: {uui_str}")) | |
}), | |
_ => Err(Status::invalid_argument( | |
"No ID options provided".to_string(), | |
)), | |
} | |
} | |
} | |
impl From<segment::types::ScalarQuantization> for ScalarQuantization { | |
fn from(value: segment::types::ScalarQuantization) -> Self { | |
let config = value.scalar; | |
ScalarQuantization { | |
r#type: match config.r#type { | |
segment::types::ScalarType::Int8 => { | |
crate::grpc::qdrant::QuantizationType::Int8 as i32 | |
} | |
}, | |
quantile: config.quantile, | |
always_ram: config.always_ram, | |
} | |
} | |
} | |
impl TryFrom<ScalarQuantization> for segment::types::ScalarQuantization { | |
type Error = Status; | |
fn try_from(value: ScalarQuantization) -> Result<Self, Self::Error> { | |
Ok(segment::types::ScalarQuantization { | |
scalar: segment::types::ScalarQuantizationConfig { | |
r#type: match QuantizationType::try_from(value.r#type).ok() { | |
Some(QuantizationType::Int8) => segment::types::ScalarType::Int8, | |
Some(QuantizationType::UnknownQuantization) | None => { | |
return Err(Status::invalid_argument("Unknown quantization type")); | |
} | |
}, | |
quantile: value.quantile, | |
always_ram: value.always_ram, | |
}, | |
}) | |
} | |
} | |
impl From<segment::types::ProductQuantization> for ProductQuantization { | |
fn from(value: segment::types::ProductQuantization) -> Self { | |
let config = value.product; | |
ProductQuantization { | |
compression: match config.compression { | |
segment::types::CompressionRatio::X4 => CompressionRatio::X4 as i32, | |
segment::types::CompressionRatio::X8 => CompressionRatio::X8 as i32, | |
segment::types::CompressionRatio::X16 => CompressionRatio::X16 as i32, | |
segment::types::CompressionRatio::X32 => CompressionRatio::X32 as i32, | |
segment::types::CompressionRatio::X64 => CompressionRatio::X64 as i32, | |
}, | |
always_ram: config.always_ram, | |
} | |
} | |
} | |
impl TryFrom<ProductQuantization> for segment::types::ProductQuantization { | |
type Error = Status; | |
fn try_from(value: ProductQuantization) -> Result<Self, Self::Error> { | |
Ok(segment::types::ProductQuantization { | |
product: segment::types::ProductQuantizationConfig { | |
compression: match CompressionRatio::try_from(value.compression) { | |
Err(_) => { | |
return Err(Status::invalid_argument( | |
"Unknown compression ratio".to_string(), | |
)); | |
} | |
Ok(CompressionRatio::X4) => segment::types::CompressionRatio::X4, | |
Ok(CompressionRatio::X8) => segment::types::CompressionRatio::X8, | |
Ok(CompressionRatio::X16) => segment::types::CompressionRatio::X16, | |
Ok(CompressionRatio::X32) => segment::types::CompressionRatio::X32, | |
Ok(CompressionRatio::X64) => segment::types::CompressionRatio::X64, | |
}, | |
always_ram: value.always_ram, | |
}, | |
}) | |
} | |
} | |
impl From<segment::types::BinaryQuantization> for BinaryQuantization { | |
fn from(value: segment::types::BinaryQuantization) -> Self { | |
let config = value.binary; | |
BinaryQuantization { | |
always_ram: config.always_ram, | |
} | |
} | |
} | |
impl TryFrom<BinaryQuantization> for segment::types::BinaryQuantization { | |
type Error = Status; | |
fn try_from(value: BinaryQuantization) -> Result<Self, Self::Error> { | |
Ok(segment::types::BinaryQuantization { | |
binary: segment::types::BinaryQuantizationConfig { | |
always_ram: value.always_ram, | |
}, | |
}) | |
} | |
} | |
impl From<segment::types::QuantizationConfig> for QuantizationConfig { | |
fn from(value: segment::types::QuantizationConfig) -> Self { | |
match value { | |
segment::types::QuantizationConfig::Scalar(scalar) => Self { | |
quantization: Some(super::qdrant::quantization_config::Quantization::Scalar( | |
scalar.into(), | |
)), | |
}, | |
segment::types::QuantizationConfig::Product(product) => Self { | |
quantization: Some(super::qdrant::quantization_config::Quantization::Product( | |
product.into(), | |
)), | |
}, | |
segment::types::QuantizationConfig::Binary(binary) => Self { | |
quantization: Some(super::qdrant::quantization_config::Quantization::Binary( | |
binary.into(), | |
)), | |
}, | |
} | |
} | |
} | |
impl TryFrom<QuantizationConfig> for segment::types::QuantizationConfig { | |
type Error = Status; | |
fn try_from(value: QuantizationConfig) -> Result<Self, Self::Error> { | |
let value = value | |
.quantization | |
.ok_or_else(|| Status::invalid_argument("Unable to convert quantization config"))?; | |
match value { | |
super::qdrant::quantization_config::Quantization::Scalar(config) => Ok( | |
segment::types::QuantizationConfig::Scalar(config.try_into()?), | |
), | |
super::qdrant::quantization_config::Quantization::Product(config) => Ok( | |
segment::types::QuantizationConfig::Product(config.try_into()?), | |
), | |
super::qdrant::quantization_config::Quantization::Binary(config) => Ok( | |
segment::types::QuantizationConfig::Binary(config.try_into()?), | |
), | |
} | |
} | |
} | |
impl From<segment::types::MultiVectorConfig> for MultiVectorConfig { | |
fn from(value: segment::types::MultiVectorConfig) -> Self { | |
Self { | |
comparator: MultiVectorComparator::from(value.comparator) as i32, | |
} | |
} | |
} | |
impl From<segment::types::MultiVectorComparator> for MultiVectorComparator { | |
fn from(value: segment::types::MultiVectorComparator) -> Self { | |
match value { | |
segment::types::MultiVectorComparator::MaxSim => MultiVectorComparator::MaxSim, | |
} | |
} | |
} | |
impl TryFrom<MultiVectorConfig> for segment::types::MultiVectorConfig { | |
type Error = Status; | |
fn try_from(value: MultiVectorConfig) -> Result<Self, Self::Error> { | |
let comparator = MultiVectorComparator::try_from(value.comparator) | |
.map_err(|_| Status::invalid_argument("Unknown multi vector comparator"))?; | |
Ok(segment::types::MultiVectorConfig { | |
comparator: segment::types::MultiVectorComparator::from(comparator), | |
}) | |
} | |
} | |
impl From<MultiVectorComparator> for segment::types::MultiVectorComparator { | |
fn from(value: MultiVectorComparator) -> Self { | |
match value { | |
MultiVectorComparator::MaxSim => segment::types::MultiVectorComparator::MaxSim, | |
} | |
} | |
} | |
fn conditions_helper_from_grpc( | |
conditions: Vec<Condition>, | |
) -> Result<Option<Vec<segment::types::Condition>>, tonic::Status> { | |
if conditions.is_empty() { | |
Ok(None) | |
} else { | |
let vec = conditions | |
.into_iter() | |
.map(|c| c.try_into()) | |
.collect::<Result<_, _>>()?; | |
Ok(Some(vec)) | |
} | |
} | |
fn conditions_helper_to_grpc(conditions: Option<Vec<segment::types::Condition>>) -> Vec<Condition> { | |
match conditions { | |
None => vec![], | |
Some(conditions) => { | |
if conditions.is_empty() { | |
vec![] | |
} else { | |
conditions | |
.into_iter() | |
.map(Condition::from) | |
.filter(|c| c.condition_one_of.is_some()) // Filter out empty conditions | |
.collect() | |
} | |
} | |
} | |
} | |
impl TryFrom<Filter> for segment::types::Filter { | |
type Error = Status; | |
fn try_from(value: Filter) -> Result<Self, Self::Error> { | |
Ok(Self { | |
should: conditions_helper_from_grpc(value.should)?, | |
min_should: { | |
match value.min_should { | |
Some(MinShould { | |
conditions, | |
min_count, | |
}) => Some(segment::types::MinShould { | |
conditions: conditions_helper_from_grpc(conditions) | |
.map(|conds| conds.unwrap_or_default())?, | |
min_count: min_count as usize, | |
}), | |
None => None, | |
} | |
}, | |
must: conditions_helper_from_grpc(value.must)?, | |
must_not: conditions_helper_from_grpc(value.must_not)?, | |
}) | |
} | |
} | |
impl From<segment::types::Filter> for Filter { | |
fn from(value: segment::types::Filter) -> Self { | |
Self { | |
should: conditions_helper_to_grpc(value.should), | |
min_should: { | |
if let Some(segment::types::MinShould { | |
conditions, | |
min_count, | |
}) = value.min_should | |
{ | |
Some(MinShould { | |
conditions: conditions_helper_to_grpc(Some(conditions)), | |
min_count: min_count as u64, | |
}) | |
} else { | |
None | |
} | |
}, | |
must: conditions_helper_to_grpc(value.must), | |
must_not: conditions_helper_to_grpc(value.must_not), | |
} | |
} | |
} | |
impl TryFrom<Condition> for segment::types::Condition { | |
type Error = Status; | |
fn try_from(value: Condition) -> Result<Self, Self::Error> { | |
if let Some(condition) = value.condition_one_of { | |
return match condition { | |
ConditionOneOf::Field(field) => { | |
Ok(segment::types::Condition::Field(field.try_into()?)) | |
} | |
ConditionOneOf::HasId(has_id) => { | |
Ok(segment::types::Condition::HasId(has_id.try_into()?)) | |
} | |
ConditionOneOf::Filter(filter) => { | |
Ok(segment::types::Condition::Filter(filter.try_into()?)) | |
} | |
ConditionOneOf::IsEmpty(is_empty) => { | |
Ok(segment::types::Condition::IsEmpty(is_empty.try_into()?)) | |
} | |
ConditionOneOf::IsNull(is_null) => { | |
Ok(segment::types::Condition::IsNull(is_null.try_into()?)) | |
} | |
ConditionOneOf::Nested(nested) => Ok(segment::types::Condition::Nested( | |
segment::types::NestedCondition::new(nested.try_into()?), | |
)), | |
ConditionOneOf::HasVector(has_vector) => Ok(segment::types::Condition::HasVector( | |
segment::types::HasVectorCondition { | |
has_vector: has_vector.has_vector, | |
}, | |
)), | |
}; | |
} | |
Err(Status::invalid_argument("Malformed Condition type")) | |
} | |
} | |
impl From<segment::types::Condition> for Condition { | |
fn from(value: segment::types::Condition) -> Self { | |
let condition_one_of = match value { | |
segment::types::Condition::Field(field) => { | |
Some(ConditionOneOf::Field(FieldCondition::from(field))) | |
} | |
segment::types::Condition::IsEmpty(is_empty) => { | |
Some(ConditionOneOf::IsEmpty(IsEmptyCondition::from(is_empty))) | |
} | |
segment::types::Condition::IsNull(is_null) => { | |
Some(ConditionOneOf::IsNull(IsNullCondition::from(is_null))) | |
} | |
segment::types::Condition::HasId(has_id) => { | |
Some(ConditionOneOf::HasId(HasIdCondition::from(has_id))) | |
} | |
segment::types::Condition::Filter(filter) => { | |
Some(ConditionOneOf::Filter(Filter::from(filter))) | |
} | |
segment::types::Condition::Nested(nested) => { | |
Some(ConditionOneOf::Nested(NestedCondition::from(nested.nested))) | |
} | |
// This type of condition should be only applied locally | |
// and never be sent to the other peers | |
segment::types::Condition::CustomIdChecker(_) => None, | |
segment::types::Condition::HasVector(has_vector) => { | |
Some(ConditionOneOf::HasVector(HasVectorCondition { | |
has_vector: has_vector.has_vector, | |
})) | |
} | |
}; | |
Self { condition_one_of } | |
} | |
} | |
impl TryFrom<NestedCondition> for segment::types::Nested { | |
type Error = Status; | |
fn try_from(value: NestedCondition) -> Result<Self, Self::Error> { | |
match value.filter { | |
None => Err(Status::invalid_argument( | |
"Nested condition must have a filter", | |
)), | |
Some(filter) => Ok(Self { | |
key: json::json_path_from_proto(&value.key)?, | |
filter: filter.try_into()?, | |
}), | |
} | |
} | |
} | |
impl From<segment::types::Nested> for NestedCondition { | |
fn from(value: segment::types::Nested) -> Self { | |
Self { | |
key: value.key.to_string(), | |
filter: Some(value.filter.into()), | |
} | |
} | |
} | |
impl TryFrom<IsEmptyCondition> for segment::types::IsEmptyCondition { | |
type Error = Status; | |
fn try_from(value: IsEmptyCondition) -> Result<Self, Status> { | |
Ok(segment::types::IsEmptyCondition { | |
is_empty: segment::types::PayloadField { | |
key: json::json_path_from_proto(&value.key)?, | |
}, | |
}) | |
} | |
} | |
impl From<segment::types::IsEmptyCondition> for IsEmptyCondition { | |
fn from(value: segment::types::IsEmptyCondition) -> Self { | |
Self { | |
key: value.is_empty.key.to_string(), | |
} | |
} | |
} | |
impl TryFrom<IsNullCondition> for segment::types::IsNullCondition { | |
type Error = Status; | |
fn try_from(value: IsNullCondition) -> Result<Self, Status> { | |
Ok(segment::types::IsNullCondition { | |
is_null: segment::types::PayloadField { | |
key: json::json_path_from_proto(&value.key)?, | |
}, | |
}) | |
} | |
} | |
impl From<segment::types::IsNullCondition> for IsNullCondition { | |
fn from(value: segment::types::IsNullCondition) -> Self { | |
Self { | |
key: value.is_null.key.to_string(), | |
} | |
} | |
} | |
impl TryFrom<HasIdCondition> for segment::types::HasIdCondition { | |
type Error = Status; | |
fn try_from(value: HasIdCondition) -> Result<Self, Self::Error> { | |
let set: HashSet<segment::types::PointIdType> = value | |
.has_id | |
.into_iter() | |
.map(|p| p.try_into()) | |
.collect::<Result<_, _>>()?; | |
Ok(Self { has_id: set }) | |
} | |
} | |
impl From<segment::types::HasIdCondition> for HasIdCondition { | |
fn from(value: segment::types::HasIdCondition) -> Self { | |
let set: Vec<PointId> = value.has_id.into_iter().map(|p| p.into()).collect(); | |
Self { has_id: set } | |
} | |
} | |
impl TryFrom<FieldCondition> for segment::types::FieldCondition { | |
type Error = Status; | |
fn try_from(value: FieldCondition) -> Result<Self, Self::Error> { | |
let FieldCondition { | |
key, | |
r#match, | |
range, | |
geo_bounding_box, | |
geo_radius, | |
values_count, | |
geo_polygon, | |
datetime_range, | |
} = value; | |
let geo_bounding_box = | |
geo_bounding_box.map_or_else(|| Ok(None), |g| g.try_into().map(Some))?; | |
let geo_radius = geo_radius.map_or_else(|| Ok(None), |g| g.try_into().map(Some))?; | |
let geo_polygon = geo_polygon.map_or_else(|| Ok(None), |g| g.try_into().map(Some))?; | |
let mut range = range.map(Into::into); | |
if range.is_none() { | |
range = datetime_range | |
.map(segment::types::RangeInterface::try_from) | |
.transpose()?; | |
} | |
Ok(Self { | |
key: json::json_path_from_proto(&key)?, | |
r#match: r#match.map_or_else(|| Ok(None), |m| m.try_into().map(Some))?, | |
range, | |
geo_bounding_box, | |
geo_radius, | |
geo_polygon, | |
values_count: values_count.map(Into::into), | |
}) | |
} | |
} | |
impl From<segment::types::FieldCondition> for FieldCondition { | |
fn from(value: segment::types::FieldCondition) -> Self { | |
let segment::types::FieldCondition { | |
key, | |
r#match, | |
range, | |
geo_bounding_box, | |
geo_radius, | |
geo_polygon, | |
values_count, | |
} = value; | |
let (range, datetime_range) = match range { | |
Some(segment::types::RangeInterface::Float(range)) => (Some(range.into()), None), | |
Some(segment::types::RangeInterface::DateTime(range)) => (None, Some(range.into())), | |
None => (None, None), | |
}; | |
Self { | |
key: key.to_string(), | |
r#match: r#match.map(Into::into), | |
range, | |
geo_bounding_box: geo_bounding_box.map(Into::into), | |
geo_radius: geo_radius.map(Into::into), | |
geo_polygon: geo_polygon.map(Into::into), | |
values_count: values_count.map(Into::into), | |
datetime_range, | |
} | |
} | |
} | |
impl TryFrom<GeoBoundingBox> for segment::types::GeoBoundingBox { | |
type Error = Status; | |
fn try_from(value: GeoBoundingBox) -> Result<Self, Self::Error> { | |
match value { | |
GeoBoundingBox { | |
top_left: Some(t), | |
bottom_right: Some(b), | |
} => Ok(Self { | |
top_left: t.into(), | |
bottom_right: b.into(), | |
}), | |
_ => Err(Status::invalid_argument("Malformed GeoBoundingBox type")), | |
} | |
} | |
} | |
impl From<segment::types::GeoBoundingBox> for GeoBoundingBox { | |
fn from(value: segment::types::GeoBoundingBox) -> Self { | |
Self { | |
top_left: Some(value.top_left.into()), | |
bottom_right: Some(value.bottom_right.into()), | |
} | |
} | |
} | |
impl TryFrom<GeoRadius> for segment::types::GeoRadius { | |
type Error = Status; | |
fn try_from(value: GeoRadius) -> Result<Self, Self::Error> { | |
match value { | |
GeoRadius { | |
center: Some(c), | |
radius, | |
} => Ok(Self { | |
center: c.into(), | |
radius: radius.into(), | |
}), | |
_ => Err(Status::invalid_argument("Malformed GeoRadius type")), | |
} | |
} | |
} | |
impl From<segment::types::GeoRadius> for GeoRadius { | |
fn from(value: segment::types::GeoRadius) -> Self { | |
Self { | |
center: Some(value.center.into()), | |
radius: value.radius as f32, // TODO lossy ok? | |
} | |
} | |
} | |
impl TryFrom<GeoPolygon> for segment::types::GeoPolygon { | |
type Error = Status; | |
fn try_from(value: GeoPolygon) -> Result<Self, Self::Error> { | |
match value { | |
GeoPolygon { | |
exterior: Some(e), | |
interiors, | |
} => Ok(Self { | |
exterior: e.into(), | |
interiors: Some(interiors.into_iter().map(Into::into).collect()), | |
}), | |
_ => Err(Status::invalid_argument( | |
"Malformed GeoPolygon type - field `exterior` is required", | |
)), | |
} | |
} | |
} | |
impl From<segment::types::GeoPolygon> for GeoPolygon { | |
fn from(value: segment::types::GeoPolygon) -> Self { | |
Self { | |
exterior: Some(value.exterior.into()), | |
interiors: value | |
.interiors | |
.unwrap_or_default() | |
.into_iter() | |
.map(Into::into) | |
.collect(), | |
} | |
} | |
} | |
impl From<GeoPoint> for segment::types::GeoPoint { | |
fn from(value: GeoPoint) -> Self { | |
Self { | |
lon: value.lon, | |
lat: value.lat, | |
} | |
} | |
} | |
impl From<GeoLineString> for segment::types::GeoLineString { | |
fn from(value: GeoLineString) -> Self { | |
Self { | |
points: value.points.into_iter().map(Into::into).collect(), | |
} | |
} | |
} | |
impl From<segment::types::GeoLineString> for GeoLineString { | |
fn from(value: segment::types::GeoLineString) -> Self { | |
Self { | |
points: value.points.into_iter().map(Into::into).collect(), | |
} | |
} | |
} | |
impl From<Range> for segment::types::Range<FloatPayloadType> { | |
fn from(value: Range) -> Self { | |
Self { | |
lt: value.lt, | |
gt: value.gt, | |
gte: value.gte, | |
lte: value.lte, | |
} | |
} | |
} | |
impl From<segment::types::Range<FloatPayloadType>> for Range { | |
fn from(value: segment::types::Range<FloatPayloadType>) -> Self { | |
Self { | |
lt: value.lt, | |
gt: value.gt, | |
gte: value.gte, | |
lte: value.lte, | |
} | |
} | |
} | |
impl From<Range> for segment::types::RangeInterface { | |
fn from(value: Range) -> Self { | |
Self::Float(value.into()) | |
} | |
} | |
impl TryFrom<DatetimeRange> for segment::types::RangeInterface { | |
type Error = Status; | |
fn try_from(value: DatetimeRange) -> Result<Self, Self::Error> { | |
Ok(Self::DateTime(segment::types::Range { | |
lt: value.lt.map(try_date_time_from_proto).transpose()?, | |
gt: value.gt.map(try_date_time_from_proto).transpose()?, | |
gte: value.gte.map(try_date_time_from_proto).transpose()?, | |
lte: value.lte.map(try_date_time_from_proto).transpose()?, | |
})) | |
} | |
} | |
impl From<segment::types::Range<DateTimePayloadType>> for DatetimeRange { | |
fn from(value: segment::types::Range<DateTimePayloadType>) -> Self { | |
Self { | |
lt: value.lt.map(date_time_to_proto), | |
gt: value.gt.map(date_time_to_proto), | |
gte: value.gte.map(date_time_to_proto), | |
lte: value.lte.map(date_time_to_proto), | |
} | |
} | |
} | |
impl From<ValuesCount> for segment::types::ValuesCount { | |
fn from(value: ValuesCount) -> Self { | |
Self { | |
lt: value.lt.map(|x| x as usize), | |
gt: value.gt.map(|x| x as usize), | |
gte: value.gte.map(|x| x as usize), | |
lte: value.lte.map(|x| x as usize), | |
} | |
} | |
} | |
impl From<segment::types::ValuesCount> for ValuesCount { | |
fn from(value: segment::types::ValuesCount) -> Self { | |
Self { | |
lt: value.lt.map(|x| x as u64), | |
gt: value.gt.map(|x| x as u64), | |
gte: value.gte.map(|x| x as u64), | |
lte: value.lte.map(|x| x as u64), | |
} | |
} | |
} | |
impl TryFrom<Match> for segment::types::Match { | |
type Error = Status; | |
fn try_from(value: Match) -> Result<Self, Self::Error> { | |
match value.match_value { | |
Some(mv) => Ok(match mv { | |
MatchValue::Keyword(kw) => kw.into(), | |
MatchValue::Integer(int) => int.into(), | |
MatchValue::Boolean(flag) => flag.into(), | |
MatchValue::Text(text) => segment::types::Match::Text(text.into()), | |
MatchValue::Keywords(kwds) => kwds.strings.into(), | |
MatchValue::Integers(ints) => ints.integers.into(), | |
MatchValue::ExceptIntegers(kwds) => { | |
segment::types::Match::Except(kwds.integers.into()) | |
} | |
MatchValue::ExceptKeywords(ints) => { | |
segment::types::Match::Except(ints.strings.into()) | |
} | |
}), | |
_ => Err(Status::invalid_argument("Malformed Match condition")), | |
} | |
} | |
} | |
impl From<segment::types::Match> for Match { | |
fn from(value: segment::types::Match) -> Self { | |
let match_value = match value { | |
segment::types::Match::Value(value) => match value.value { | |
segment::types::ValueVariants::String(kw) => MatchValue::Keyword(kw), | |
segment::types::ValueVariants::Integer(int) => MatchValue::Integer(int), | |
segment::types::ValueVariants::Bool(flag) => MatchValue::Boolean(flag), | |
}, | |
segment::types::Match::Text(segment::types::MatchText { text }) => { | |
MatchValue::Text(text) | |
} | |
segment::types::Match::Any(any) => match any.any { | |
segment::types::AnyVariants::Strings(strings) => { | |
let strings = strings.into_iter().collect(); | |
MatchValue::Keywords(RepeatedStrings { strings }) | |
} | |
segment::types::AnyVariants::Integers(integers) => { | |
let integers = integers.into_iter().collect(); | |
MatchValue::Integers(RepeatedIntegers { integers }) | |
} | |
}, | |
segment::types::Match::Except(except) => match except.except { | |
segment::types::AnyVariants::Strings(strings) => { | |
let strings = strings.into_iter().collect(); | |
MatchValue::ExceptKeywords(RepeatedStrings { strings }) | |
} | |
segment::types::AnyVariants::Integers(integers) => { | |
let integers = integers.into_iter().collect(); | |
MatchValue::ExceptIntegers(RepeatedIntegers { integers }) | |
} | |
}, | |
}; | |
Self { | |
match_value: Some(match_value), | |
} | |
} | |
} | |
impl From<Direction> for segment::data_types::order_by::Direction { | |
fn from(value: Direction) -> Self { | |
match value { | |
Direction::Asc => segment::data_types::order_by::Direction::Asc, | |
Direction::Desc => segment::data_types::order_by::Direction::Desc, | |
} | |
} | |
} | |
impl From<segment::data_types::order_by::Direction> for Direction { | |
fn from(value: segment::data_types::order_by::Direction) -> Self { | |
match value { | |
segment::data_types::order_by::Direction::Asc => Direction::Asc, | |
segment::data_types::order_by::Direction::Desc => Direction::Desc, | |
} | |
} | |
} | |
impl TryFrom<OrderBy> for segment::data_types::order_by::OrderBy { | |
type Error = Status; | |
fn try_from(value: OrderBy) -> Result<Self, Self::Error> { | |
use segment::data_types::order_by::StartFrom; | |
use crate::conversions::json; | |
use crate::grpc::qdrant::start_from::Value; | |
let direction = value | |
.direction | |
.and_then(|x| | |
// XXX: Invalid values silently converted to None | |
Direction::try_from(x).ok()) | |
.map(segment::data_types::order_by::Direction::from); | |
let start_from = value | |
.start_from | |
.and_then(|value| value.value) | |
.map(|v| -> Result<StartFrom, Status> { | |
match v { | |
Value::Integer(int) => Ok(StartFrom::Integer(int)), | |
Value::Float(float) => Ok(StartFrom::Float(float)), | |
Value::Timestamp(timestamp) => { | |
Ok(StartFrom::Datetime(try_date_time_from_proto(timestamp)?)) | |
} | |
Value::Datetime(datetime_str) => Ok(StartFrom::Datetime( | |
segment::types::DateTimeWrapper::from_str(&datetime_str).map_err(|e| { | |
Status::invalid_argument(format!("Malformed datetime: {e}")) | |
})?, | |
)), | |
} | |
}) | |
.transpose()?; | |
Ok(Self { | |
key: json::json_path_from_proto(&value.key)?, | |
direction, | |
start_from, | |
}) | |
} | |
} | |
impl From<segment::data_types::order_by::OrderBy> for OrderBy { | |
fn from(value: segment::data_types::order_by::OrderBy) -> Self { | |
Self { | |
key: value.key.to_string(), | |
direction: value.direction.map(|d| Direction::from(d) as i32), | |
start_from: value.start_from.map(|start_from| start_from.into()), | |
} | |
} | |
} | |
impl From<segment::data_types::order_by::StartFrom> for StartFrom { | |
fn from(value: segment::data_types::order_by::StartFrom) -> Self { | |
Self { | |
value: Some(match value { | |
segment::data_types::order_by::StartFrom::Integer(int) => { | |
start_from::Value::Integer(int) | |
} | |
segment::data_types::order_by::StartFrom::Float(float) => { | |
start_from::Value::Float(float) | |
} | |
segment::data_types::order_by::StartFrom::Datetime(datetime) => { | |
start_from::Value::Timestamp(date_time_to_proto(datetime)) | |
} | |
}), | |
} | |
} | |
} | |
impl From<HnswConfigDiff> for segment::types::HnswConfig { | |
fn from(hnsw_config: HnswConfigDiff) -> Self { | |
Self { | |
m: hnsw_config.m.unwrap_or_default() as usize, | |
ef_construct: hnsw_config.ef_construct.unwrap_or_default() as usize, | |
full_scan_threshold: hnsw_config.full_scan_threshold.unwrap_or_default() as usize, | |
max_indexing_threads: hnsw_config.max_indexing_threads.unwrap_or_default() as usize, | |
on_disk: hnsw_config.on_disk, | |
payload_m: hnsw_config.payload_m.map(|x| x as usize), | |
} | |
} | |
} | |
impl From<StrictModeConfig> for segment::types::StrictModeConfig { | |
fn from(value: StrictModeConfig) -> Self { | |
Self { | |
enabled: value.enabled, | |
max_query_limit: value.max_query_limit.map(|i| i as usize), | |
max_timeout: value.max_timeout.map(|i| i as usize), | |
unindexed_filtering_retrieve: value.unindexed_filtering_retrieve, | |
unindexed_filtering_update: value.unindexed_filtering_update, | |
search_max_hnsw_ef: value.search_max_hnsw_ef.map(|i| i as usize), | |
search_allow_exact: value.search_allow_exact, | |
search_max_oversampling: value.search_max_oversampling.map(f64::from), | |
} | |
} | |
} | |
impl From<segment::types::StrictModeConfig> for StrictModeConfig { | |
fn from(value: segment::types::StrictModeConfig) -> Self { | |
Self { | |
enabled: value.enabled, | |
max_query_limit: value.max_query_limit.map(|i| i as u32), | |
max_timeout: value.max_timeout.map(|i| i as u32), | |
unindexed_filtering_retrieve: value.unindexed_filtering_retrieve, | |
unindexed_filtering_update: value.unindexed_filtering_update, | |
search_max_hnsw_ef: value.search_max_hnsw_ef.map(|i| i as u32), | |
search_allow_exact: value.search_allow_exact, | |
search_max_oversampling: value.search_max_oversampling.map(|i| i as f32), | |
} | |
} | |
} | |
pub fn naive_date_time_to_proto(date_time: NaiveDateTime) -> prost_wkt_types::Timestamp { | |
prost_wkt_types::Timestamp { | |
seconds: date_time.and_utc().timestamp(), // number of non-leap seconds since the midnight on January 1, 1970. | |
nanos: date_time.nanosecond() as i32, | |
} | |
} | |
pub fn date_time_to_proto(date_time: DateTimePayloadType) -> prost_wkt_types::Timestamp { | |
naive_date_time_to_proto(date_time.0.naive_utc()) | |
} | |
pub fn try_date_time_from_proto( | |
date_time: prost_wkt_types::Timestamp, | |
) -> Result<DateTimePayloadType, Status> { | |
chrono::DateTime::from_timestamp(date_time.seconds, date_time.nanos.try_into().unwrap_or(0)) | |
.map(|date_time| date_time.into()) | |
.ok_or_else(|| Status::invalid_argument(format!("Unable to parse timestamp: {date_time}"))) | |
} | |
impl TryFrom<Distance> for segment::types::Distance { | |
type Error = Status; | |
fn try_from(value: Distance) -> Result<Self, Self::Error> { | |
Ok(match value { | |
Distance::UnknownDistance => { | |
return Err(Status::invalid_argument( | |
"Malformed distance parameter: UnknownDistance", | |
)); | |
} | |
Distance::Cosine => segment::types::Distance::Cosine, | |
Distance::Euclid => segment::types::Distance::Euclid, | |
Distance::Dot => segment::types::Distance::Dot, | |
Distance::Manhattan => segment::types::Distance::Manhattan, | |
}) | |
} | |
} | |
pub fn from_grpc_dist(dist: i32) -> Result<segment::types::Distance, Status> { | |
match Distance::try_from(dist) { | |
Err(_) => Err(Status::invalid_argument(format!( | |
"Malformed distance parameter, unexpected value: {dist}" | |
))), | |
Ok(grpc_distance) => Ok(grpc_distance.try_into()?), | |
} | |
} | |
pub fn into_named_vector_struct( | |
vector_name: Option<String>, | |
vector: segment_vectors::DenseVector, | |
indices: Option<SparseIndices>, | |
) -> Result<segment_vectors::NamedVectorStruct, Status> { | |
use segment_vectors::{NamedSparseVector, NamedVector, NamedVectorStruct}; | |
use sparse::common::sparse_vector::SparseVector; | |
Ok(match indices { | |
Some(indices) => NamedVectorStruct::Sparse(NamedSparseVector { | |
name: vector_name | |
.ok_or_else(|| Status::invalid_argument("Sparse vector must have a name"))?, | |
vector: SparseVector::new(indices.data, vector).map_err(|_| { | |
Status::invalid_argument("Sparse indices does not match sparse vector conditions") | |
})?, | |
}), | |
None => { | |
if let Some(vector_name) = vector_name { | |
NamedVectorStruct::Dense(NamedVector { | |
name: vector_name, | |
vector, | |
}) | |
} else { | |
NamedVectorStruct::Default(vector) | |
} | |
} | |
}) | |
} | |
impl From<PointsOperationResponseInternal> for PointsOperationResponse { | |
fn from(resp: PointsOperationResponseInternal) -> Self { | |
Self { | |
result: resp.result.map(Into::into), | |
time: resp.time, | |
} | |
} | |
} | |
// TODO: Make it explicit `from_operations_response` method instead of `impl From<PointsOperationResponse>`? | |
impl From<PointsOperationResponse> for PointsOperationResponseInternal { | |
fn from(resp: PointsOperationResponse) -> Self { | |
Self { | |
result: resp.result.map(Into::into), | |
time: resp.time, | |
} | |
} | |
} | |
impl From<UpdateResultInternal> for UpdateResult { | |
fn from(res: UpdateResultInternal) -> Self { | |
Self { | |
operation_id: res.operation_id, | |
status: res.status, | |
} | |
} | |
} | |
// TODO: Make it explicit `from_update_result` method instead of `impl From<UpdateResult>`? | |
impl From<UpdateResult> for UpdateResultInternal { | |
fn from(res: UpdateResult) -> Self { | |
Self { | |
operation_id: res.operation_id, | |
status: res.status, | |
clock_tag: None, | |
} | |
} | |
} | |
impl From<RecommendStrategy> for crate::rest::RecommendStrategy { | |
fn from(value: RecommendStrategy) -> Self { | |
match value { | |
RecommendStrategy::AverageVector => crate::rest::RecommendStrategy::AverageVector, | |
RecommendStrategy::BestScore => crate::rest::RecommendStrategy::BestScore, | |
} | |
} | |
} | |
impl TryFrom<i32> for crate::rest::RecommendStrategy { | |
type Error = Status; | |
fn try_from(value: i32) -> Result<Self, Self::Error> { | |
let strategy = RecommendStrategy::try_from(value).map_err(|_| { | |
Status::invalid_argument(format!("Unknown recommend strategy: {value}")) | |
})?; | |
Ok(strategy.into()) | |
} | |
} | |
impl From<segment_query::RecoQuery<segment_vectors::VectorInternal>> for raw_query::Recommend { | |
fn from(value: segment_query::RecoQuery<segment_vectors::VectorInternal>) -> Self { | |
Self { | |
positives: value.positives.into_iter().map(RawVector::from).collect(), | |
negatives: value.negatives.into_iter().map(RawVector::from).collect(), | |
} | |
} | |
} | |
impl TryFrom<raw_query::Recommend> for segment_query::RecoQuery<segment_vectors::VectorInternal> { | |
type Error = Status; | |
fn try_from(value: raw_query::Recommend) -> Result<Self, Self::Error> { | |
Ok(Self { | |
positives: value | |
.positives | |
.into_iter() | |
.map(segment_vectors::VectorInternal::try_from) | |
.try_collect()?, | |
negatives: value | |
.negatives | |
.into_iter() | |
.map(segment_vectors::VectorInternal::try_from) | |
.try_collect()?, | |
}) | |
} | |
} | |
impl From<segment_query::ContextPair<segment_vectors::VectorInternal>> | |
for raw_query::RawContextPair | |
{ | |
fn from(value: segment_query::ContextPair<segment_vectors::VectorInternal>) -> Self { | |
Self { | |
positive: Some(RawVector::from(value.positive)), | |
negative: Some(RawVector::from(value.negative)), | |
} | |
} | |
} | |
impl TryFrom<raw_query::RawContextPair> | |
for segment_query::ContextPair<segment_vectors::VectorInternal> | |
{ | |
type Error = Status; | |
fn try_from(value: raw_query::RawContextPair) -> Result<Self, Self::Error> { | |
Ok(Self { | |
positive: value | |
.positive | |
.map(segment_vectors::VectorInternal::try_from) | |
.transpose()? | |
.ok_or_else(|| { | |
Status::invalid_argument("No positive part of context pair provided") | |
})?, | |
negative: value | |
.negative | |
.map(segment_vectors::VectorInternal::try_from) | |
.transpose()? | |
.ok_or_else(|| { | |
Status::invalid_argument("No negative part of context pair provided") | |
})?, | |
}) | |
} | |
} | |
impl From<segment_query::ContextQuery<segment_vectors::VectorInternal>> for raw_query::Context { | |
fn from(value: segment_query::ContextQuery<segment_vectors::VectorInternal>) -> Self { | |
Self { | |
context: value.pairs.into_iter().map(RawContextPair::from).collect(), | |
} | |
} | |
} | |
impl TryFrom<raw_query::Context> for segment_query::ContextQuery<segment_vectors::VectorInternal> { | |
type Error = Status; | |
fn try_from(value: raw_query::Context) -> Result<Self, Self::Error> { | |
Ok(Self { | |
pairs: value | |
.context | |
.into_iter() | |
.map(segment_query::ContextPair::try_from) | |
.try_collect()?, | |
}) | |
} | |
} | |
impl From<segment_query::DiscoveryQuery<segment_vectors::VectorInternal>> for raw_query::Discovery { | |
fn from(value: segment_query::DiscoveryQuery<segment_vectors::VectorInternal>) -> Self { | |
Self { | |
target: Some(RawVector::from(value.target)), | |
context: value.pairs.into_iter().map(RawContextPair::from).collect(), | |
} | |
} | |
} | |
impl TryFrom<raw_query::Discovery> | |
for segment_query::DiscoveryQuery<segment_vectors::VectorInternal> | |
{ | |
type Error = Status; | |
fn try_from(value: raw_query::Discovery) -> Result<Self, Self::Error> { | |
Ok(Self { | |
target: value | |
.target | |
.map(segment_vectors::VectorInternal::try_from) | |
.transpose()? | |
.ok_or_else(|| Status::invalid_argument("No target provided"))?, | |
pairs: value | |
.context | |
.into_iter() | |
.map(segment_query::ContextPair::try_from) | |
.try_collect()?, | |
}) | |
} | |
} | |
impl TryFrom<SearchPoints> for rest::SearchRequestInternal { | |
type Error = Status; | |
fn try_from(value: SearchPoints) -> Result<Self, Self::Error> { | |
let named_struct = crate::grpc::conversions::into_named_vector_struct( | |
value.vector_name, | |
value.vector, | |
value.sparse_indices, | |
)?; | |
let vector = match named_struct { | |
segment_vectors::NamedVectorStruct::Default(v) => rest::NamedVectorStruct::Default(v), | |
segment_vectors::NamedVectorStruct::Dense(v) => rest::NamedVectorStruct::Dense(v), | |
segment_vectors::NamedVectorStruct::Sparse(v) => rest::NamedVectorStruct::Sparse(v), | |
segment_vectors::NamedVectorStruct::MultiDense(_) => { | |
return Err(Status::invalid_argument( | |
"MultiDense vector is not supported in search request", | |
)) | |
} | |
}; | |
Ok(Self { | |
vector, | |
filter: value.filter.map(|f| f.try_into()).transpose()?, | |
params: value.params.map(|p| p.into()), | |
limit: value.limit as usize, | |
offset: value.offset.map(|x| x as usize), | |
with_payload: value.with_payload.map(|wp| wp.try_into()).transpose()?, | |
with_vector: Some( | |
value | |
.with_vectors | |
.map(|with_vectors| with_vectors.into()) | |
.unwrap_or_default(), | |
), | |
score_threshold: value.score_threshold, | |
}) | |
} | |
} | |
impl TryFrom<SearchPointGroups> for rest::SearchGroupsRequestInternal { | |
type Error = Status; | |
fn try_from(value: SearchPointGroups) -> Result<Self, Self::Error> { | |
let search_points = SearchPoints { | |
vector: value.vector, | |
filter: value.filter, | |
params: value.params, | |
with_payload: value.with_payload, | |
with_vectors: value.with_vectors, | |
score_threshold: value.score_threshold, | |
vector_name: value.vector_name, | |
limit: 0, | |
offset: None, | |
collection_name: String::new(), | |
read_consistency: None, | |
timeout: None, | |
shard_key_selector: None, | |
sparse_indices: value.sparse_indices, | |
}; | |
if let Some(sparse_indices) = &search_points.sparse_indices { | |
validate_sparse_vector_impl(&sparse_indices.data, &search_points.vector).map_err( | |
|_| { | |
Status::invalid_argument( | |
"Sparse indices does not match sparse vector conditions", | |
) | |
}, | |
)?; | |
} | |
let rest::SearchRequestInternal { | |
vector, | |
filter, | |
params, | |
limit: _, | |
offset: _, | |
with_payload, | |
with_vector, | |
score_threshold, | |
} = search_points.try_into()?; | |
Ok(Self { | |
vector, | |
filter, | |
params, | |
with_payload, | |
with_vector, | |
score_threshold, | |
group_request: rest::BaseGroupRequest { | |
group_by: json::json_path_from_proto(&value.group_by)?, | |
limit: value.limit, | |
group_size: value.group_size, | |
with_lookup: value | |
.with_lookup | |
.map(rest::WithLookupInterface::try_from) | |
.transpose()?, | |
}, | |
}) | |
} | |
} | |
impl TryFrom<WithLookup> for rest::WithLookupInterface { | |
type Error = Status; | |
fn try_from(value: WithLookup) -> Result<Self, Self::Error> { | |
Ok(Self::WithLookup(value.try_into()?)) | |
} | |
} | |
impl TryFrom<WithLookup> for rest::WithLookup { | |
type Error = Status; | |
fn try_from(value: WithLookup) -> Result<Self, Self::Error> { | |
let with_default_payload = || Some(segment::types::WithPayloadInterface::Bool(true)); | |
Ok(Self { | |
collection_name: value.collection, | |
with_payload: value | |
.with_payload | |
.map(|wp| wp.try_into()) | |
.transpose()? | |
.or_else(with_default_payload), | |
with_vectors: value.with_vectors.map(|wv| wv.into()), | |
}) | |
} | |
} | |
impl From<LookupLocation> for rest::LookupLocation { | |
fn from(value: LookupLocation) -> Self { | |
Self { | |
collection: value.collection_name, | |
vector: value.vector_name, | |
shard_key: value.shard_key_selector.map(rest::ShardKeySelector::from), | |
} | |
} | |
} | |
impl TryFrom<FacetHitInternal> for segment_facets::FacetValueHit { | |
type Error = Status; | |
fn try_from(hit: FacetHitInternal) -> Result<Self, Self::Error> { | |
let value = hit | |
.value | |
.ok_or_else(|| Status::internal("expected FacetHit to have a value"))?; | |
Ok(Self { | |
value: segment_facets::FacetValue::try_from(value)?, | |
count: hit.count as usize, | |
}) | |
} | |
} | |
impl From<segment_facets::FacetValueHit> for FacetHitInternal { | |
fn from(hit: segment_facets::FacetValueHit) -> Self { | |
Self { | |
value: Some(From::from(hit.value)), | |
count: hit.count as u64, | |
} | |
} | |
} | |
impl From<segment_facets::FacetValueHit> for FacetHit { | |
fn from(hit: segment_facets::FacetValueHit) -> Self { | |
Self { | |
value: Some(hit.value.into()), | |
count: hit.count as u64, | |
} | |
} | |
} | |
impl TryFrom<FacetValueInternal> for segment_facets::FacetValue { | |
type Error = Status; | |
fn try_from(value: FacetValueInternal) -> Result<Self, Self::Error> { | |
use super::qdrant::facet_value_internal::Variant; | |
let variant = value | |
.variant | |
.ok_or_else(|| Status::internal("expected FacetValueInternal to have a value"))?; | |
Ok(match variant { | |
Variant::KeywordValue(value) => segment_facets::FacetValue::Keyword(value), | |
Variant::IntegerValue(value) => segment_facets::FacetValue::Int(value), | |
Variant::UuidValue(value) => { | |
let uuid_bytes: [u8; 16] = value.try_into().map_err(|_| { | |
Status::invalid_argument("Unable to parse UUID: expected 16 bytes") | |
})?; | |
segment_facets::FacetValue::Uuid(Uuid::from_bytes(uuid_bytes).as_u128()) | |
} | |
Variant::BoolValue(value) => segment_facets::FacetValue::Bool(value), | |
}) | |
} | |
} | |
impl From<segment_facets::FacetValue> for FacetValueInternal { | |
fn from(value: segment_facets::FacetValue) -> Self { | |
use super::qdrant::facet_value_internal::Variant; | |
Self { | |
variant: Some(match value { | |
segment_facets::FacetValue::Keyword(value) => Variant::KeywordValue(value), | |
segment_facets::FacetValue::Int(value) => Variant::IntegerValue(value), | |
segment_facets::FacetValue::Uuid(value) => { | |
let uuid = Uuid::from_u128(value); | |
Variant::UuidValue(uuid.as_bytes().to_vec()) | |
} | |
segment_facets::FacetValue::Bool(value) => Variant::BoolValue(value), | |
}), | |
} | |
} | |
} | |
impl From<segment_facets::FacetValue> for FacetValue { | |
fn from(value: segment_facets::FacetValue) -> Self { | |
use super::qdrant::facet_value::Variant; | |
Self { | |
variant: Some(match value { | |
segment_facets::FacetValue::Keyword(value) => Variant::StringValue(value), | |
segment_facets::FacetValue::Int(value) => Variant::IntegerValue(value), | |
segment_facets::FacetValue::Uuid(value) => { | |
Variant::StringValue(Uuid::from_u128(value).to_string()) | |
} | |
segment_facets::FacetValue::Bool(value) => Variant::BoolValue(value), | |
}), | |
} | |
} | |
} | |
impl From<rest::SearchMatrixPair> for SearchMatrixPair { | |
fn from(pair: rest::SearchMatrixPair) -> Self { | |
Self { | |
a: Some(pair.a.into()), | |
b: Some(pair.b.into()), | |
score: pair.score, | |
} | |
} | |
} | |
impl From<HwMeasurementAcc> for HardwareUsage { | |
fn from(value: HwMeasurementAcc) -> Self { | |
Self { | |
cpu: value.get_cpu() as u64, | |
} | |
} | |
} | |
impl From<HardwareUsage> for HardwareCounterCell { | |
fn from(value: HardwareUsage) -> Self { | |
let HardwareUsage { cpu } = value; | |
HardwareCounterCell::new_with(cpu as usize) | |
} | |
} | |