Skip to content
Open
Show file tree
Hide file tree
Changes from all 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 @@ -172,6 +172,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``.
9 changes: 9 additions & 0 deletions test/components/evaluators/test_answer_exact_match.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,12 @@ def test_run_with_different_lengths():

with pytest.raises(ValueError):
evaluator.run(ground_truth_answers=["Berlin", "Paris"], predicted_answers=["Berlin"])


def test_run_with_empty_inputs():
evaluator = AnswerExactMatchEvaluator()

# Empty (equal-length) inputs previously fell through the length check and
# crashed with a bare ZeroDivisionError when averaging over zero items.
with pytest.raises(ValueError, match="must be provided"):
evaluator.run(ground_truth_answers=[], predicted_answers=[])
9 changes: 9 additions & 0 deletions test/components/evaluators/test_document_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,3 +147,12 @@ def test_run_with_different_lengths():
ground_truth_documents=[[Document(content="Berlin")], [Document(content="Paris")]],
retrieved_documents=[[Document(content="Berlin")]],
)


def test_run_with_empty_inputs():
evaluator = DocumentMAPEvaluator()

# Empty (equal-length) inputs previously fell through the length check and
# crashed with a bare ZeroDivisionError when averaging over zero items.
with pytest.raises(ValueError, match="must be provided"):
evaluator.run(ground_truth_documents=[], retrieved_documents=[])
9 changes: 9 additions & 0 deletions test/components/evaluators/test_document_mrr.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,12 @@ def test_run_with_different_lengths():
ground_truth_documents=[[Document(content="Berlin")], [Document(content="Paris")]],
retrieved_documents=[[Document(content="Berlin")]],
)


def test_run_with_empty_inputs():
evaluator = DocumentMRREvaluator()

# Empty (equal-length) inputs previously fell through the length check and
# crashed with a bare ZeroDivisionError when averaging over zero items.
with pytest.raises(ValueError, match="must be provided"):
evaluator.run(ground_truth_documents=[], retrieved_documents=[])
9 changes: 9 additions & 0 deletions test/components/evaluators/test_document_recall.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,15 @@ def test_run_with_nested_meta_comparison():
assert result == {"individual_scores": [0.5], "score": 0.5}


def test_run_with_empty_inputs():
evaluator = DocumentRecallEvaluator()

# Empty (equal-length) inputs previously fell through the length check and
# crashed with a bare ZeroDivisionError when averaging over zero items.
with pytest.raises(ValueError, match="must be provided"):
evaluator.run(ground_truth_documents=[], retrieved_documents=[])


class TestDocumentRecallEvaluatorSingleHit:
@pytest.fixture
def evaluator(self):
Expand Down
Loading