qdrant / rust-client Goto Github PK
View Code? Open in Web Editor NEWRust client for Qdrant vector search engine
Home Page: https://crates.io/crates/qdrant-client
License: Apache License 2.0
Rust client for Qdrant vector search engine
Home Page: https://crates.io/crates/qdrant-client
License: Apache License 2.0
Hello
I have some qdrant instances
first of them v1.6.1
second of them v1.5.1
Can I use this client v1.6.1 with qdrant v1.5.1?
Hello
https://github.com/qdrant/rust-client/blob/master/src/qdrant.rs#L183
ScalarQuantization
r#type
required i32
value
It is not clear.
Where can I find information?
Please add serde json support. Serializing de-serializing payload is extremely painful right now. There is a Value class that is included but there is no support for serializing from json string. Why reinvent the wheel when you can use serde json to do all of that easily. The Value pattern is exactly what serde json already uses for unstructured json data.
I have a Tauri (Rust) desktop app that uses a local qdrant for vector storage. Even after waiting for the gRPC channel message and a health check from the server I still get the following error when later in the code I'm trying to use my generated rust client object:
Err(status: Internal, message: "Failed to connect to http://localhost:6334/: transport error", details: [], metadata: MetadataMap { headers: {} })
Does anyone have any suggestions for what the issue might be? This only occurs on a subset of the machines I'm testing with.
The Filter conditions seem to have changed drastically compared to the example. There are now structs and enums instead of functions.
Specifically:
let search_result = client
.search_points(&SearchPoints {
collection_name: collection_name.into(),
vector: vec![11.; 10],
filter: Some(Filter::all([Condition::matches("bar", 12)])),
limit: 10,
..Default::default()
})
.await?;
Currently this crate uses anyhow
, which is usually meant for applications, not libraries. This makes it very hard to match on an error, because the error is essentially opaque. As far as I can see, we mostly return ´tonic::Status`, but there may be some APIs that also can return other errors.
The classic way of dealing with this is create a newtype that wraps Status, has a From<Status>
impl and allows basically the same functionality (especially matching on Code
). We could also create an enum
instead, but I should note that this will either make the implementation, the user interface or both needlessly complex. If we have API calls that can return other errors, either have them return their own specific error type or convert whatever error we get to our predefined error type internally.
Another way would be to make the error type opaque, but that has the downside of making it harder for users to implement From<QdrantError>
for their own error types, essentially requiring a Box
or other indirection.
Hey folks,
I'm creating a custom payload and committing data to Qdrant. The upsert operation works perfectly for about a thousand points, then gets blocked indefinitely. There was no debug information available to identify what could have gone wrong.
client
.upsert_points_blocking(COLLECTION_NAME, new, None)
.await
.map_err(|_| Box::new(CommitError::QdrantError))?;
Hi.
I see that you library uses anyhow lib for error handling.
Question.
Client has recoverable errors or all types of errors critical?
I am trying to check error when
I get anyhow::Error and can not split these cases.
I'm using Rust's client v1.9.0, and when I try to connect to the cloud cluster I get an error message:
status: Unimplemented, message: "grpc-status header missing, mapped from HTTP status code 404", details: [], metadata: MetadataMap { headers: {"date": "Wed, 15 May 2024 20:34:00 GMT", "vary": "Origin, Access-Control-Request-Method, Access-Control-Request-Headers", "content-length": "0"} }
Here's how I'm initializing the client:
let client_config = QdrantClientConfig::from_url(config.address.as_deref().unwrap_or("http://localhost:6334")).with_api_key(config.api_key.as_ref());
let client = QdrantClient::new(Some(client_config))?;
Sounds like this version of the SDK is not compatible. When CURLing the health endpoint, I get that the cluster is running on version 1.9.2
.
Hi there.
I am glad for the FastEmbed / python-client integration. I am a little bit surprised that you did not choose Rust for the job though.
I am new to the Rust language. I needed to construct a tool to manage real-time text search through on-the-fly embedding creation, and handle bulk product image uploads through image embedding creation. I built this one; RustEmbed inspiring from qdrant RustSearch example and clip-as-service-rs.
Though the code is quite beginner-level and amateurish, it functions effectively. I am diligently refining the codebase daily to enhance its robustness. This service will be integrated atop Qdrant for our upcoming search project at a fashion e-commerce company, which caters to over 7 million customers and experiences around 1 million+ daily sessions, so it's imperative that it operates seamlessly.
Here is the progress for RustEmbed;
What I am trying to say is, if you happen to decide on a Rust-based embedding service, and put together a team around it, I would gladly contribute.
The provided sample code in the readme file does not work.
cargo new
Does not compile.
Compiles successfully.
Background:
ChannelPool
is a struct for managing gRPC client connections, providing basic connection pooling functionality. While it already offers some useful features, there are potential improvements and extensions that could further enhance performance, stability, and maintainability.
Proposed Features:
Maximum Connection Limit: To prevent creating too many simultaneous connections, consider adding a maximum connection limit to the ChannelPool struct. Concurrent connection creation can be controlled using a Semaphore or other concurrency control structures.
Connection Expiration: Add an expiration time for each connection in the ChannelPool. Connections exceeding this duration would be automatically closed, ensuring connections don't remain open indefinitely.
I chose to implement these two features because they can significantly improve performance and reduce resource usage. Additionally, these features lay the groundwork for future improvements.
There are also any other features about ChannelPool
, for example :
Smarter Connection Recycling Strategy: The current implementation simply discards connections when they encounter errors. Implement a smarter recycling strategy, such as deciding when to close connections based on their usage frequency or idle time.
Connection Health Checks: Perform periodic health checks on connections to ensure that the connections in the pool are still functional. If unhealthy connections are discovered, remove them from the pool and create new connections as needed.
Connection Load Balancing: If connecting to a service with multiple backend instances, consider implementing connection load balancing. Choose between round-robin, least connections, or other load balancing strategies based on connection usage.
Detailed Error Handling and Logging: For easier debugging and troubleshooting, consider adding more detailed error handling and logging within the code.
Generics: The current implementation of the with_channel method requires a function returning a Result<T, Status>. Consider using a generic error type to make it more adaptable to different error handling requirements.
Currently, Qdrant server gRPC is able to receive and send gzip-ed traffic.
But in order to use this functionality, it should be also enabled on the client.
We should create an option on the client builder, which should allow us to enabled compressed traffic to the server.
Reference - https://docs.rs/tonic/latest/tonic/client/struct.Grpc.html#method.send_compressed
Hi, thanks for the rust client. However, I'm not sure how to work with qdrant_client::qdrant::Value
. I would like to convert back to a rust type. Please help.
Also, it would be really helpful if detailed examples (like how it is done for the python client) can be added for the rust client. Thanks!
Hello,
I have a bug in my implementation where no PointStructs that I define get upserted into the database.
The problem is that even with a "fresh" database, I get the error update operation failed and no vectors get added to the database. The error says "no existing vector name" but upsert should insert in that case, am I right ?
I have a function called insert_points
that converts a custom type I have to a PointStruct and attempts to upsert these pointstructs into the database. Each of the PointStructs has a NamedVector where the keys of the hashmap are.
So for example {"README": Vec<f32>, "README:0": Vec<f32>, "README:1": Vec<f32> }
.
This error did not happen when I did not use NamedVectors and simply used Vector.
The log is as follows
_ _
__ _ __| |_ __ __ _ _ __ | |_
/ _` |/ _` | '__/ _` | '_ \| __|
| (_| | (_| | | | (_| | | | | |_
\__, |\__,_|_| \__,_|_| |_|\__|
|_|
Access web UI at http://localhost:6333/dashboard
2023-11-21T12:40:26.652341Z INFO storage::content_manager::consensus::persistent: Initializing new raft state at ./storage/raft_state.json
2023-11-21T12:40:26.655909Z DEBUG storage::content_manager::consensus::persistent: State: Persistent { state: RaftState { hard_state: HardState { term: 0, vote: 0, commit: 0 }, conf_state: ConfState { voters: [834260950052035], learners: [], voters_outgoing: [], learners_next: [], auto_leave: false } }, latest_snapshot_meta: SnapshotMetadataSer { term: 0, index: 0 }, apply_progress_queue: EntryApplyProgressQueue(None), peer_address_by_id: RwLock { data: {} }, this_peer_id: 834260950052035, path: "./storage/raft_state.json", dirty: false }
2023-11-21T12:40:26.658803Z INFO qdrant: Distributed mode disabled
2023-11-21T12:40:26.658816Z INFO qdrant: Telemetry reporting disabled
2023-11-21T12:40:26.658911Z DEBUG qdrant: Waiting for thread web to finish
2023-11-21T12:40:26.659352Z INFO qdrant::actix: TLS disabled for REST API
2023-11-21T12:40:26.659491Z INFO qdrant::actix: Qdrant HTTP listening on 6333
2023-11-21T12:40:26.659500Z INFO actix_server::builder: Starting 11 workers
2023-11-21T12:40:26.659508Z INFO actix_server::server: Actix runtime found; starting in Actix runtime
2023-11-21T12:40:26.660786Z INFO qdrant::tonic: Qdrant gRPC listening on 6334
2023-11-21T12:40:26.660794Z INFO qdrant::tonic: TLS disabled for gRPC API
2023-11-21T12:41:10.265991Z DEBUG storage::content_manager::toc::collection_meta_ops: Creating collection fs
2023-11-21T12:41:10.372934Z DEBUG segment::vector_storage::simple_vector_storage: Segment vectors: 0
2023-11-21T12:41:10.372950Z DEBUG segment::vector_storage::simple_vector_storage: Estimated segment size 0 MB
2023-11-21T12:41:10.374026Z DEBUG segment::vector_storage::simple_vector_storage: Segment vectors: 0
2023-11-21T12:41:10.374035Z DEBUG segment::vector_storage::simple_vector_storage: Estimated segment size 0 MB
2023-11-21T12:41:10.422461Z DEBUG collection::collection: Changing shard fs:0 replica state from Some(Initializing) to Active
2023-11-21T12:41:10.422488Z DEBUG collection::shards::replica_set: Changing local shard fs:0 state from Some(Initializing) to Active
2023-11-21T12:41:17.285251Z WARN collection::collection_manager::collection_updater: Update operation declined: Wrong input: Not existing vector name error: README
2023-11-21T12:41:17.286326Z WARN collection::collection_manager::collection_updater: Update operation declined: Wrong input: Not existing vector name error: devin
2023-11-21T12:41:17.287908Z WARN collection::collection_manager::collection_updater: Update operation declined: Wrong input: Not existing vector name error: rivers:2
2023-11-21T12:41:17.289641Z WARN collection::collection_manager::collection_updater: Update operation declined: Wrong input: Not existing vector name error: O Captain:8
2023-11-21T12:41:17.291052Z WARN collection::collection_manager::collection_updater: Update operation declined: Wrong input: Not existing vector name error: goodbye:9
2023-11-21T12:41:17.291782Z WARN collection::collection_manager::collection_updater: Update operation declined: Wrong input: Not existing vector name error: man
2023-11-21T12:41:17.292444Z WARN collection::collection_manager::collection_updater: Update operation declined: Wrong input: Not existing vector name error: odyssey
E.g. in FieldCondition
, a new field geo_polygon
was added and a new parameter was added to upsert_points_blocking
.
I realize that this library's code is generated from the protobuf files which may complicate things. Still, what is the version compatibility policy for this crate? If possible, adhering to semver would be nice as all the Rust tooling assumes semver compatibility is kept (e.g. cargo upgrade
+ cargo update
will update from 1.3
to 1.7
in Cargo.lock
and break the build). Hence, I assume the version always needs to be pinned as of now. Thanks!
Set up client and a collection create request as per the pod readme:
let client = QdrantClient::from_url(QDRANT_DB_URL)
// using an env variable for the API KEY for example
.with_api_key(API_KEY)
.build()?;
Creating a collection:
client
.create_collection(&CreateCollection { collection_name: collection_name.into(),
vectors_config: Some(VectorsConfig {
config: Some (Config::Params(VectorParams {
size: 128,
distance: Distance::Euclid.into(),
..Default::default()
})),
}),
..Default::default()
}).await?;
The create_collection command fails with this error: Error: status: Unknown, message: "grpc-status header missing, mapped from HTTP status code 464", details: [], metadata: MetadataMap { headers: {"server": "awselb/2.0", "date": "Thu, 21 Sep 2023 23:57:02 GMT", "content-length": "0"} }
Hi!
I'm curious whether there's any intention of adding support of a local qdrant setup for Rust, like there is for Python3. I would love to use qdrant for a project I'm working on and it would definitely be a huge convenience!
from qdrant_client import QdrantClient
client = QdrantClient(path="path/to/db") # Persists changes to disk, fast prototyping
Thanks for building this awesome database!
Cheers.
Hello.
QdrantClient::new function has keyword async
.
I did not find await
in this function.
Why is it async
.
Thanks.
I noticed that the vectors only support f32
floats:
Lines 2037 to 2042 in cd7ee0f
and I ran into an issue attempting to load PointStruct
s that are of Vec<f64>
(using embeddings generated from an ollama rust client.
/// An embeddings generation response from Ollama.
#[derive(Debug, Deserialize, Clone)]
pub struct GenerateEmbeddingsResponse {
#[serde(rename = "embedding")]
#[allow(dead_code)]
pub embeddings: Vec<f64>,
}
Trying to use this vec f64
results in:
error[E0277]: the trait bound `qdrant_client::qdrant::Vectors: From<Vec<f64>>` is not satisfied
--> src/main.rs:99:42
|
99 | let point = vec![PointStruct::new(0, embedding_resp.embeddings, payload)];
| ---------------- ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<Vec<f64>>` is not implemented for `qdrant_client::qdrant::Vectors`
| |
| required by a bound introduced by this call
|
= help: the following other types implement trait `From<T>`:
<qdrant_client::qdrant::Vectors as From<HashMap<std::string::String, qdrant_client::qdrant::Vector>>>
<qdrant_client::qdrant::Vectors as From<HashMap<std::string::String, Vec<f32>>>>
<qdrant_client::qdrant::Vectors as From<HashMap<std::string::String, Vec<(u32, f32)>>>>
<qdrant_client::qdrant::Vectors as From<HashMap<std::string::String, &[(u32, f32)]>>>
<qdrant_client::qdrant::Vectors as From<Vec<f32>>>
= note: required for `Vec<f64>` to implement `Into<qdrant_client::qdrant::Vectors>`
note: required by a bound in `client::<impl qdrant_client::prelude::PointStruct>::new`
--> /home/jmcb/.cargo/registry/src/index.crates.io-6f17d22bba15001f/qdrant-client-1.8.0/src/client.rs:1927:54
|
1927 | pub fn new(id: impl Into<PointId>, vectors: impl Into<Vectors>, payload: Payload) -> Self {
| ^^^^^^^^^^^^^ required by this bound in `client::<impl PointStruct>::new`
For more information about this error, try `rustc --explain E0277`.
warning: `nvim-llama-qdrant-ctl` (bin "nvim-llama-qdrant-ctl") generated 1 warning
error: could not compile `nvim-llama-qdrant-ctl` (bin "nvim-llama-qdrant-ctl") due to 1 previous error; 1 warning emitted
let qdrant_client = QdrantClient::from_url("http://localhost:6334").build()?;
let collection_name = "test";
qdrant_client
.create_collection(&CreateCollection {
collection_name: collection_name.into(),
vectors_config: Some(VectorsConfig {
config: Some(Config::Params(VectorParams {
size: 384, // size of the all-minilm embeddings
distance: Distance::Cosine.into(),
..Default::default()
})),
}),
..Default::default()
})
.await?;
let ollama = Ollama::default();
let ollama = Ollama::new("http://localhost".to_string(), 11434);
Vec<f64>
let embedding_model = "all-minilm".to_string();
let embedding_prompt = "Woof woof, bark bark".to_string();
let embedding_resp = ollama
.generate_embeddings(embedding_model, embedding_prompt, None)
.await
.unwrap();
PointStruct
and notice error.let payload: Payload = json!(
{
"test": "this is a test",
}
)
.try_into()
.unwrap();
let point = vec![PointStruct::new(0, embedding_resp.embeddings, payload)];
client
.upsert_points_blocking(collection_name, None, point, None)
.await?;
Currently, update_collection()
only accepts the optimizers_config
parameter.
This is a problem as we've added new parameters in recent Qdrant versions. For example, updating vector parameters is currently impossible.
We should patch this to support all parameters as described here.
To prevent breaking changes in the current minor version we might have to add a second update_collection
function which supports all arguments. We can add the new arguments to the current function in 1.7.
cc @Anush008
Is it possible to start qdrant in-memory for testing? How do you guys test the client on CI?
cargo new test-qdrant-client
cargo add qdrant-client
cargo build
App builds successfully, prints Hello World
Build fails with message Error: Custom { kind: Other, error: "protoc failed: collections.proto:73:12: Explicit 'optional' labels are disallowed in the Proto3 syntax. To define 'optional' fields in Proto3, simply remove the 'optional' label, as fields are 'optional' by default.\n...
Identical behavior with rust stable (rustc 1.67.1) and rust nightly (rustc 1.69.0-nightly).
It is not derived from Clone
Hello!
Has not client supported cluster scaling API yet?
https://qdrant.tech/documentation/distributed_deployment/#cluster-scaling
OS: Windows11
rust(release ~308ms):
use anyhow::Result;
use qdrant_client::prelude::*;
#[actix_web::main]
async fn main() -> Result<()> {
let client = QdrantClientBuilder::default().build()?;
let collection_name = "test_collection";
let t = std::time::Instant::now();
client
.get_points(
collection_name,
None,
&[
"211b0f43-1b8d-4d12-9dd3-62aa0f07a8c6".to_owned().into(),
"bdd8a0a7-8f39-4b3e-9a92-7a8e2c6f0a4d".to_owned().into(),
"9cda8e6d-6e0f-4e33-8a6b-2e3b13d6a2e2".to_owned().into(),
"e9e6e4e9-3b69-4edf-9a5c-a9e8b4df8a66".to_owned().into(),
"4f80c7a1-4f7b-4c79-94a4-8e20c3f6a1e3".to_owned().into(),
"17b73663-3a8c-4e5d-9a7d-ec7bba2a8bcf".to_owned().into(),
],
Some(false),
Some(true),
None,
)
.await?;
println!("\n{:?}", t.elapsed());
Ok(())
}
python(~270ms):
from qdrant_client import QdrantClient
client = QdrantClient(prefer_grpc=True)
t = time.time()
client.retrieve(
"test_collection",
[
"211b0f43-1b8d-4d12-9dd3-62aa0f07a8c6",
"bdd8a0a7-8f39-4b3e-9a92-7a8e2c6f0a4d",
"9cda8e6d-6e0f-4e33-8a6b-2e3b13d6a2e2",
"e9e6e4e9-3b69-4edf-9a5c-a9e8b4df8a66",
"4f80c7a1-4f7b-4c79-94a4-8e20c3f6a1e3",
"17b73663-3a8c-4e5d-9a7d-ec7bba2a8bcf",
],
)
print(time.time() - t)
I know it's minor but I wonder is it related with Tonic
or client itself ?
We are attempting to use qdrant's full text filters in order to be able to move our filtering logic to solely qdrant, however we were facing issues with the fact that qdrant's rust client only support full text matching when there is a space added to the end.
We want to be able to use qdrant's full text and substring filtering as a replacement for the LIKE queries that we perform in pg as of rn, however, in certain cases where we have multi word filters or single word filters, the logic would behave unpredictably.
Here is a link the the gist that contains our filtering logic: https://gist.github.com/skeptrunedev/3ede217aa78d6462c5c52c63d0318764.
The easiest solution to this issue is probably adding a separate full text match function like python does.
Thank you so much for a first class rust client and an amazing SVD!!
eg:
vectors_config: Some(VectorsConfig { config: Some(Config::Params(VectorParams { size: 10, distance: Distance::Cosine.into(), hnsw_config: None, quantization_config: None, ****on_disk:None**** })),
Hey,
I'm encountering errors while trying to use the list_collections
method with the Qdrant Rust client. This error seems to be specific to the client as directly accessing the endpoint doesn't produce any issues.
Here are the specifics:
Err value: status: Unknown, message: "grpc-status header missing, mapped from HTTP status code 464", details: [],
metadata: MetadataMap { headers: {"server": "awselb/2.0", "date": "Tue, 25 Jul 2023 14:08:49 GMT", "content-length": "0"} }
Err value: status: Internal, message: "protocol error: received message with invalid
compression flag: 52 (valid flags are 0 and 1) while receiving response with status: 404 Not Found", details: [],
metadata: MetadataMap { headers: {"server": "awselb/2.0", "date": "Tue, 25 Jul 2023 15:21:54 GMT",
"content-type": "text/plain; charset=utf-8", "content-length": "19", "x-content-type-options": "nosniff"} }
I'm following the search example but using Qdrant Cloud
Any insights or suggestions to address this would be greatly appreciated.
How to support connection pool?
Fix all Clippy issues and setup CI to validate it.
Hi, according to the docs, it is possible to use range filtering on both float and integer payloads but the Range
client type can only hold f64 optional fields, i.e.:
Lines 2931 to 2940 in cd7ee0f
Clients don't have to be async, it's more the necessity for the server-side components. But this library forces a client to run inside an async runtime introducing unnecessary complexity for many cases.
I am a Rust user and I am becoming a qdrant fan. I want to use qdrant in a production project with Rust. Unfortunately I miss a beter documentation where not only examples but possibilities and how to use types are covered.
Wich are the available features of the crate, what does each function does, what each type does and how to create them from other common types like vectors and serde_json::Value, these are just some examples of questions that could be answered in a beter documentation.
I would like to help with that, but I will need the help of the developers to create that.
The cluster manager allows developers to copy a cluster's URL into the clipboard. That is convenient. If this URL is used with the Rust client, it does not work. It results in a 464 (incompatible protocol) error. As a developer, you have to add :6334
to the URL to make it work. It would be helpful to have a hint in the cluster manager and/or the Rust client docs that this is important.
Kind request for people considering to try qdrant with Rust programs.
Could you create more tutorials and examples that illustrate also how to use rust-client together e.g. with https://github.com/pepperoni21/ollama-rs generated embeddings, and other potential libraries/solutions?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.