docs/design-docs/design_docs/20260708-xgboost-function-chain.md
This document describes native xgboost FunctionChain expression support for Milvus L0 rerank.
The feature allows a search-time FunctionChain to reference an XGBoost model registered as a FileResource, load the corresponding local UBJ model file on the execution side, and use native model prediction as the rerank score.
Tracking issue: #51192
Recommendation and learning-to-rank workloads often use vector search as a recall stage, then apply a ranking model over scalar features to reorder the recalled candidates. The ranking model may use business features such as price, click-through-rate, freshness, user-specific scores, or other scalar columns stored with the entity.
Milvus already supports FunctionChain-based rerank pipelines. Adding a native XGBoost expression lets users keep vector recall and model-based reranking in the same search request, avoiding an external requery-and-rerank round trip for L0 rerank scenarios.
xgboost FunctionChain expression.output=raw and output=default.model_format user parameter.feature_names parameter.objective parameter.maxCacheModels cache capacity management.L2 rerank is not enabled in this stage because L2 rerank runs on Proxy, and Proxy does not yet have FileResource sync, local FileResource management, or FileResource resolving support. L2 support can be added later after Proxy-side FileResource support is available.
The FunctionChain expression name is xgboost.
| Parameter | Required | Description |
|---|---|---|
model_resource | Yes | FileResource name of the UBJ XGBoost model. |
output | No | Prediction output mode. Defaults to default. |
Allowed output values:
| Value | Description |
|---|---|
raw | Return the raw tree margin without applying the model objective transform. |
default | Return the model's default prediction output. For binary:logistic, this applies sigmoid to the raw margin. For reg:squarederror, this is the raw score. |
Client-side usage syntax is intentionally omitted from this design because the PyMilvus FunctionChain API may be updated separately.
Expression arguments are feature columns. The feature order passed to XGBoost is exactly the expression argument order.
The expression requires at least one feature column. Literal arguments are not supported.
Search request with FunctionChain
│
▼
FunctionChain execution side
│
▼
`xgboost` FunctionExpr
- validate parameters
- validate input Arrow chunks
- acquire model lease
│
▼
XGBoost model cache
- resolve FileResource name
- lazy load by resource identity
- singleflight concurrent loads
- lease/refcount lifecycle protection
- stale eviction on FileResource sync
│
▼
CGO bridge
- export Arrow arrays through Arrow C Data Interface
- call native C API
│
▼
C++ XGBoost UBJ runtime
- parse UBJ model metadata and trees
- validate objective / booster / feature count
- batch predict over Arrow feature columns
- apply optional objective transform
│
▼
Arrow Float32 score column
The expression implementation is placed under internal/util/function/chain/expr. The native model runtime lives under internal/core/src/rescores and is called through a small C API.
Files:
internal/util/function/chain/expr/xgboost_expr.gointernal/util/function/chain/expr/xgboost_expr_test.goResponsibilities:
xgboost FunctionChain expression.feature_names and objective.model_resource.num_feature metadata.Parameter validation happens when building the expression. Runtime validation covers FileResource resolution, model metadata, input chunk layout, feature count, and native prediction failures.
Files:
internal/util/function/chain/expr/xgboost_cache.gointernal/util/function/chain/expr/xgboost_cache_test.goResponsibilities:
.ubj resources in the XGBoost resource index.model_resource names to local FileResource paths.The cache does not implement capacity-based eviction in this stage. LRU and maxCacheModels can be added later as an independent optimization.
Files:
internal/util/function/chain/expr/xgboost_model_cgo.gointernal/util/function/chain/expr/xgboost_model_stub.gointernal/util/function/chain/expr/xgboost_real_parity_local_test.goThe CGO bridge is enabled by default for cgo builds. It is responsible for:
CStatus failures into Milvus errors.When cgo is disabled, the stub implementation keeps the package buildable and returns a clear error telling the operator to rebuild with CGO_ENABLED=1.
Files:
internal/core/src/rescores/xgboost_model_c.hinternal/core/src/rescores/xgboost_model_c.cppinternal/core/src/rescores/xgboost_model_c_test.cppResponsibilities:
num_feature, objective, base score, tree parameters, split nodes, leaf values, and default directions.output=default.CStatus errors for load and predict failures.The model handle is immutable after load. Prediction must not mutate shared model state or retain Arrow input pointers after the call returns.
Only XGBoost UBJ model files are supported in this stage. FileResource sync filters resources by the .ubj extension for the XGBoost resource index.
Unsupported formats include:
Supported objectives:
reg:squarederrorbinary:logisticSupported booster path:
gbtree models compatible with the native parser.Unsupported model capabilities include:
gblineardartA single-target size_leaf_vector value is accepted, while values greater than one are rejected because multi-target leaf vectors are not supported.
For output=raw, Milvus returns the raw tree margin.
For output=default, Milvus applies the model's default objective transform:
binary:logistic: sigmoid of raw margin.reg:squarederror: raw score.The output column type is Float32.
The implementation rejects invalid requests or unsupported runtime states with clear errors.
Expression and parameter validation:
model_resourceoutput valuefeature_names parameterobjective parameterFileResource validation:
Model validation:
Runtime input validation:
The Go layer uses Milvus error helpers for request validation and internal failures. Native C++ failures are returned through CStatus and converted at the cgo boundary.
Model loading and prediction must be safe under concurrent search requests.
The cache lifecycle is:
.ubj resource index.model_resource to a resource.The native model handle is immutable. Concurrent predictions against the same handle are allowed. Per-request scratch data must stay local to the prediction call.
The native runtime is required for XGBoost FunctionChain execution and is built by default when cgo is enabled. It requires:
When cgo is disabled, Milvus can still compile the expression package through the stub implementation, but executing an XGBoost expression returns an explicit runtime-disabled error.
This stage supports L0 rerank because L0 execution has access to the execution-side FileResource resolver and local model files.
L2 rerank is deferred. L2 runs on Proxy, and Proxy does not yet support FileResource sync and local FileResource resolution. Enabling L2 requires a follow-up design and implementation to provide Proxy-side FileResource local management, resource synchronization, resolver wiring, and L2 FunctionChain data-frame integration.
C++ tests cover native UBJ parsing and prediction behavior:
size_leaf_vector=1size_leaf_vector>1Go tests cover expression validation, cache behavior, and native runtime integration:
.ubj FileResource filteringNative Go tests must be run with CGO_ENABLED=1.
Python client end-to-end tests cover real L0 execution through Milvus standalone:
Negative E2E coverage includes:
outputmaxCacheModels.