diff --git a/rag/retriever/keyword_search.py b/rag/retriever/keyword_search.py index bad161f..14dbfbb 100644 --- a/rag/retriever/keyword_search.py +++ b/rag/retriever/keyword_search.py @@ -21,6 +21,11 @@ def index(self, chunks: list[dict]) -> None: chunks: List of chunk dicts with 'text' field """ self.chunks = chunks + if not chunks: + # BM25Okapi([]) divides by zero in IDF; keep an empty, searchable index. + self.bm25 = None + logger.info("keyword_index_built", chunk_count=0) + return tokenized_corpus = [self._tokenize(chunk["text"]) for chunk in chunks] self.bm25 = BM25Okapi(tokenized_corpus) logger.info("keyword_index_built", chunk_count=len(chunks)) diff --git a/tests/unit/test_keyword_search.py b/tests/unit/test_keyword_search.py index 6d2d326..a43047f 100644 --- a/tests/unit/test_keyword_search.py +++ b/tests/unit/test_keyword_search.py @@ -131,10 +131,6 @@ def test_results_preserve_chunk_fields(self, searcher): assert result["source"] == "readme" assert result["custom"] == "value" - @pytest.mark.xfail( - strict=True, - reason="issue #68 (manifest H-01): BM25 keyword search raises ZeroDivisionError on an empty index", - ) def test_empty_index(self, searcher): """Test searching on empty index.""" searcher.index([])