From e49264ae4740434687220745821c43df3ff5c537 Mon Sep 17 00:00:00 2001 From: pewdiepie-archdaemon Date: Thu, 17 Sep 2026 19:15:39 +0000 Subject: [PATCH] preserve product identity in manual search --- services/search/core.py | 22 +++++++++++++++++++++ tests/test_search_empty_query_relaxation.py | 14 +++++++++++++ 2 files changed, 36 insertions(+) diff --git a/services/search/core.py b/services/search/core.py index 3d20aa1e2..62dea902d 100644 --- a/services/search/core.py +++ b/services/search/core.py @@ -237,6 +237,28 @@ def _result_has_query_overlap(query: str, result: dict) -> bool: ) result_tokens = set(re.findall(r"[a-z0-9]+", text)) + document_cues = { + "manual", "manuals", "guide", "guides", "instructions", "instruction", + "documentation", "docs", "pdf", "handbook", + } + if query_tokens & document_cues: + entity_fillers = _SEARCH_QUERY_FILLER | document_cues | { + "english", "operator", "owner", "owners", "user", "installation", + } + ordered_query_tokens = re.findall(r"[a-z0-9]+", str(query or "").lower()) + entity_terms = [ + token for token in ordered_query_tokens + if token not in entity_fillers and not token.isdigit() + ] + # Product/manual lookups are especially vulnerable to homonyms. A + # result matching only the generic product word and "manual" is not + # evidence for the named brand/entity in the request. + if entity_terms and entity_terms[0] not in result_tokens: + return False + model_numbers = {token for token in ordered_query_tokens if token.isdigit()} + if model_numbers and not model_numbers.issubset(result_tokens): + return False + def lexical_root(word: str) -> str: for suffix in ("ation", "ition", "ence", "ance", "ment", "ents", "ent", "ant", "ing", "ed", "es", "s"): if word.endswith(suffix) and len(word) - len(suffix) >= 6: diff --git a/tests/test_search_empty_query_relaxation.py b/tests/test_search_empty_query_relaxation.py index 107c54b2d..630b67831 100644 --- a/tests/test_search_empty_query_relaxation.py +++ b/tests/test_search_empty_query_relaxation.py @@ -23,6 +23,20 @@ def test_empty_document_search_relaxes_scaffolding_then_entity(): ] +def test_manual_relevance_rejects_homonym_without_brand_and_model(): + query = 'WIKING Miro 3 English manual official source' + assert not core._result_has_query_overlap(query, { + 'title': 'Miro Appliance User Manuals', + 'url': 'https://shop.mirohome.com/pages/miro-appliance-user-manuals', + 'snippet': 'Manuals for Miro humidifiers and air purifiers.', + }) + assert core._result_has_query_overlap(query, { + 'title': 'WIKING Miro 3 Installation and User Manual', + 'url': 'https://www.hwam.com/manuals/wiking-miro-3.pdf', + 'snippet': 'Official English installation and user manual.', + }) + + def test_search_uses_entity_relaxation_only_after_exact_queries_are_empty( monkeypatch, tmp_path, ):