diff --git a/arborist/qa/corpus_query.py b/arborist/qa/corpus_query.py index f82dbef..a08afc8 100644 --- a/arborist/qa/corpus_query.py +++ b/arborist/qa/corpus_query.py @@ -192,7 +192,10 @@ def run_query( ts = _time.time() multi_route = bool(policy and policy.get("multi_route", False)) if multi_route: - from arborist.qa.retrieval_routes import question_phrases + from arborist.qa.retrieval_routes import ( + filter_by_title_relevance, + question_phrases, + ) per_route_limit = top_k * 4 body_hits = _safe_route(corpus, "fts_body", question, per_route_limit) title_hits = _safe_route(corpus, "fts_title", question, per_route_limit) @@ -200,8 +203,6 @@ def run_query( phrase_hits = _safe_phrase_route( corpus, phrases, per_route_limit, ) if phrases else [] - # core_keyword needs qtokens; reuse the title_query_tokens helper - # since legacy query() does the same thing. from arborist.qa.query import _title_query_tokens qtokens = list(_title_query_tokens(question)) core_hits = _safe_core_route( @@ -210,6 +211,22 @@ def run_query( hits = _merge_routes_min_bm25( body_hits, title_hits, phrase_hits, core_hits, ) + # 5-accept-path filter from arborist.qa.retrieval_routes — + # gates the merged set on title-overlap / synonym / TFIDF-core + # match / verbatim-phrase match / hyphen-fold anchor. Without + # this, multi-route over-recalls on noisy title overlaps (e.g. + # "East Asia" outranks "Nineteen Eighty-Four" for the Orwell + # phrase query). core_match_roots and phrase_match_roots are + # passed through so accept-paths 2 + 4 fire on docs that + # surfaced via those routes even when titles miss. + core_match_roots = {h.document_root for h in core_hits} + phrase_match_roots = {h.document_root for h in phrase_hits} + hits = filter_by_title_relevance( + hits, question, + core_match_roots=core_match_roots, + phrase_match_roots=phrase_match_roots, + fallback_top_n=top_k, + ) else: try: hits = corpus.fts_body(question, limit=top_k * 4)