Skip to main content

qdrant_client/qdrant_client/
search.rs

1use crate::qdrant::{
2    DiscoverBatchPoints, DiscoverBatchResponse, DiscoverPoints, DiscoverResponse,
3    RecommendBatchPoints, RecommendBatchResponse, RecommendGroupsResponse, RecommendPointGroups,
4    RecommendPoints, RecommendResponse, SearchBatchPoints, SearchBatchResponse,
5    SearchGroupsResponse, SearchPointGroups, SearchPoints, SearchResponse,
6};
7use crate::qdrant_client::{Qdrant, QdrantResult};
8
9/// # Search operations
10///
11/// <div class="warning">
12/// For searching, please switch to the more fully featured <a href="#query-operations">Query API</a> instead. The search API will be removed in the future.
13/// </div>
14///
15/// Search and explore points.
16///
17/// Documentation: <https://qdrant.tech/documentation/concepts/search/>
18impl Qdrant {
19    /// Search points in a collection.
20    ///
21    /// ```no_run
22    ///# use qdrant_client::{Qdrant, QdrantError};
23    /// use qdrant_client::qdrant::{Condition, Filter, SearchParamsBuilder, SearchPointsBuilder};
24    ///
25    ///# async fn search_points(client: &Qdrant)
26    ///# -> Result<(), QdrantError> {
27    /// client
28    ///     .search_points(
29    ///         SearchPointsBuilder::new("my_collection", vec![0.2, 0.1, 0.9, 0.7], 3)
30    ///             .filter(Filter::must([Condition::matches(
31    ///                 "city",
32    ///                 "London".to_string(),
33    ///             )]))
34    ///             .params(SearchParamsBuilder::default().hnsw_ef(128).exact(false)),
35    ///     )
36    ///     .await?;
37    ///# Ok(())
38    ///# }
39    /// ```
40    ///
41    /// Documentation: <https://qdrant.tech/documentation/concepts/search/#search-api>
42    pub async fn search_points(
43        &self,
44        request: impl Into<SearchPoints>,
45    ) -> QdrantResult<SearchResponse> {
46        let request = &request.into();
47
48        self.with_points_client(|mut points_api| async move {
49            let result = points_api.search(request.clone()).await?;
50            Ok(result.into_inner())
51        })
52        .await
53    }
54
55    /// Batch multiple points searches in a collection.
56    ///
57    /// ```no_run
58    ///# use qdrant_client::{Qdrant, QdrantError};
59    /// use qdrant_client::qdrant::{Condition, Filter, SearchBatchPointsBuilder, SearchPointsBuilder,};
60    ///
61    ///# async fn search_batch_points(client: &Qdrant)
62    ///# -> Result<(), QdrantError> {
63    /// let filter = Filter::must([Condition::matches("city", "London".to_string())]);
64    ///
65    /// let searches = vec![
66    ///     SearchPointsBuilder::new("my_collection", vec![0.2, 0.1, 0.9, 0.7], 3)
67    ///         .filter(filter.clone())
68    ///         .build(),
69    ///     SearchPointsBuilder::new("my_collection", vec![0.5, 0.3, 0.2, 0.3], 3)
70    ///         .filter(filter)
71    ///         .build(),
72    /// ];
73    ///
74    /// client
75    ///     .search_batch_points(SearchBatchPointsBuilder::new("my_collection", searches))
76    ///     .await?;
77    ///# Ok(())
78    ///# }
79    /// ```
80    ///
81    /// Documentation: <https://qdrant.tech/documentation/concepts/search/#batch-search-api>
82    pub async fn search_batch_points(
83        &self,
84        request: impl Into<SearchBatchPoints>,
85    ) -> QdrantResult<SearchBatchResponse> {
86        let request = &request.into();
87
88        self.with_points_client(|mut points_api| async move {
89            let result = points_api.search_batch(request.clone()).await?;
90            Ok(result.into_inner())
91        })
92        .await
93    }
94
95    /// Search points in a collection and group results by a payload field.
96    ///
97    /// ```no_run
98    ///# use qdrant_client::{Qdrant, QdrantError};
99    /// use qdrant_client::qdrant::SearchPointGroupsBuilder;
100    ///
101    ///# async fn search_points(client: &Qdrant)
102    ///# -> Result<(), QdrantError> {
103    /// client
104    ///     .search_groups(SearchPointGroupsBuilder::new(
105    ///         "my_collection", // Collection name
106    ///         vec![1.1],       // Search vector
107    ///         4,               // Search limit
108    ///         "document_id",   // Group by field
109    ///         2,               // Group size
110    ///     ))
111    ///     .await?;
112    ///# Ok(())
113    ///# }
114    /// ```
115    ///
116    /// Documentation: <https://qdrant.tech/documentation/concepts/search/#search-groups>
117    pub async fn search_groups(
118        &self,
119        request: impl Into<SearchPointGroups>,
120    ) -> QdrantResult<SearchGroupsResponse> {
121        let request = &request.into();
122
123        self.with_points_client(|mut points_api| async move {
124            let result = points_api.search_groups(request.clone()).await?;
125            Ok(result.into_inner())
126        })
127        .await
128    }
129
130    /// Recommend points in a collection.
131    ///
132    /// ```no_run
133    ///# use qdrant_client::{Qdrant, QdrantError};
134    /// use qdrant_client::qdrant::{Condition, Filter, RecommendPointsBuilder, RecommendStrategy};
135    ///
136    ///# async fn recommend(client: &Qdrant)
137    ///# -> Result<(), QdrantError> {
138    /// client
139    ///     .recommend(
140    ///         RecommendPointsBuilder::new("my_collection", 3)
141    ///             .add_positive(100)
142    ///             .add_positive(200)
143    ///             .add_positive(vec![100.0, 231.0])
144    ///             .add_negative(718)
145    ///             .add_negative(vec![0.2, 0.3, 0.4, 0.5])
146    ///             .strategy(RecommendStrategy::AverageVector)
147    ///             .filter(Filter::must([Condition::matches(
148    ///                 "city",
149    ///                 "London".to_string(),
150    ///             )])),
151    ///     )
152    ///     .await?;
153    ///# Ok(())
154    ///# }
155    /// ```
156    ///
157    /// Documentation: <https://qdrant.tech/documentation/concepts/explore/#recommendation-api>
158    pub async fn recommend(
159        &self,
160        request: impl Into<RecommendPoints>,
161    ) -> QdrantResult<RecommendResponse> {
162        let request = &request.into();
163
164        self.with_points_client(|mut points_api| async move {
165            let result = points_api.recommend(request.clone()).await?;
166            Ok(result.into_inner())
167        })
168        .await
169    }
170
171    /// Batch multiple points recommendations in a collection.
172    ///
173    /// ```no_run
174    ///# use qdrant_client::{Qdrant, QdrantError};
175    /// use qdrant_client::qdrant::{Condition, Filter, RecommendBatchPointsBuilder, RecommendPointsBuilder};
176    ///
177    ///# async fn recommend_batch(client: &Qdrant)
178    ///# -> Result<(), QdrantError> {
179    /// let filter = Filter::must([Condition::matches("city", "London".to_string())]);
180    ///
181    /// let recommend_queries = vec![
182    ///     RecommendPointsBuilder::new("my_collection", 3)
183    ///         .add_positive(100)
184    ///         .add_positive(231)
185    ///         .add_negative(718)
186    ///         .filter(filter.clone())
187    ///         .build(),
188    ///     RecommendPointsBuilder::new("my_collection", 3)
189    ///         .add_positive(200)
190    ///         .add_positive(67)
191    ///         .add_negative(300)
192    ///         .filter(filter.clone())
193    ///         .build(),
194    /// ];
195    ///
196    /// client
197    ///     .recommend_batch(RecommendBatchPointsBuilder::new(
198    ///         "my_collection",
199    ///         recommend_queries,
200    ///     ))
201    ///     .await?;
202    ///# Ok(())
203    ///# }
204    /// ```
205    ///
206    /// Documentation: <https://qdrant.tech/documentation/concepts/explore/#batch-recommendation-api>
207    pub async fn recommend_batch(
208        &self,
209        request: impl Into<RecommendBatchPoints>,
210    ) -> QdrantResult<RecommendBatchResponse> {
211        let request = &request.into();
212
213        self.with_points_client(|mut points_api| async move {
214            let result = points_api.recommend_batch(request.clone()).await?;
215            Ok(result.into_inner())
216        })
217        .await
218    }
219
220    /// Recommend points in a collection and group results by a payload field.
221    ///
222    /// ```no_run
223    ///# use qdrant_client::{Qdrant, QdrantError};
224    /// use qdrant_client::qdrant::{RecommendPointGroupsBuilder, RecommendStrategy};
225    ///
226    ///# async fn recommend_groups(client: &Qdrant)
227    ///# -> Result<(), QdrantError> {
228    /// client
229    ///     .recommend_groups(
230    ///         RecommendPointGroupsBuilder::new(
231    ///             "my_collection", // Collection name
232    ///             "document_id",   // Group by field
233    ///             2,               // Group size
234    ///             3,               // Search limit
235    ///         )
236    ///         .add_positive(100)
237    ///         .add_positive(200)
238    ///         .add_negative(718)
239    ///         .strategy(RecommendStrategy::AverageVector),
240    ///     )
241    ///     .await?;
242    ///# Ok(())
243    ///# }
244    /// ```
245    ///
246    /// Documentation: <https://qdrant.tech/documentation/concepts/explore/#recommendation-api>
247    pub async fn recommend_groups(
248        &self,
249        request: impl Into<RecommendPointGroups>,
250    ) -> QdrantResult<RecommendGroupsResponse> {
251        let request = &request.into();
252
253        self.with_points_client(|mut points_api| async move {
254            let result = points_api.recommend_groups(request.clone()).await?;
255            Ok(result.into_inner())
256        })
257        .await
258    }
259
260    /// Discover points in a collection.
261    ///
262    /// ```no_run
263    ///# use qdrant_client::{Qdrant, QdrantError};
264    /// use qdrant_client::qdrant::{
265    ///     target_vector::Target, vector_example::Example, ContextExamplePairBuilder,
266    ///     DiscoverPointsBuilder, VectorExample,
267    /// };
268    ///
269    ///# async fn discover(client: &Qdrant)
270    ///# -> Result<(), QdrantError> {
271    /// client
272    ///     .discover(
273    ///         DiscoverPointsBuilder::new(
274    ///             "my_collection", // Collection name
275    ///             vec![
276    ///                 ContextExamplePairBuilder::default()
277    ///                     .positive(Example::Id(100.into()))
278    ///                     .negative(Example::Id(718.into()))
279    ///                     .build(),
280    ///                 ContextExamplePairBuilder::default()
281    ///                     .positive(Example::Id(200.into()))
282    ///                     .negative(Example::Id(300.into()))
283    ///                     .build(),
284    ///             ],
285    ///             10,              // Search limit
286    ///         )
287    ///         .target(Target::Single(VectorExample {
288    ///             example: Some(Example::Vector(vec![0.2, 0.1, 0.9, 0.7].into())),
289    ///         })),
290    ///     )
291    ///     .await?;
292    ///# Ok(())
293    ///# }
294    /// ```
295    ///
296    /// Documentation: <https://qdrant.tech/documentation/concepts/explore/#discovery-api>
297    pub async fn discover(
298        &self,
299        request: impl Into<DiscoverPoints>,
300    ) -> QdrantResult<DiscoverResponse> {
301        let request = &request.into();
302
303        self.with_points_client(|mut points_api| async move {
304            let result = points_api.discover(request.clone()).await?;
305            Ok(result.into_inner())
306        })
307        .await
308    }
309
310    /// Batch multiple point discoveries in a collection.
311    ///
312    /// ```no_run
313    ///# use qdrant_client::{Qdrant, QdrantError};
314    /// use qdrant_client::qdrant::{
315    ///     vector_example::Example, ContextExamplePairBuilder, DiscoverBatchPointsBuilder,
316    ///     DiscoverPointsBuilder,
317    /// };
318    ///
319    ///# async fn discover_batch(client: &Qdrant)
320    ///# -> Result<(), QdrantError> {
321    /// let discover_points = DiscoverBatchPointsBuilder::new(
322    ///     "my_collection",
323    ///     vec![
324    ///         DiscoverPointsBuilder::new(
325    ///             "my_collection",
326    ///             vec![
327    ///                 ContextExamplePairBuilder::default()
328    ///                     .positive(Example::Id(100.into()))
329    ///                     .negative(Example::Id(718.into()))
330    ///                     .build(),
331    ///                 ContextExamplePairBuilder::default()
332    ///                     .positive(Example::Id(200.into()))
333    ///                     .negative(Example::Id(300.into()))
334    ///                     .build(),
335    ///             ],
336    ///             10,
337    ///         )
338    ///         .build(),
339    ///         DiscoverPointsBuilder::new(
340    ///             "my_collection",
341    ///             vec![
342    ///                 ContextExamplePairBuilder::default()
343    ///                     .positive(Example::Id(342.into()))
344    ///                     .negative(Example::Id(213.into()))
345    ///                     .build(),
346    ///                 ContextExamplePairBuilder::default()
347    ///                     .positive(Example::Id(100.into()))
348    ///                     .negative(Example::Id(200.into()))
349    ///                     .build(),
350    ///             ],
351    ///             10,
352    ///         )
353    ///         .build(),
354    ///     ],
355    /// );
356    ///
357    /// client.discover_batch(&discover_points.build()).await?;
358    ///# Ok(())
359    ///# }
360    /// ```
361    ///
362    /// Documentation: <https://qdrant.tech/documentation/concepts/explore/#discovery-api>
363    pub async fn discover_batch(
364        &self,
365        request: &DiscoverBatchPoints,
366    ) -> QdrantResult<DiscoverBatchResponse> {
367        self.with_points_client(|mut points_api| async move {
368            let result = points_api.discover_batch(request.clone()).await?;
369            Ok(result.into_inner())
370        })
371        .await
372    }
373}