streamsearch / scripts /build_index.py
sharmaaryan's picture
Phase 1: demo tier — FastAPI + Streamlit over a baked index, Docker-deployable
a22b195
Raw
History Blame Contribute Delete
2.22 kB
"""Build the baked-in demo index from data/corpus_sample.jsonl.
Produces, under app/prebuilt/:
- qdrant/ on-disk Qdrant collection with the dense vectors
- lexical.pkl exported BM25 state (ids, tokens, metadata)
Baking both into the image means the demo is never empty, even after the host
restarts its ephemeral storage (spec, Phase 1 acceptance).
Usage:
python scripts/build_index.py
"""
from __future__ import annotations
import json
import logging
import pickle
import sys
from pathlib import Path
# Make src/ importable when run as a script.
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
from streamsearch import config
from streamsearch.schema import Document
from streamsearch.search import HybridSearcher
logging.basicConfig(level=logging.INFO, format="%(levelname)s %(message)s")
log = logging.getLogger("build_index")
def load_corpus(path: Path) -> list[Document]:
docs = []
with path.open(encoding="utf-8") as f:
for line in f:
line = line.strip()
if line:
docs.append(Document.from_json(json.loads(line)))
return docs
def main() -> None:
if config.QDRANT_URL:
log.info("QDRANT_URL set -> building into cloud Qdrant at %s", config.QDRANT_URL)
else:
# Fresh local build: wipe any stale on-disk index first.
import shutil
if config.QDRANT_LOCAL_PATH.exists():
shutil.rmtree(config.QDRANT_LOCAL_PATH)
log.info("Building embedded on-disk index at %s", config.QDRANT_LOCAL_PATH)
docs = load_corpus(config.CORPUS_PATH)
log.info("Loaded %d documents from %s", len(docs), config.CORPUS_PATH)
client = config.make_qdrant_client()
searcher = HybridSearcher(client)
searcher.ensure_collection()
searcher.add_documents(docs)
config.PREBUILT_DIR.mkdir(parents=True, exist_ok=True)
with config.LEXICAL_PATH.open("wb") as f:
pickle.dump(searcher.export_lexical(), f)
log.info("Wrote lexical export to %s", config.LEXICAL_PATH)
# Release the embedded client's file lock so the app can open it.
del client
log.info("Done. Indexed %d docs.", len(docs))
if __name__ == "__main__":
main()