Picking the best run, building reports and cleaning up old runs all start with search.
mlflow.search_runs() returns a pandas DataFrame with one row per run and columns like run_id, status, params.max_depth, metrics.val_auc and tags.owner.
mlflow.search_runs(experiment_names=["churn"],
filter_string="metrics.val_auc > 0.85 and params.model = 'gbm'",
order_by=["metrics.val_auc DESC"], max_results=5)The filter language is SQL-like:
- Prefixes:
metrics.,params.,tags.,attributes.(e.g.attributes.status = 'FINISHED',attributes.start_time > ...in milliseconds). - Params and tags are strings, so compare them with quoted strings; metrics are numbers.
- Operators:
=,!=,<,>,LIKE,ILIKE,IN,IS NULL, combined withAND(noOR). - Names with spaces or dots need backticks: `
metrics.val auc`.
MlflowClient().search_runs(...) returns Run objects instead of a DataFrame, with pagination, which suits automation.
In the UI, select runs and click Compare to see parallel coordinates plots, scatter plots of a parameter against a metric, and metric curves overlaid. Charts and table views can be grouped by tags or parameters, handy for sweeps.
Metric filters use the latest logged value of each metric; log a separate best_val_auc metric if you need to search on the best epoch.
Example
import mlflow
mlflow.set_experiment("search-demo")
for depth in [2, 4, 8]:
with mlflow.start_run(run_name=f"depth-{depth}"):
mlflow.log_params({"model": "tree", "max_depth": depth})
mlflow.log_metric("val_auc", 0.70 + depth * 0.02)
best = mlflow.search_runs(
experiment_names=["search-demo"],
filter_string="params.model = 'tree' and metrics.val_auc > 0.75",
order_by=["metrics.val_auc DESC"],
)
print(best[["params.max_depth", "metrics.val_auc"]].head(2).to_string(index=False))
# params.max_depth metrics.val_auc
# 8 0.86
# 4 0.78Remember
search_runsreturns a DataFrame with params., metrics. and tags. columns- Filter strings quote string values; metrics compare as numbers
- Metric filters see the latest value, not the best
Watch out for
- Filtering params numerically like params.max_depth > 4; params are strings, so compare as strings or cast in pandas.