mirror of
https://github.com/deepset-ai/haystack.git
synced 2026-10-12 02:12:50 +00:00
Fix/query expander duplicate queries (#12035)
This commit is contained in:
@@ -228,7 +228,7 @@ class QueryExpander:
|
||||
)
|
||||
expanded_queries = expanded_queries[:expansion_count]
|
||||
|
||||
# Add original query if requested and remove duplicates
|
||||
# Add original query if not already present
|
||||
if self.include_original_query:
|
||||
expanded_queries_lower = [q.lower() for q in expanded_queries]
|
||||
if query.lower() not in expanded_queries_lower:
|
||||
@@ -297,7 +297,7 @@ class QueryExpander:
|
||||
)
|
||||
expanded_queries = expanded_queries[:expansion_count]
|
||||
|
||||
# Add original query if requested and remove duplicates
|
||||
# Add original query if not already present
|
||||
if self.include_original_query:
|
||||
expanded_queries_lower = [q.lower() for q in expanded_queries]
|
||||
if query.lower() not in expanded_queries_lower:
|
||||
@@ -349,7 +349,7 @@ class QueryExpander:
|
||||
Parse the generator response to extract individual expanded queries.
|
||||
|
||||
:param generator_response: The raw text response from the generator.
|
||||
:return: List of parsed expanded queries.
|
||||
:return: List of parsed expanded queries, deduplicated in first-seen order.
|
||||
"""
|
||||
parsed = _parse_dict_from_json(generator_response, expected_keys=["queries"], raise_on_failure=False)
|
||||
|
||||
@@ -364,9 +364,13 @@ class QueryExpander:
|
||||
return []
|
||||
|
||||
queries = []
|
||||
seen: set[str] = set()
|
||||
for item in parsed["queries"]:
|
||||
if isinstance(item, str) and item.strip():
|
||||
queries.append(item.strip())
|
||||
stripped = item.strip()
|
||||
if stripped not in seen:
|
||||
seen.add(stripped)
|
||||
queries.append(stripped)
|
||||
else:
|
||||
logger.warning("Skipping non-string or empty query in response: {item}", item=item)
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
fixes:
|
||||
- |
|
||||
Fixed ``QueryExpander`` returning duplicate queries when the chat generator repeats an
|
||||
expansion. Generated queries are now deduplicated while preserving first-seen order,
|
||||
so repeated expansions no longer trigger redundant retrievals or consume the requested
|
||||
expansion budget. Both ``run`` and ``run_async`` are affected.
|
||||
@@ -200,6 +200,18 @@ class TestQueryExpander:
|
||||
assert result["queries"] == ["original query", "alt1", "alt2"]
|
||||
assert len(result["queries"]) == 3
|
||||
|
||||
def test_run_deduplicates_generated_queries(self):
|
||||
chat_generator = MockChatGenerator('{"queries": ["same query", "same query", "other query"]}')
|
||||
expander = QueryExpander(chat_generator=chat_generator, n_expansions=3, include_original_query=False)
|
||||
result = expander.run("topic")
|
||||
assert result["queries"] == ["same query", "other query"]
|
||||
|
||||
def test_run_deduplicates_before_truncating(self):
|
||||
chat_generator = MockChatGenerator('{"queries": ["a", "a", "b", "c"]}')
|
||||
expander = QueryExpander(chat_generator=chat_generator, n_expansions=3, include_original_query=False)
|
||||
result = expander.run("topic")
|
||||
assert result["queries"] == ["a", "b", "c"]
|
||||
|
||||
def test_run_truncates_excess_queries(self, caplog):
|
||||
chat_generator = MockChatGenerator('{"queries": ["q1", "q2", "q3", "q4", "q5"]}')
|
||||
expander = QueryExpander(chat_generator=chat_generator, n_expansions=3, include_original_query=False)
|
||||
@@ -397,6 +409,20 @@ class TestQueryExpanderAsync:
|
||||
]
|
||||
fake_chat_generator.run.assert_called_once()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_run_async_deduplicates_generated_queries(self):
|
||||
chat_generator = MockChatGenerator('{"queries": ["same query", "same query", "other query"]}')
|
||||
expander = QueryExpander(chat_generator=chat_generator, n_expansions=3, include_original_query=False)
|
||||
result = await expander.run_async("topic")
|
||||
assert result["queries"] == ["same query", "other query"]
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_run_async_deduplicates_before_truncating(self):
|
||||
chat_generator = MockChatGenerator('{"queries": ["a", "a", "b", "c"]}')
|
||||
expander = QueryExpander(chat_generator=chat_generator, n_expansions=3, include_original_query=False)
|
||||
result = await expander.run_async("topic")
|
||||
assert result["queries"] == ["a", "b", "c"]
|
||||
|
||||
|
||||
@pytest.mark.integration
|
||||
class TestQueryExpanderIntegration:
|
||||
|
||||
Reference in New Issue
Block a user