Build a small search index in the spirit of Lucene or Elasticsearch: add documents, then search them. Each lesson opens with a concrete spec and closes with it satisfied, until the analyzer, index, and ranking all hold together.
Over the next 34 lessons you build a working in-memory search index library from scratch - a small core in the spirit of Lucene or Elasticsearch. You add documents to it and search them: an analyzer turns text into normalized terms, an inverted index maps every term to the documents and positions where it appears, and a ranking layer scores matches with TF-IDF, cosine normalization, and BM25.
You finish with a coherent library you import and use: construct an index, add documents, and run BM25-ranked free-text search alongside boolean and phrase queries, with highlighted snippets for results. It is a teaching-grade core - clear and correct, held in memory rather than persisted, sharded, or compressed like a production system - and every lesson ends green with the public API importable and working.
Today you create the core object of the whole project - a search index you can add documents to and read them back. Everything else you build hangs off this one type.
Build a SearchIndex that stores documents by id and reports how many it holds.
Every search engine begins with the same humble object: a place to put documents. Before you can tokenize, index, or rank anything, you need a document store - a mapping from a document id to its original text. Keeping the raw text around matters: later you will show snippets of it in results, so the store is not just a stepping stone.
Keep it tiny. A dictionary from id to text, an add method, a size, and a
document(id) lookup. This is the spine the rest of the project attaches to -
every later lesson adds a method to this same class.
class SearchIndex:def __init__(self):self._docs = {} # id -> original textdef add(self, doc_id, text):... # store it# size, document(id) read it back
Manning, Introduction to Information Retrieval - ch. 1.
The library implements BM25 free-text ranking, boolean AND/OR/NOT, phrase queries, and snippets end to end with fail-fast error handling, but the boolean grammar has no operator precedence and only free-text search is BM25-ranked.
The standard textbook on indexing, ranking, and evaluation - free online from the authors.
The classic reference on index compression and large-scale text retrieval.
The 1975 paper that introduced the vector space model underlying TF-IDF ranking.
A more implementation-minded companion, with worked examples of indexing and ranking pipelines.