@@ -42,8 +42,8 @@ use crate::{client::ChromaHttpClientError, ChromaHttpClient};
4242///
4343/// ```
4444/// # use chroma::collection::ChromaCollection;
45- /// # use chroma::client::ChromaClientError ;
46- /// # async fn example(collection: ChromaCollection) -> Result<(), ChromaClientError > {
45+ /// # use chroma::client::ChromaHttpClientError ;
46+ /// # async fn example(collection: ChromaCollection) -> Result<(), ChromaHttpClientError > {
4747/// let count = collection.count().await?;
4848/// println!("Collection contains {} records", count);
4949///
@@ -325,87 +325,144 @@ impl ChromaCollection {
325325 self . send ( "query" , Method :: POST , Some ( request) ) . await
326326 }
327327
328- /// Executes advanced search with multiple search payloads in a single request .
328+ /// Performs hybrid search on the collection using the Search API .
329329 ///
330- /// Each [`SearchPayload`] can specify distinct query vectors, filters, and result counts,
331- /// enabling efficient batch similarity search with heterogeneous parameters .
330+ /// The Search API provides a powerful, flexible interface for vector similarity search
331+ /// combined with metadata filtering and custom ranking expressions .
332332 ///
333- /// # Errors
333+ /// # Arguments
334334 ///
335- /// Returns an error if:
336- /// - Any search payload fails validation
337- /// - Network communication fails
335+ /// * `searches` - One or more search payloads to execute in a single request
336+ ///
337+ /// # Returns
338+ ///
339+ /// A `SearchResponse` containing results for each search payload
338340 ///
339341 /// # Examples
340342 ///
341- /// Basic search with default parameters:
343+ /// ## Basic similarity search
344+ ///
342345 /// ```
343- /// # use chroma::collection::ChromaCollection;
344- /// # use chroma_types::plan::SearchPayload;
345- /// # async fn example(collection: ChromaCollection) -> Result<(), Box<dyn std::error::Error>> {
346- /// let search1 = SearchPayload {
347- /// filter: Default::default(),
348- /// rank: Default::default(),
349- /// limit: Default::default(),
350- /// select: Default::default(),
346+ /// use chroma_types::plan::SearchPayload;
347+ /// use chroma_types::operator::{RankExpr, QueryVector, Key};
348+ ///
349+ /// # async fn example(collection: &chroma::collection::ChromaCollection) -> Result<(), Box<dyn std::error::Error>> {
350+ /// // Search with a query vector
351+ /// let search = SearchPayload::default()
352+ /// .rank(RankExpr::Knn {
353+ /// query: QueryVector::Dense(vec![0.1, 0.2, 0.3]),
354+ /// key: Key::Embedding,
355+ /// limit: 100,
356+ /// default: None,
357+ /// return_rank: false,
358+ /// })
359+ /// .limit(Some(10), 0)
360+ /// .select([Key::Document, Key::Score]);
361+ ///
362+ /// let results = collection.search(vec![search]).await?;
363+ /// # Ok(())
364+ /// # }
365+ /// ```
366+ ///
367+ /// ## Filtered search with metadata
368+ ///
369+ /// ```
370+ /// use chroma_types::plan::SearchPayload;
371+ /// use chroma_types::operator::{RankExpr, QueryVector, Key};
372+ ///
373+ /// # async fn example(collection: &chroma::collection::ChromaCollection) -> Result<(), Box<dyn std::error::Error>> {
374+ /// // Filter by category and year, then rank by similarity
375+ /// let search = SearchPayload::default()
376+ /// .r#where(
377+ /// Key::field("category").eq("science")
378+ /// & Key::field("year").gte(2020)
379+ /// )
380+ /// .rank(RankExpr::Knn {
381+ /// query: QueryVector::Dense(vec![0.1, 0.2, 0.3]),
382+ /// key: Key::Embedding,
383+ /// limit: 200,
384+ /// default: None,
385+ /// return_rank: false,
386+ /// })
387+ /// .limit(Some(5), 0)
388+ /// .select([Key::Document, Key::Score, Key::field("title")]);
389+ ///
390+ /// let results = collection.search(vec![search]).await?;
391+ /// # Ok(())
392+ /// # }
393+ /// ```
394+ ///
395+ /// ## Hybrid search with custom ranking
396+ ///
397+ /// ```
398+ /// use chroma_types::plan::SearchPayload;
399+ /// use chroma_types::operator::{RankExpr, QueryVector, Key};
400+ ///
401+ /// # async fn example(collection: &chroma::collection::ChromaCollection) -> Result<(), Box<dyn std::error::Error>> {
402+ /// // Combine two KNN searches with weights
403+ /// let dense_knn = RankExpr::Knn {
404+ /// query: QueryVector::Dense(vec![0.1, 0.2, 0.3]),
405+ /// key: Key::Embedding,
406+ /// limit: 200,
407+ /// default: None,
408+ /// return_rank: false,
351409 /// };
352- /// let search2 = SearchPayload {
353- /// filter: Default::default(),
354- /// rank: Default::default(),
355- /// limit: Default::default(),
356- /// select: Default::default(),
410+ ///
411+ /// let sparse_knn = RankExpr::Knn {
412+ /// query: QueryVector::Dense(vec![0.1, 0.2, 0.3]), // Use sparse vector in practice
413+ /// key: Key::field("sparse_embedding"),
414+ /// limit: 200,
415+ /// default: None,
416+ /// return_rank: false,
357417 /// };
358418 ///
359- /// let response = collection.search(vec![search1, search2]).await?;
360- /// println!("Executed {} searches", response.ids.len());
419+ /// // Weighted combination: 70% dense + 30% sparse
420+ /// let hybrid_rank = dense_knn * 0.7 + sparse_knn * 0.3;
421+ ///
422+ /// let search = SearchPayload::default()
423+ /// .rank(hybrid_rank)
424+ /// .limit(Some(10), 0)
425+ /// .select([Key::Document, Key::Score]);
426+ ///
427+ /// let results = collection.search(vec![search]).await?;
361428 /// # Ok(())
362429 /// # }
363430 /// ```
364431 ///
365- /// Advanced search with all fields configured:
432+ /// ## Batch operations
433+ ///
366434 /// ```
367- /// # use chroma::collection::ChromaCollection;
368- /// # use chroma_types::plan::SearchPayload;
369- /// # use chroma_types::{Filter, Rank, RankExpr, QueryVector, Key, Limit, Select};
370- /// # use chroma_types::{Where, MetadataExpression, MetadataComparison, PrimitiveOperator, MetadataValue};
371- /// # use std::collections::HashSet;
372- /// # async fn example(collection: ChromaCollection) -> Result<(), Box<dyn std::error::Error>> {
373- /// let search = SearchPayload {
374- /// filter: Filter {
375- /// query_ids: Some(vec!["doc1".to_string(), "doc2".to_string()]),
376- /// where_clause: Some(Where::Metadata(MetadataExpression {
377- /// key: "category".to_string(),
378- /// comparison: MetadataComparison::Primitive(
379- /// PrimitiveOperator::Equal,
380- /// MetadataValue::Str("research".to_string()),
381- /// ),
382- /// })),
383- /// },
384- /// rank: Rank {
385- /// expr: Some(RankExpr::Knn {
386- /// query: QueryVector::Dense(vec![0.1, 0.2, 0.3, 0.4]),
435+ /// use chroma_types::plan::SearchPayload;
436+ /// use chroma_types::operator::{RankExpr, QueryVector, Key};
437+ ///
438+ /// # async fn example(collection: &chroma::collection::ChromaCollection) -> Result<(), Box<dyn std::error::Error>> {
439+ /// // Run multiple searches in one request
440+ /// let searches = vec![
441+ /// SearchPayload::default()
442+ /// .r#where(Key::field("category").eq("tech"))
443+ /// .rank(RankExpr::Knn {
444+ /// query: QueryVector::Dense(vec![0.1, 0.2, 0.3]),
387445 /// key: Key::Embedding,
388- /// limit: 50 ,
446+ /// limit: 100 ,
389447 /// default: None,
390448 /// return_rank: false,
391- /// }),
392- /// },
393- /// limit: Limit {
394- /// offset: 0,
395- /// limit: Some(10),
396- /// },
397- /// select: Select {
398- /// keys: HashSet::from([
399- /// Key::Document,
400- /// Key::Metadata,
401- /// Key::Embedding,
402- /// Key::Score,
403- /// ]),
404- /// },
405- /// };
449+ /// })
450+ /// .limit(Some(5), 0),
451+ /// SearchPayload::default()
452+ /// .r#where(Key::field("category").eq("science"))
453+ /// .rank(RankExpr::Knn {
454+ /// query: QueryVector::Dense(vec![0.1, 0.2, 0.3]),
455+ /// key: Key::Embedding,
456+ /// limit: 100,
457+ /// default: None,
458+ /// return_rank: false,
459+ /// })
460+ /// .limit(Some(5), 0),
461+ /// ];
406462 ///
407- /// let response = collection.search(vec![search]).await?;
408- /// println!("Found {} results", response.ids[0].len());
463+ /// let results = collection.search(searches).await?;
464+ /// // results.results[0] contains first search results
465+ /// // results.results[1] contains second search results
409466 /// # Ok(())
410467 /// # }
411468 /// ```
0 commit comments