Skip to content

refactor: make Reranker stateless with std::variant value semantics (…#471

Open
Cuiyus wants to merge 8 commits into
alibaba:mainfrom
Cuiyus:refactor/reranker-stateless-461
Open

refactor: make Reranker stateless with std::variant value semantics (…#471
Cuiyus wants to merge 8 commits into
alibaba:mainfrom
Cuiyus:refactor/reranker-stateless-461

Conversation

@Cuiyus
Copy link
Copy Markdown
Collaborator

@Cuiyus Cuiyus commented Jun 8, 2026

#461)

Replace class hierarchy (Reranker/ScoreBasedReranker/RrfReranker/ WeightedReranker/CallbackReranker) with std::variant<RrfParams, WeightedParams, CallbackParams> value type and a stateless free function reranker::rerank().

Key changes:

  • reranker.h: define RerankParams variant + reranker::rerank() API
  • query.h: MultiQuery::reranker (shared_ptr) -> MultiQuery::rerank (value)
  • schema.h: add CollectionSchema::get_field_ptr() returning FieldSchema::Ptr
  • collection.cc: push field lookup to caller, pass vectorFieldSchema::Ptr
  • c_api: remove opaque zvec_reranker_t, add zvec_multi_query_set_rerank_*
  • python binding: expose _RrfParams/_WeightedParams/_CallbackParams + setters
  • python layer: WeightedReRanker(list[float]), remove Python rerank logic
  • all tests updated to new interface

Benefits:

  • Thread-safe by design: no mutable state, safe to share across threads
  • Collection-decoupled: no bind_schema(), field info passed as parameter
  • Simpler lifecycle: value semantics, no shared_ptr management

Closes #461

@Cuiyus Cuiyus marked this pull request as draft June 8, 2026 03:33
…libaba#461)

Replace class hierarchy (Reranker/ScoreBasedReranker/RrfReranker/
WeightedReranker/CallbackReranker) with std::variant<RrfParams,
WeightedParams, CallbackParams> value type and a stateless free function
reranker::rerank().

Key changes:
- reranker.h: define RerankParams variant + reranker::rerank() API
- query.h: MultiQuery::reranker (shared_ptr) -> MultiQuery::rerank (value)
- schema.h: add CollectionSchema::get_field_ptr() returning FieldSchema::Ptr
- collection.cc: push field lookup to caller, pass vector<FieldSchema::Ptr>
- c_api: remove opaque zvec_reranker_t, add zvec_multi_query_set_rerank_*
- python binding: expose _RrfParams/_WeightedParams/_CallbackParams + setters
- python layer: WeightedReRanker(list[float]), remove Python rerank logic
- all tests updated to new interface

Benefits:
- Thread-safe by design: no mutable state, safe to share across threads
- Collection-decoupled: no bind_schema(), field info passed as parameter
- Simpler lifecycle: value semantics, no shared_ptr management

Closes alibaba#461
@Cuiyus Cuiyus force-pushed the refactor/reranker-stateless-461 branch from 5a02f13 to af54e77 Compare June 8, 2026 03:37
After the reranker stateless refactor the C++ MultiQuery rerank
strategy uses a std::variant with a default value, so the implicit
'reranker required' validation no longer triggered. Restore the
check in QueryExecutor._execute_multi_query so that a hybrid
(multi-query) request without a reranker raises ValueError.
@Cuiyus Cuiyus marked this pull request as ready for review June 8, 2026 06:38
Comment thread src/db/reranker/reranker.cc Outdated
return tl::make_unexpected(
Status::InvalidArgument("WeightedReranker: field '", field.name(),
"' has no vector index params"));
// Non-vector fields (e.g., FTS/BM25): use IP-like normalization
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

需要保留用index_type()判断fts的逻辑,避免后续添加其他检索方式走到这里发现不了

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

done

Comment thread src/db/reranker/reranker.cc Outdated
"' has no vector index params"));
// Non-vector fields (e.g., FTS/BM25): use IP-like normalization
// that maps positive scores to (0.5, 1.0).
return 0.5 + std::atan(score) / M_PI;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

为什么要映射分数到(0.5, 1.0)?

Copy link
Copy Markdown
Collaborator Author

@Cuiyus Cuiyus Jun 8, 2026

Choose a reason for hiding this comment

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

done. 好几处comment 都因为amend 提交被回滚了...

# SubQuery default of 10 to ensure sufficient candidates for reranking.
_DEFAULT_NUM_CANDIDATES = 10
for sub in multi_query.queries:
sub.num_candidates = max(ctx.topk, _DEFAULT_NUM_CANDIDATES)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

需要允许用户指定比topk大的num_candidates

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

python 层的query 暂未透出num_candidates。

理想情况下,python 接口中的topk(include_vec & filter) 归属于 subQuery,可适配单路&多路 Query场景。
但现阶段topk 与 query参数并列,调整会有breaking change。

若透出num_candidates,则 topk & topn & num_candidates 三个参数 都有召回数量的含义,担心会给用户带来confuse。

此外,多向量场景每一路召回数量不一致,rerank打分的公平性会被每一路召回数量影响。

个人建议先不透出num_candidates 。 @zhourrr 你觉得呢?

Comment thread src/db/collection.cc Outdated
search_queries.reserve(query.queries.size());
field_names.reserve(query.queries.size());
struct PendingQuery {
std::string field_name;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

field_name没用到?继续用std::vector<SearchQuery>就可以?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

done

Re-ranked document list.
"""
return None # noqa: RET501
...
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

去掉abstruct,基类默认实现为raise NotImplementedError ,这样qwen/sentence不用再重复实现了

Comment thread src/include/zvec/db/reranker.h Outdated
// Public: Rerank execution API (stateless free function)
// ===========================================================================

namespace reranker {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

为啥有些在zvec有些在zvec::reranker中?区分的考虑是什么?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

done

int rank_constant_;
/// RRF (Reciprocal Rank Fusion) parameters.
/// Score formula: 1 / (rank_constant + rank + 1)
struct RrfParams {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

这些定义都带上Reranker吧,XxxRerankerParams,不然有些泛。或者都放到reranker ns中,这样不带也没有歧义

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

done

Cuiyus added 3 commits June 8, 2026 20:22
Replace dynamic_cast nullptr check with explicit IndexType::FTS check
and map FTS/BM25 positive scores to (0.0, 1.0) via 2*atan(score)/pi.
…lify usages

Move RrfParams, WeightedParams, CallbackParams and RerankParams into the
zvec::reranker namespace, and add explicit reranker:: qualification at all
usage sites outside the reranker module (query.h, python/c bindings, tests).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Refactor: Make Reranker stateless and decoupled from Collection to fix race condition

2 participants