microsoft/qlib · error · NotImplementedError

Please implement the `search_records` method.

Error message

Please implement the `search_records` method.

What it means

Experiment.search_records is an abstract method meant to return a pandas DataFrame of records (metrics.*, params.*, tags.* columns) matching search criteria. The base class raises NotImplementedError; only concrete backends such as MLflowExperiment implement it by forwarding filter_string/run_view_type/max_results/order_by to the MLflow client.

Source

Thrown at qlib/workflow/exp.py:101

        Returns
        -------
        A recorder object.
        """
        raise NotImplementedError(f"Please implement the `create_recorder` method.")

    def search_records(self, **kwargs):
        """
        Get a pandas DataFrame of records that fit the search criteria of the experiment.
        Inputs are the search criteria user want to apply.

        Returns
        -------
        A pandas.DataFrame of records, where each metric, parameter, and tag
        are expanded into their own columns named metrics.*, params.*, and tags.*
        respectively. For records that don't have a particular metric, parameter, or tag, their
        value will be (NumPy) Nan, None, or None respectively.
        """
        raise NotImplementedError(f"Please implement the `search_records` method.")

    def delete_recorder(self, recorder_id):
        """
        Create a recorder for each experiment.

        Parameters
        ----------
        recorder_id : str
            the id of the recorder to be deleted.
        """
        raise NotImplementedError(f"Please implement the `delete_recorder` method.")

    def get_recorder(self, recorder_id=None, recorder_name=None, create: bool = True, start: bool = False) -> Recorder:
        """
        Retrieve a Recorder for user. When user specify recorder id and name, the method will try to return the
        specific recorder. When user does not provide recorder id or name, the method will try to return the current
        active recorder. The `create` argument determines whether the method will automatically create a new recorder
        according to user's specification if the recorder hasn't been created before.

View on GitHub (pinned to 79633dd950)

Solutions

  1. Use the default MLflowExperiment, whose search_records maps kwargs to MlflowClient.search_runs.
  2. Implement search_records(self, **kwargs) in your subclass returning a DataFrame of matched records.
  3. For ad-hoc inspection, query your backend's native API directly instead of the abstract method.

Example fix

# before
Experiment('1', 'e').search_records()  # NotImplementedError

# after
R.search_records(experiment_ids=[exp_id], filter_string="metrics.ic > 0.02")  # via MLflow backend
Defensive patterns

Strategy: type-guard

Validate before calling

from qlib.workflow.exp import Experiment
if exp.__class__.search_records is Experiment.search_records:
    raise RuntimeError('backend cannot search records; use MLflow backend')

Type guard

def searchable(exp) -> bool:
    from qlib.workflow.exp import Experiment
    return exp.__class__.search_records is not Experiment.search_records

Prevention

When it happens

Trigger: Calling exp.search_records(...) on the base Experiment; R.search_records(experiment_ids, ...) when the configured exp_manager class delegates to an Experiment subclass lacking this override.

Common situations: Custom experiment backends that support run tracking but not search; probing the API in tests; version drift where a fork's subclass fell behind the abstract interface.

Related errors


AI-assisted analysis of microsoft/qlib@79633dd950 (2026-08-15). Data as JSON: /api/errors/5a2f1057fbaa9789. Report an issue: GitHub.