Skip to content

Commit 7fe5003

Browse files
authored
fix: eval() with add_isolated_node_eval=True breaks if no node supports it (#3347)
* fix isolated eval for pipelines without a node supporting isolated mode * reformat * add test
1 parent 84aff5e commit 7fe5003

File tree

2 files changed

+40
-1
lines changed

2 files changed

+40
-1
lines changed

haystack/pipelines/base.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2094,7 +2094,9 @@ def _validate_node_names_in_params(self, params: Optional[Dict]):
20942094

20952095
# Might be a non-targeted param. Verify that too
20962096
not_a_node = set(params.keys()) - set(self.graph.nodes)
2097-
valid_global_params = set(["debug"]) # Debug will be picked up by _dispatch_run, see its code
2097+
# "debug" will be picked up by _dispatch_run, see its code
2098+
# "add_isolated_node_eval" is set by pipeline.eval / pipeline.eval_batch
2099+
valid_global_params = set(["debug", "add_isolated_node_eval"])
20982100
for node_id in self.graph.nodes:
20992101
run_signature_args = self._get_run_node_signature(node_id)
21002102
valid_global_params |= set(run_signature_args)

test/pipelines/test_eval.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1020,6 +1020,43 @@ def test_document_search_calculate_metrics(retriever_with_docs):
10201020
assert metrics["Retriever"]["ndcg"] == 0.5
10211021

10221022

1023+
@pytest.mark.parametrize("retriever_with_docs", ["tfidf"], indirect=True)
1024+
@pytest.mark.parametrize("document_store_with_docs", ["memory"], indirect=True)
1025+
def test_document_search_isolated(retriever_with_docs):
1026+
pipeline = DocumentSearchPipeline(retriever=retriever_with_docs)
1027+
# eval run must not fail even though no node supports add_isolated_node_eval
1028+
eval_result: EvaluationResult = pipeline.eval(
1029+
labels=EVAL_LABELS, params={"Retriever": {"top_k": 5}}, add_isolated_node_eval=True
1030+
)
1031+
1032+
metrics = eval_result.calculate_metrics(document_scope="document_id")
1033+
1034+
assert "Retriever" in eval_result
1035+
assert len(eval_result) == 1
1036+
retriever_result = eval_result["Retriever"]
1037+
retriever_berlin = retriever_result[retriever_result["query"] == "Who lives in Berlin?"]
1038+
retriever_munich = retriever_result[retriever_result["query"] == "Who lives in Munich?"]
1039+
1040+
assert (
1041+
retriever_berlin[retriever_berlin["rank"] == 1]["document_id"].iloc[0]
1042+
in retriever_berlin[retriever_berlin["rank"] == 1]["gold_document_ids"].iloc[0]
1043+
)
1044+
assert (
1045+
retriever_munich[retriever_munich["rank"] == 1]["document_id"].iloc[0]
1046+
not in retriever_munich[retriever_munich["rank"] == 1]["gold_document_ids"].iloc[0]
1047+
)
1048+
assert metrics["Retriever"]["mrr"] == 0.5
1049+
assert metrics["Retriever"]["map"] == 0.5
1050+
assert metrics["Retriever"]["recall_multi_hit"] == 0.5
1051+
assert metrics["Retriever"]["recall_single_hit"] == 0.5
1052+
assert metrics["Retriever"]["precision"] == 0.1
1053+
assert metrics["Retriever"]["ndcg"] == 0.5
1054+
1055+
isolated_metrics = eval_result.calculate_metrics(document_scope="document_id", eval_mode="isolated")
1056+
# empty metrics for nodes that do not support add_isolated_node_eval
1057+
assert isolated_metrics["Retriever"] == {}
1058+
1059+
10231060
@pytest.mark.parametrize("retriever_with_docs", ["tfidf"], indirect=True)
10241061
@pytest.mark.parametrize("document_store_with_docs", ["memory"], indirect=True)
10251062
def test_faq_calculate_metrics(retriever_with_docs):

0 commit comments

Comments
 (0)