Skip to content

feat(query): make hybrid_search ranker optional with RRF default#107

Open
marlon-costa-dc wants to merge 1 commit into
milvus-io:mainfrom
marlon-costa-dc:feat/optional-hybrid-search-ranker
Open

feat(query): make hybrid_search ranker optional with RRF default#107
marlon-costa-dc wants to merge 1 commit into
milvus-io:mainfrom
marlon-costa-dc:feat/optional-hybrid-search-ranker

Conversation

@marlon-costa-dc
Copy link
Copy Markdown

Summary

  • Makes the ranker parameter in hybrid_search an Option<Box<dyn BaseRanker>>.
  • If None is provided, it falls back to options.ranker or defaults to RrfRanker with k=60.0.
  • This simplifies the API for the common case where users just want standard RRF ranking.

@sre-ci-robot
Copy link
Copy Markdown
Collaborator

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: marlon-costa-dc
To complete the pull request process, please assign yah01 after the PR has been reviewed.
You can assign the PR to them by writing /assign @yah01 in a comment when ready.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@mergify
Copy link
Copy Markdown

mergify Bot commented Feb 25, 2026

@marlon-costa-dc Thanks for your contribution. Please submit with DCO, see the contributing guide https://github.com/milvus-io/milvus/blob/master/CONTRIBUTING.md#developer-certificate-of-origin-dco.

@mergify
Copy link
Copy Markdown

mergify Bot commented Feb 25, 2026

@marlon-costa-dc Please associate the related issue to the body of your Pull Request. (eg. “issue: #187”)

Comment thread src/query.rs
///
/// let ranker = WeightedRanker::new(vec![0.7, 0.3]);
/// let results = client.hybrid_search("my_collection", vec![req1, req2], Box::new(ranker), None).await?;
/// let results = client.hybrid_search("my_collection", vec![req1, req2], Some(Box::new(ranker)), None).await?;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new doc example at L1417 moves req1 and req2 into vec![req1, req2], then L1420 reuses them in a second call. AnnSearchRequest derives Clone but the example never calls .clone(), so this demonstrates use-after-move to users. Either split into independent examples or clone the requests before the second call.

Comment thread src/query.rs
};

let ids: Vec<String> = ids.into_iter().map(|x| x.into()).collect();
let ids: Vec<String> = ids.into_iter().collect();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR simplified this line from .map(|x| x.into()).collect() to .into_iter().collect(), but ids is already Vec<String>, so the collect is still a pointless identity reallocation. Since the PR intentionally touched this line to simplify it, the simplification should be completed by deleting the line entirely.

Comment thread src/query.rs
/// let options = SearchOptions::new().ranker(Box::new(WeightedRanker::new(vec![0.7, 0.3])));
/// let results = client.hybrid_search("my_collection", vec![req1, req2], None, Some(options)).await?;
/// ```
pub async fn hybrid_search<S>(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The third parameter of hybrid_search() changed from Box<dyn BaseRanker> to Option<Box<dyn BaseRanker>>. All existing external callers must wrap their argument with Some(...) or their code will fail to compile. While 0.1.0 SemVer allows breaking changes and the error is caught at compile time, this should be explicitly declared in release notes so downstream users are aware.

Comment thread src/query.rs
where
S: Into<String>,
{
let options = options.unwrap_or_default();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new priority logic ranker.or(options.ranker).unwrap_or_else(|| RrfRanker(60.0)) at L1432-1435 introduces three distinct branches (explicit parameter, options.ranker, default RRF) but none are covered by unit or integration tests. This core public API behavior is vulnerable to accidental regression during future refactoring.

@yhmo yhmo force-pushed the feat/optional-hybrid-search-ranker branch from 6af654b to 2d4b618 Compare April 30, 2026 10:21
@mergify mergify Bot added the ci-passed label Apr 30, 2026
Copilot AI review requested due to automatic review settings May 6, 2026 04:06
@yhmo yhmo force-pushed the feat/optional-hybrid-search-ranker branch from 2d4b618 to a068d69 Compare May 6, 2026 04:06
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the Client::hybrid_search API to make the ranker parameter optional, simplifying the common usage by defaulting to Reciprocal Rank Fusion (RRF) when no ranker is explicitly provided.

Changes:

  • Changed hybrid_search to accept ranker: Option<Box<dyn BaseRanker>> and select an effective ranker from (param → options.ranker → default RrfRanker(k=60.0)).
  • Added SearchOptions::ranker(...) to allow configuring the ranker via options instead of always passing it to hybrid_search.
  • Performed a few small refactors/cleanups (derive Default for QueryOptions, minor idiomatic Rust simplifications, and slice-based params helpers).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/query.rs
Comment on lines 1432 to +1434
let options = options.unwrap_or_default();
let effective_ranker = ranker
.or(options.ranker)
@yhmo yhmo added the code-conflict Code conflict, cannot be merged label May 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants