Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions haystack/components/evaluators/answer_exact_match.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ def run(self, ground_truth_answers: list[str], predicted_answers: list[str]) ->
- `score` - A number from 0.0 to 1.0 that represents the proportion of questions where any predicted
answer matched one of the ground truth answers.
"""
if len(ground_truth_answers) == 0 or len(predicted_answers) == 0:
raise ValueError("ground_truth_answers and predicted_answers must be provided.")

if not len(ground_truth_answers) == len(predicted_answers):
raise ValueError("The length of ground_truth_answers and predicted_answers must be the same.")

Expand Down
4 changes: 4 additions & 0 deletions haystack/components/evaluators/document_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@ def run(
- `individual_scores` - A list of numbers from 0.0 to 1.0 that represents how high retrieved documents
are ranked.
"""
if len(ground_truth_documents) == 0 or len(retrieved_documents) == 0:
msg = "ground_truth_documents and retrieved_documents must be provided."
raise ValueError(msg)

if len(ground_truth_documents) != len(retrieved_documents):
msg = "The length of ground_truth_documents and retrieved_documents must be the same."
raise ValueError(msg)
Expand Down
4 changes: 4 additions & 0 deletions haystack/components/evaluators/document_mrr.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ def run(
- `individual_scores` - A list of numbers from 0.0 to 1.0 that represents how high the first retrieved
document is ranked.
"""
if len(ground_truth_documents) == 0 or len(retrieved_documents) == 0:
msg = "ground_truth_documents and retrieved_documents must be provided."
raise ValueError(msg)

if len(ground_truth_documents) != len(retrieved_documents):
msg = "The length of ground_truth_documents and retrieved_documents must be the same."
raise ValueError(msg)
Expand Down
4 changes: 4 additions & 0 deletions haystack/components/evaluators/document_recall.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,10 @@ def run(
- `individual_scores` - A list of numbers from 0.0 to 1.0 that represents the proportion of matching
documents retrieved. If the mode is `single_hit`, the individual scores are 0 or 1.
"""
if len(ground_truth_documents) == 0 or len(retrieved_documents) == 0:
msg = "ground_truth_documents and retrieved_documents must be provided."
raise ValueError(msg)

if len(ground_truth_documents) != len(retrieved_documents):
msg = "The length of ground_truth_documents and retrieved_documents must be the same."
raise ValueError(msg)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
fixes:
- |
``AnswerExactMatchEvaluator``, ``DocumentMAPEvaluator``, ``DocumentMRREvaluator`` and
``DocumentRecallEvaluator`` now raise a descriptive ``ValueError`` when called with
empty input lists, instead of failing with an opaque ``ZeroDivisionError``. This
matches the existing behavior of ``DocumentNDCGEvaluator``.
30 changes: 30 additions & 0 deletions test/components/evaluators/test_evaluators_empty_input.py

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Let's not add this test file containing only a single test function. Instead, let's add this test to the existing evaluator test files.

Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>
#
# SPDX-License-Identifier: Apache-2.0

import pytest

from haystack.components.evaluators import (
AnswerExactMatchEvaluator,
DocumentMAPEvaluator,
DocumentMRREvaluator,
DocumentRecallEvaluator,
)


@pytest.mark.parametrize(
"evaluator, kwargs",
[
(AnswerExactMatchEvaluator(), {"ground_truth_answers": [], "predicted_answers": []}),
(DocumentMAPEvaluator(), {"ground_truth_documents": [], "retrieved_documents": []}),
(DocumentMRREvaluator(), {"ground_truth_documents": [], "retrieved_documents": []}),
(DocumentRecallEvaluator(), {"ground_truth_documents": [], "retrieved_documents": []}),
],
)
def test_run_with_empty_inputs_raises_value_error(evaluator, kwargs):
# Empty (equal-length) inputs previously fell through the length check and
# crashed with a bare ZeroDivisionError when averaging over zero items.
# They must instead raise a descriptive ValueError, matching
# DocumentNDCGEvaluator's contract.
with pytest.raises(ValueError, match="must be provided"):
evaluator.run(**kwargs)
Loading