The inverted index — term to docs

An inverted index stores term → sorted list of doc ids (a posting list), so a word lookup is one hash-into-sorted-list and Boolean queries become merges of sorted iterators — the cost collapses from O(documents) to O(matches).

Previously

Asking 'which rows contain this term?' needs a precomputed map from term to rows. Build it once, query it many times.

Scene 02

The inverted index — term to docs

  1. Watch
  2. Try it
  3. Predict
  4. Capture
QUERYcatDOCUMENTS · tokenised#1The Cat in the Hatthecatinthehatclassic#2Distributed Systemsdistributedsystems#3Designing Data-Intensive Applicationsdesigningdataintensiveapplicationsdistributed#4Lucene in Actionluceneinactionsearchjava#5The Old Man and the SeatheoldmanseafictionclassicTERM DICTIONARY · sortedtermposting list (sorted doc ids)applications3cat1classic15data3designing3distributed23fiction5hat1lucene4sea5search4systems23Term 'cat' → posting list [1] (sorted doc ids)
What to watch for

Five books, six terms each. Watch the term dictionary populate one term at a time, with each posting list showing exactly which doc ids contain that word. The walk ends on the scene-1 query 'distributed systems' — same query, two hash lookups, one merge.

Continue unlocks when the animation finishes.
Implementation

Highlighted lines are the ones running in the diagram right now.

tokenize(book)
split body, lowercase, dedupe — runs once per doc, at index time
def tokenize(book):
raw = split_on_whitespace(book.body)
terms = [lowercase(t) for t in raw]
return set(terms) # dedupe within a doc
lookup(term)
one hash into the term dictionary returns a sorted posting list
def lookup(term):
if term not in dictionary:
return []
return dictionary[term] # sorted list of doc ids
and_merge(a, b)
two-pointer walk over sorted posting lists
def and_merge(a, b):
i, j, out = 0, 0, []
while i < len(a) and j < len(b):
if a[i] == b[j]: # match — emit and step both
out.append(a[i])
i += 1; j += 1
elif a[i] < b[j]:
i += 1 # advance the smaller cursor
else:
j += 1
return out # bounded by min(|a|, |b|)

Where this sits in Build a distributed search engine (Elasticsearch / OpenSearch style)

Scene 02 of 12. Flip the relation: a precomputed map from each word to the doc IDs it appears in turns O(documents) Boolean queries into O(matches) sorted-list merges.

Up next. The map is beautiful when frozen and miserable when mutated — every insert touches the term dictionary at random terms, every delete shifts posting lists. The next scene buys back mutability without touching what is already on disk.

All 12 scenes in Build a distributed search engine (Elasticsearch / OpenSearch style) · Every curriculum

Built with Arqly
Every scene in Build a distributed search engine (Elasticsearch / OpenSearch style) builds on the one before it.All 12 Build a distributed search engine (Elasticsearch / OpenSearch style) scenes