Skip to main content
Information Retrieval

Index Compression and Ranked Retrieval

Published: 2026-09-14
Level: postgraduate
Audience: Postgraduate students in Information Retrieval

7.1 Why Index Compression Matters and Why It Must Stay Lossless

7.1.1 Memory Against Disk and the RCV1 Running Example

Why does a search engine feel instant while your laptop slows down on a big file? The answer is where the index lives when you ask the question.

An inverted index (the map from each distinct word to the list of documents that hold it) has to live where queries can reach it fast. Disk is big but slow. Each random read from disk costs a seek plus a transfer. Main memory is fast but small. It answers in nanoseconds and serves many lookups without moving a disk head. As collections keep growing, the index keeps growing with them, and the push is always to squeeze the index so more of it fits in memory and each query touches fewer slow disk reads.

Think of it like packing for a small cupboard. You can either buy a bigger cupboard, which is costly, or fold your clothes tighter so the same cupboard holds more. Compression is the folding. It adds some work when you pack and unpack, but each lookup after that is quicker because the data is already where you need it. The mapping is direct. Cupboard size is main memory. Clothes are dictionary entries and postings. Folding time is the one-time cost to encode. Unfolding time is the small cost to decode on each query. The win is that far more queries are served from the cupboard without a trip to the store room, which is disk.

An inverted index has two halves. The dictionary is the sorted list of distinct terms with per-term data. The postings are the per-term lists of document identifiers. Compression keeps both halves but stores them in fewer bytes so a larger share fits in fast memory.

The trade stays favorable because encoding happens once while decoding pays off on every query. A collection indexed once may serve millions of queries. Even a modest shrink in bytes cuts disk traffic, grows the share held in cache, and speeds transfers from disk to memory.

The running example for the whole session is the RCV1 collection. The anchor numbers are about 800,000 documents and about 400,000 distinct terms. The average document holds about 200 tokens, and the average token is about 6 characters, so the text itself is about 960 MB while postings run into hundreds of megabytes. That size is big enough that a naive layout already hurts, and it is the base for every megabyte calculation that follows. A nearby aside mentions token counts in the millions. Read that as loose speech for the same scale, not a competing exact total.

Picture the scale as a chart. Put storage tiers on the horizontal axis from cache to main memory to disk, and access time on the vertical axis on a log scale. The bar for disk towers over memory. Each megabyte moved from the disk side to the memory side pulls average query time down. That one-sentence takeaway drives every step in this session.

Example — Cupboard math for RCV1 scale. Take 400,000 terms at 28 bytes in the naive layout, which is 11.2 MB. If only 8 MB of fast memory is free for the dictionary, 3.2 MB must sit on disk and each query risks extra seeks. Squeeze the same index to 7.6 MB with packed strings and it fits fully in the 8 MB budget. Answer: compression turns a spillover index into a memory-resident one. Sense-check: the example uses the same RCV1 anchor numbers, about 800,000 documents and about 400,000 terms, that anchor every later megabyte step.

Scope: This compression story assumes a largely static index that is built once and read many times. Assumption: Queries touch the dictionary on almost every lookup, so dictionary bytes matter out of proportion to their share. When the index changes fast, update cost joins the trade and the best code can shift.

Two traps catch beginners here. First, treating dictionary compression as unimportant because the dictionary looks small next to postings. It is small in bytes but hot in access, so each saved megabyte avoids many seeks. Second, treating compression as free. Every code adds encode work at build time and decode work at query time. The codes taught here are picked because decode stays cheap.

Index compression exists to fit hot structures in fast memory and cut disk seeks. RCV1 at about 800,000 documents and about 400,000 terms is the running proof that naive layouts already strain memory. The next step is the ground rule for how we may shrink them.

Search teams at web scale keep hot dictionary pages in memory for exactly this reason, and phone or on-board search systems use the same idea under tight hardware limits. Fast startup and shared memory with other apps are the same cupboard problem in new clothes.

7.1.2 Lossless Against Lossy and the Case-Folding Trap

What if we saved space by merging words that look alike? Would anyone notice?

A lossless compression (a method where the exact input can be rebuilt bit for bit), written with no symbol because it is a property of the code, might save for example 3.6 MB on a dictionary while returning every term exactly. A lossy compression (a method that throws away detail to save space) might save a similar amount but return a different term. For index data only the first kind is acceptable, because a small change can change meaning and break retrieval.

The example used is case folding pushed too far. Fold United States as a country name down to a short form such as us and it collides with the pronoun us. One asks for a country. The other matches millions of ordinary sentences. Merging them saves a few bytes but corrupts answers in a way no ranking fix can undo.

That is why the rule in this material is simple. In index work, use lossless methods only. Save space, but never change what the index says. Case folding and stemming still belong in text processing where the choice is deliberate and tested. They do not belong as hidden side effects of a compression step.

Scope: Lossless here means bit-exact rebuild of dictionary strings, frequencies, gaps, and identifiers after decode. Assumption: The retrieval model decides what to normalize before indexing. Compression must preserve that decision, not second-guess it.

A common slip is to call any size reduction compression and stop asking whether meaning survived. Ask the rebuild test instead. Can you rebuild the exact term string, the exact document frequency, and the exact gap chain? If yes, the code is lossless. If no, it is a model change wearing a compression name.

Shrink the index only with codes that rebuild every byte exactly. The folding trap shows why a lossy shortcut corrupts meaning. With that rule fixed, the open question is how large the vocabulary can get.

7.1.3 How Large Can the Vocabulary Grow

Once the decision to compress is made, the next question is practical. How big will the vocabulary get. Can we set one safe fixed upper limit and plan memory once.

The answer given is no. Collections are dynamic. New documents keep arriving, new words keep appearing, and spellings plus names plus codes plus numbers keep growing the list. Enterprise search over many languages and web search over fresh pages both see steady arrivals of unseen strings. No single fixed cap stays safe for long.

The follow-up question is softer and more useful. Can we at least estimate the size. The answer is yes. That estimation job belongs to Heaps law, which is taken up next. The estimate lets builders size servers, pick pointer widths, and choose codes before the full index exists.

Do not plan for a fixed vocabulary cap. Plan for growth and estimate it early with Heaps law, which bridges this motive section to the first estimation law.

7.2 Heaps Law for Estimating Vocabulary Size

7.2.1 Mathematical Formulation

If you index a million more words tomorrow, how many brand-new words will you meet? Heaps law gives a working answer before you index them.

Heaps law (the empirical rule that links total words seen to distinct words found), written for vocabulary size and for token count, says new text keeps bringing some new words but mostly repeats old ones. An everyday picture is collecting stickers. The first pack brings many new faces. Later packs bring mostly duplicates with a few new faces each time. The mapping holds. Packs are tokens. New faces are new vocabulary. The slowdown in new faces is the sublinear growth. The picture breaks where text is highly repetitive or highly coded, because then duplicates arrive even faster or new codes arrive even quicker than plain prose suggests.

Let be vocabulary size, meaning the count of distinct terms seen so far. Let be collection size in tokens, meaning the total count of word occurrences including repeats. Let be an empirically set multiplier. Let be an empirically set exponent. Then:

Here and are not derived from theory. They are set by fitting real collections. Standard values are with near 0.5, often . For the RCV1 fit used in class, and . Speech around these numbers wobbles between nearby bands, so keep the book form as ground truth and read the RCV1 fit as .

What the form says in plain terms is direct. As grows, grows too, but not at the same rate. When , the relation says , which is the square root of , so vocabulary grows roughly with the square root of tokens times . Double the tokens and the vocabulary does not double. It rises much more slowly.

The same relation is often drawn in log log space because both and get very large and a log scale keeps them readable. Take base 10 logs on both sides. In words, log base 10 of equals intercept plus slope times log base 10 of . With the fitted numbers for RCV1:

Here 1.64 is the intercept of the fitted line and 0.49 is the slope. and keep the same meanings as above. This is the straight-line view of Heaps law. A straight line here means a power relation in the original counts. The fit is strong for above about 100,000 tokens.

To get back to , raise 10 to the power of each side. In words, 10 to the power log base 10 of is simply , so apply 10 to the power to both sides. That gives:

Split the exponent of a sum into a product, since . In words, 10 to the power of a sum is 10 to the power of the first part times 10 to the power of the second part:

Now focus on the second factor alone. Call its exponent , so . In words, log of a power brings the power out front, since , read backwards here as . So:

In words, 10 to the power log base 10 of something is just that something. Put the first factor back. is about 44, since is about , which is about 43.7. So the fitted line turns into:

That is exactly form with and for this collection and this fit. A quick check helps trust it. Dimensions match because both sides count terms. A limit check helps too. With , quadrupling doubles , which matches square-root behavior.

Picture log base 10 of on the horizontal axis and log base 10 of on the vertical axis. Data points climb as a near-straight line with slope about 0.49 and intercept about 1.64. The straightness is the visual signature of a power law. The slope under 1 is the visual signature of sublinear growth. One-sentence takeaway: a straight line in log log space means vocabulary lags tokens in raw counts.

Scope: Heaps law predicts size for natural text under stable processing. Assumption: Tokenization, case handling, stemming, and number handling stay fixed while grows. Change the processing and shifts, because folding or stemming slows growth while keeping numbers and spelling errors speeds it.

Two traps matter. First, reading and as universal constants. They are fitted per collection. Second, mixing log bases mid-derivation. Base 10 matches the intercept 1.64 here. Switch to natural logs and the intercept bookkeeping changes while the power form stays equivalent.

Heaps law with RCV1 fit turns a log log line into a memory plan. Vocabulary keeps growing but lags tokens. That fact sets up the worked fits next.

Capacity planners use this fit to size dictionary memory and to pick pointer widths before a full build, which is the same estimation habit used for web crawls and enterprise stores.

7.2.2 Worked Examples

Example 1 — RCV1 early-token fit. Take the first 1,000,020 tokens of RCV1 with and . The book form predicts:

Work it in stages. Take , which is about 6.00001. Multiply by 0.49 to get about 2.94. Add 1.64 to get about 4.58. Raise 10 to that power to get about 38,323 terms. The measured count for that slice is 38,365 terms. The gap is 42 terms, about 0.1 percent. Answer: about 38,323 predicted against 38,365 measured. Sense-check: a gap of tens on tens of thousands means the fit is close enough to plan memory and to choose compression settings. In-class speech rounds the token slice to 1,000,000, which gives the same prediction to within a handful of terms.

Example 2 — Square-root intuition. Set so . Start at with . Then . Quadruple tokens to . Then and . Tokens rose by 4 times. Vocabulary rose by 2 times. Answer: 44,000 grows to 88,000. Sense-check: doubling against quadrupling is the sublinear lag in numbers.

A third check needs no numbers. Shuffle documents at random and regrow . The curve keeps its shape because the law describes natural text growth, not one lucky document order. That robustness is why the same and stay useful across crawl orders.

7.2.3 Student Questions and Answers

Q: Can we use natural logs here, or why only base 10 logs?

A: Stay with base 10 for this fit. The intercept 1.64 belongs to base 10 logs, tied to the way the line was fitted and to bits-and-bytes thinking in this block. Natural logs describe the same curve but change the intercept and slope bookkeeping, so mixing bases mid-derivation breaks the step that turns into 44. Keep one base from the log line through the final power form.

7.2.4 Takeaways for Compression Planning

Two big conclusions are drawn. First, the dictionary does not stop growing. As rises, keeps rising through . Second, for large collections the dictionary gets large in absolute terms even though it grows more slowly than tokens. Since the dictionary is touched on almost every query, its size controls speed. The mental model has to shift. The dictionary is not a tiny fixed lookup table as in toy examples. It is huge, it keeps growing, and that is why its memory footprint must be estimated early and then compressed.

Exam note: Be ready to derive from line by line, to state with near 0.5, and to give both conclusions: growth never stops, and absolute size still gets large. That closes Heaps law and hands off to term frequencies.

7.3 Zipf Law for Term Frequencies

7.3.1 Mathematical Formulation

Why do a handful of words own most of the index while most words barely appear? Zipf law names that skew.

Zipf law (the empirical rule that links a term rank to its frequency), written for collection frequency of the -th ranked term, starts from a simple observation about natural language. A few terms are very frequent and many terms are rare. Words such as the, a, an, and, and of appear everywhere. Most other words appear rarely. Think of city sizes. A few huge cities hold millions while hundreds of small towns hold thousands each. Rank cities largest first and size falls fast with rank. Words behave the same way. The picture breaks for controlled vocabularies with capped repeats, where frequencies stay flatter than natural prose.

Rank terms from most frequent to least frequent. Let be the collection frequency of the top term, meaning its total count across the collection. Let be the collection frequency of the -th ranked term. Then:

Equivalently, is proportional to , and in logs for a constant . Here is rank as a plain integer 1, 2, 3, and each is a count. The second ranked term appears about half as often as the first, the third about one third as often, and so on.

This is a hypothesis about shape, not an exact promise for every word, but it fits well enough to guide compression choices. On RCV1 the log log plot of frequency against rank follows a line of slope about minus 1 closely enough for planning, even though the fit is not perfect.

Why this matters for compression is direct. Frequent terms own very long posting lists. If the appears in nearly every document, its list of document identifiers is enormous. Rare terms have short lists but there are many of them. A compression plan must handle both ends. Long lists from a few frequent words dominate storage, while many short lists add up through sheer count.

A useful companion form separates collection frequency from document frequency. Collection frequency, written , counts total occurrences. Document frequency, written , counts documents holding the term. Zipf law here uses to model how posting mass concentrates on top ranks.

Scope: Zipf law models natural-text skew before heavy pruning. Assumption: Ranks are stable enough that top terms stay top across large slices. Remove stop words or stem hard and the curve shifts, though the few-huge plus many-tiny shape stays.

A common slip is to read the division as a promise that rank 2 hits exactly half. Real counts wobble around the curve. Use the curve to size the problem, not to predict any single word to the unit.

Zipf shape tells the builder to aim the best codes at long lists from top ranks. That motive leads straight to the worked numbers.

7.3.2 Worked Examples

Example 1 — the, of, and. Treat the numbers as illustrative of shape rather than exact RCV1 counts. Suppose the top term occurs about 1,000,000 times. In-class speech wobbles between 100,000 and 1,000,000 here, so keep 1,000,000 as the worked anchor because it matches the halving walk used in class. Then:

Name the as rank 1, of as rank 2, and and as rank 3 to fix the pattern as 1, one half, one third. Answer: about 500,000 and about 333,333. Sense-check: a steep early fall matches the claim that a few words dominate postings.

Example 2 — Ten documents against 800,000. With 10 documents, a posting list for the that holds all 10 identifiers looks harmless at bytes. Scale to 800,000 documents where the appears in almost every one. The same list at 4 bytes each needs about 3.2 MB for one term alone. Answer: tens of bytes grow to megabytes for one frequent term. Sense-check: multiply a harmless toy list by a real collection and fixed wide integers stop fitting.

A third picture needs no arithmetic. Even after standard pre-processing, a small set of words still accounts for a very large share of posting entries. That is why frequency shape cannot be ignored when picking a postings code. Rare terms get less attention per term, but the method must still handle them cheaply since there are so many distinct rare terms.

Picture rank on the horizontal log axis and collection frequency on the vertical log axis. Points fall along a downward line of slope near minus 1. Top-left points are few but high. Bottom-right points are many but low. One-sentence takeaway: most storage mass sits top-left, most distinct terms sit bottom-right.

7.3.3 Student Questions and Answers

Q: Why divide the same top frequency by rank for different words? Real words have their own counts, not exactly CF by 2 or CF by 3.

A: The division is a model shape, not a claim that every second word hits exactly half. Start from the top collection frequency as an upper bound, then CF by 2 and CF by 3 show the expected falloff. Real counts wobble around that curve. The curve still tells us to plan for a few huge lists and many tiny ones, which is all the compression choice needs.

Student doubts often repeat here under a second wording about positions. Keep one canonical answer for the second confusion as well.

Q: Is this about positions inside a document or about postings across documents?

A: This is about postings and collection frequency, not word positions. Take 10 documents with the in each one and ignore within-document repeats for the moment. The posting list holds one entry per document that holds the term. Frequency here means how widely and how often terms occur across the collection, which is what makes some posting lists long. Positions return later with phrase and proximity data, not in this law.

7.3.4 Why Frequency Shape Controls Compression

Think of a school corridor. A few popular rooms get visited by almost every student every day. Most rooms get few visits. If you post a guard list at each door, the popular doors need huge lists. Zipf law is that corridor picture for words. It tells the index builder to spend the best codes on small gaps in long lists, because those lists dominate the total.

Exam note: State in symbols and in the words CF by 1, CF by 2, CF by 3. Rework the 1,000,000 to 500,000 to 333,333 chain. Then bridge forward: long lists from skew are why dictionary layout and gap codes come next.

Posting-heavy traffic in web search follows the same skew, so gap codes target frequent-term lists first in real engines.

7.4 What an Inverted Index Stores and What Can Be Compressed

7.4.1 Dictionary Entry Layout

What exactly are we shrinking? Name the three numbers in each dictionary row and the order that makes later tricks possible.

A dictionary (the sorted list of distinct terms with their lookup data) and postings (the per-term lists of document identifiers) are the two halves of an inverted index. Terms, tokens, and dictionary entries are used as near synonyms in speech, so do not get tripped by the label change. The point stays the same. Each distinct term points to its postings.

Each dictionary entry in the naive layout carries three parts. First the term string itself. Then the document frequency (the count of documents that hold the term), written . Then the pointer to the postings list. Terms sit in lexicographic order, meaning alphabetical order, and postings sit in ascending document order. That sorted order is what later tricks exploit.

Sorted terms let search narrow by prefix and let lookups use binary search. Sorted postings let merges scan in order and let gap coding replace large identifiers with small differences. Without sorted order, string packing, blocking, front coding, and gaps all lose their footing.

Keeping terms sorted also lets the system find a block fast and then scan inside it, a pattern reused in blocking and front coding. Keeping postings sorted lets the decoder rebuild identifiers by adding gaps back, a pattern reused in postings compression.

Scope: This layout describes a non-positional index entry before positions and weights are added. Assumption: One document frequency plus one postings pointer per term is enough for the Boolean and early ranked steps. Later scoring adds frequencies and positions without changing the dictionary logic here.

A frequent mix-up is to treat document frequency and collection frequency as the same number. Document frequency counts documents. Collection frequency counts occurrences. A term can occur 50 times in 2 documents, giving but .

The naive row is term string plus document frequency plus postings pointer, both lists sorted. That layout is simple and wasteful, which the byte math now proves.

7.4.2 Worked Examples

Example 1 — Bytes per term in the naive layout. Document frequency takes 4 bytes. Postings pointer takes 4 bytes. Term string is fixed at 20 bytes in this naive dictionary layout, since few English terms run longer and the array uses fixed-width slots. Add them:

Answer: 28 bytes per term. Sense-check: a fixed 20-byte word slot dominates the two 4-byte numbers, which already hints where the waste sits.

Example 2 — RCV1 total for the naive layout. With 400,000 terms:

Answer: 11.2 MB. Sense-check: 11.2 megabytes is not small for a structure touched on every query. If it cannot sit in fast memory, each query pays slower access. That is the headline number for the whole size ladder that follows.

Example 3 — Why fixed 20 bytes hurts both ends. A one-letter term such as a still burns 20 bytes, so 19 bytes are wasted on padding. A long term near 15 to 20 letters strains the fixed slot, and longer strings such as hydrochlorofluorocarbons cannot fit at all. Answer: short words waste space while long words overflow. Sense-check: one fixed width cannot suit a vocabulary whose average length is about 8 characters with a long tail.

Picture term length on the horizontal axis and wasted bytes per term on the vertical axis. Bars for short words tower high. Bars near 20 fall to zero. Missing bars beyond 20 mark unrepresentable words. One-sentence takeaway: fixed width is simple but unfair to both ends, which motivates packed strings next.

Exam note: Redo 28 bytes and 11.2 MB from the three parts without prompting, and state why fixed 20 bytes fails short and long words. Those two numbers anchor the 11.2 to 7.6 to 7.1 to 5.9 ladder.

7.5 Dictionary as a String with Term Pointers

7.5.1 Mathematical Formulation

If most words are far shorter than 20 letters, why pay 20 letters for every word?

Dictionary as a string (the layout where all term characters are packed end to end with no separators) replaces fixed-width term slots with an average width plus a pointer. Keep document frequency at 4 bytes and postings pointer at 4 bytes. Add a term pointer (the offset that says where a term starts in the packed string) at 3 bytes for RCV1. Store the packed characters at an average of 8 bytes per term, matching the average English term length.

Per-term width becomes:

Here the first 4 is document frequency in bytes, the second 4 is postings pointer in bytes, 3 is term pointer in bytes, and 8 is average term characters in bytes. The pointer resolves an offset into the packed character string rather than holding the characters itself.

Where does 3 bytes for the pointer come from. Pack 400,000 terms at an average 8 bytes:

Offsets into that string run from 0 to about 3,200,000. Count the bits needed as . Since is too small and covers the range, 22 bits are needed. Twenty-two bits need 3 bytes, since 2 bytes give only 16 bits and 3 bytes give 24 bits. The rule used is to round up because a little waste beats running out of address space. So the pointer width is 3 bytes for this collection. For another collection the width would be recomputed. It is not a universal constant.

A tiny picture helps. Terms such as a, the, and encyclopedia sit back to back in memory with no spaces or commas, like atheencyclopedia in one run. The pointer for a is 0, for the is 1, for the next term is 4, then 6, and so on, marking start offsets. To read the, jump to offset 1 and read forward until the next term start tells you to stop. Binary search now runs over the smaller pointer table, then follows one pointer hop to the string.

Scope: This saving assumes average term length near 8 and offsets under about 4.2 million so 3 bytes suffice. Assumption: Lookups can afford one extra pointer hop plus a length-bounded string read. When strings grow past the address range, pointer width must grow.

Two slips recur. First, treating the 3-byte pointer as fixed for all collections. Recompute it from string bytes for each collection. Second, thinking separators are still stored. They are not. The next pointer marks the end.

Packed strings trade 20 fixed bytes for about 8 average bytes plus a 3-byte offset, dropping the row from 28 to 19 bytes. The totals next show the megabyte payoff.

7.5.2 Worked Examples

Example 1 — RCV1 total with string plus pointer. With 400,000 terms at 19 bytes:

Start was 11.2 MB. Saving is:

That is about 32 percent, since is about 0.32. Nine bytes saved per term times 400,000 terms gives the same 3.6 MB. Answer: 7.6 MB total, 3.6 MB saved. Sense-check: saving 12 bytes on the word slot while spending 3 bytes on a pointer nets 9 bytes per term, a large cut.

Example 2 — Short against long. A one-byte term such as a now costs 1 character byte in the string plus shared row overhead instead of 20 fixed bytes. A 12-letter word costs 12 character bytes. An over-long word no longer overflows. It simply takes more characters in the string. Answer: cost follows true length. Sense-check: fairness replaces fixed slots, so short words stop subsidizing the layout and long words stop breaking it.

7.5.3 Why This Step Is Safe

Nothing about meaning changes. Document frequency and postings pointers keep their values. Only the term storage shape changes from fixed slots to packed characters plus offsets. Decoding costs one extra hop through the pointer, but the memory win is large and lookups stay simple. Binary search still finds the row. One follow step reads the string.

Exam note: Rebuild 3.2 MB of string, 22 bits rounding to 3 bytes, 19 bytes per term, and 7.6 MB total from scratch. Then move to blocking, which attacks the remaining pointer overhead.

Compact lookup tables in real retrieval engines use this packed-string habit wherever many short keys share one table.

7.6 Blocking the Dictionary

7.6.1 Mathematical Formulation

If every word carries its own 3-byte address, can one address serve four words?

Blocking (the trick of keeping one pointer for a group of consecutive terms instead of one pointer per term) cuts pointer overhead further. Pick a block size , meaning the count of terms per block. Store the pointer only for the first term of each block. For the rest, store each term length in 1 byte, which is enough when terms are short on average, plus the packed characters already counted in the 8-byte average. Think of flats sharing one street door number with flat letters inside. One main address gets you to the door. Short inner labels get you to each flat.

For without blocking, pointer cost for 4 terms is:

With blocking, keep 3 bytes for the first pointer plus 1 byte per term for lengths:

Saving per block is bytes. In words, one pointer per block against one pointer per term. The general form keeps bytes of pointers at the cost of length bytes, so net saving per block is bytes.

Per-term width for the whole entry drops as those savings spread across terms. The book total for RCV1 moves from 7.6 MB toward 7.1 MB at , with larger approaching a floor near 6.8 MB where only length bytes plus characters plus the two 4-byte fields stay.

Scope: Blocking helps sorted dictionaries where neighbors share a block and lengths fit in 1 byte. Assumption: Average term length stays small so 1 length byte suffices and blocks stay balanced. Very long terms or unsorted inserts weaken the saving.

A common error is to subtract pointer bytes without adding length bytes back. Both sides of the trade must stay in the sum.

Blocking swaps pointers for 1 pointer plus length bytes. The case saves 5 bytes per block. The worked totals now cash that saving in megabytes.

7.6.2 Worked Examples

Example 1 — Block size 4 on RCV1. Number of blocks is:

Saving is bytes, which is 0.5 MB. Subtract from the prior total:

Answer: 7.1 MB. Sense-check: half a megabyte saved on a 7.6 MB base is modest but free except for lookup cost, so it is worth taking.

Example 2 — Block size 8 on RCV1. Without blocking, 8 pointers cost bytes. With blocking, cost is bytes. Saving per block is bytes. Number of blocks is . Total saved is:

New total is:

Answer: 6.95 MB. Sense-check: a larger block saves more per block over fewer blocks, netting a larger total cut than .

Example 3 — Block size 16 on RCV1. Pointer plus lengths cost bytes for 16 terms, against bytes without blocking. Saving per block is bytes. Blocks number . Total saved is bytes, about 0.725 MB. New total is about MB. Answer: about 6.875 MB. Sense-check: savings keep growing but with shrinking gains, while lookup cost keeps rising, which sets up the next subsection.

7.6.3 Student Questions and Answers

Q: If bigger blocks save more memory, why not use huge blocks?

A: Lookup cost rises. Inside a block there is no pointer per term, so search walks forward term by term. If the wanted word sits at the end of a long block, every earlier term in that block is scanned. Compression keeps helping memory, but query time starts to suffer. Block size is picked per domain to balance the two, often or in teaching examples.

7.6.4 Search Cost Inside a Block

Picture 8 sorted terms in one block, for example aid, box, den, ex, job, ox, pit, win in order. To find the first term needs 1 comparison. Later terms need 2, 3, or more steps as the scan walks forward using stored lengths. In the worked sketch the blocked average lands near 2 steps for , about 25 percent more than the unblocked average near 1.6 steps on the same 8 terms, with words such as job, den, pit, box, ox, and aid used to trace paths. The exact tree shape matters less than the message. Block search is sequential inside the block, so average cost grows with block size.

Worst case is harsh. If every query term happens to sit last in its 16-term block, each lookup scans the full block. That is why block size cannot grow without limit even though the megabyte total keeps shrinking.

Think of it like a train with no internal doors marked. You enter at the front of your coach and walk past each seat to reach the last seat. Fewer doors save building cost, but every trip to the last seat costs steps. The mapping is exact. Doors are pointers. Seats are terms. Walking is length-based skipping.

Exam note: Redo the 8-block and 16-block arithmetic from scratch as block count times saving per block, and state the space-against-speed trade in one line: larger saves more bytes but forces longer linear scans. That trade motivates front coding, which squeezes strings without lengthening scans as much.

7.7 Front Coding

7.7.1 Mathematical Formulation

When sorted words share their first letters, why write those letters again and again?

Front coding (the string method that stores a shared prefix once and then only the changed tails) exploits sorted order. Since the dictionary is in lexicographic order, words with the same start sit side by side. Store the common prefix one time, then store per-word suffixes plus small length numbers and a separator mark. Think of a family surname written once on a mailbox with first names listed below. The shared name is written once. Only the differing parts repeat.

The running words are automata, automate, automatic, and automation. Their shared start is automat, which is 7 letters. The first word automata has total length 8. The tails beyond automat are a for automata with 1 extra letter, e for automate with 1 extra letter, ic for automatic with 2 extra letters, and ion for automation with 3 extra letters. A diamond mark separates suffix entries in the packed form. In words, store automat once, then store tails a, e, ic, and ion with their lengths and separators instead of repeating automat four times.

The book form writes this as a length-led run such as 8 automat, then diamonds plus tail lengths such as 1, 1, 2, 3 with tails. The first 8 is the full length of automata, which tells the decoder where the first word ends. Without that 8, a bare run of letters would give no cut point. The following 1, 1, 2, 3 pattern tells how many tail letters to take for each later word after the shared prefix.

The verbal form kept next to the code is common prefix once plus only the different endings. Encoding adds work and decoding must rebuild each word, so there is overhead on every lookup. From a pure memory view it is the strongest dictionary method in this session. On RCV1 it saves about another 1.2 MB over blocking in the reported experiment.

Scope: Front coding wins where sorted runs share long prefixes, as in large English or multilingual dictionaries. Assumption: Blocks group prefix-sharing neighbors so one prefix covers the block. Scattered or random order removes the gain.

A frequent slip is to treat it as a postings trick. It is a string trick for the dictionary half. Keep it on the dictionary side when revising.

Front coding stores automat once and rebuilds four words from short tails. The decode walk next makes the length and diamond rules concrete.

7.7.2 Worked Examples

Example 1 — Naive against front coded. Naive sequential storage repeats a u t o m a t in each of the four words, paying 7 shared letters four times. Front coded storage writes automat once and then appends short tails a, e, ic, ion with lengths 1, 1, 2, 3. The red 8 seen at the start is the length of the first full word automata, which tells the decoder where the first word ends. Answer: four copies of a 7-letter prefix collapse to one. Sense-check: saving grows with prefix length times run length, so long shared stems pay best.

Example 2 — Reading with the diamond. When the decoder meets the diamond, it knows a new suffix starts. It takes the stored tail length, grabs that many letters, glues them to automat, and emits the next word. So one diamond plus e after automat rebuilds automate. The next diamond plus ic rebuilds automatic. The next diamond plus ion rebuilds automation. Answer: automat plus tails rebuilds all four words. Sense-check: each rebuild uses the same join rule, so the decoder loop stays tiny.

Example 3 — Size ladder. Dictionary as a string gives about 7.6 MB on RCV1. Blocking with size 4 gives about 7.1 MB. Front coding with blocking gives about 5.9 MB. That is close to half of the 11.2 MB start, since is about 0.53. Answer: 11.2 to 7.6 to 7.1 to 5.9 MB. Sense-check: each trick attacks a different waste, fixed width then pointers then prefixes, so gains stack.

Picture the four words stacked with shared letters aligned left. A box around automat spans all four rows. Tails stick out right with different lengths. Diamonds sit between tails as cut marks. One-sentence takeaway: one box plus short tails replaces four full spellings.

7.7.3 Student Questions and Answers

Q: The leading 8 is confusing. Automate looks like 7 shared letters plus 1, so why 8 at the front?

A: The 8 is the full length of the first word automata, not the shared prefix length. Shared automat is 7, plus tail a is 1, so 8 marks where the first word ends in the packed run. Later numbers mark tail lengths for e, ic, and ion. Read the first number as first-word length, then read diamonds as suffix starts. Mixing those two roles is the exam trap.

A second doubt repeats around the separator under a different wording. Keep one canonical answer for it as well.

Q: Does the diamond split whole words?

A: No. The diamond splits suffix entries only. It says a new tail starts here. Rebuild by joining automat to the next tail letters. That is why a lone diamond plus one letter can complete automate. Whole-word gaps never appear in this code.

7.7.4 Practical Note and Warning

Front coding shines at very large scale, such as search engines, where dictionary memory dominates and prefix runs are common. For small classroom or dissertation builds, the added encode and decode care often outweighs the gain. Extra code paths, harder updates, and slower single lookups can cost more than a megabyte saved.

Exam note: Remember 11.2, 7.6, 7.1, and 5.9 in order with the trick behind each drop, plus diamond as suffix separator and first-word length 8 for automata. That ladder closes dictionary compression and hands off to postings, which are far larger.

Very large engines accept the decode care because dictionary bytes stay hot. Small projects often skip this last squeeze and keep blocked strings.

7.8 Postings Compression with Gaps and Variable Byte Codes

7.8.1 Mathematical Formulation

Postings dwarf the dictionary by ten times or more. How do we store 800,000 identifiers in far fewer than 20 bits each?

Postings (the lists of document identifiers per term) are usually much larger than the dictionary, often by a factor of 10 or more, so they deserve their own compression. A document identifier (the integer id for one document), written , runs from 1 to about 800,000 on RCV1. In a naive 4-byte layout each posting costs 32 bits. Even a tight fixed width needs about 20 bits, since is under 20 and 3 bytes cover it. The goal is far fewer than 20 bits wherever possible. Think of house numbers on one street. Writing the full street address for every house repeats the street each time. Writing only steps from the last house, such as 3 doors on, then 5 doors on, uses small numbers most of the time.

Purpose. Replace large sorted identifiers with small gaps that cost fewer bits on average.

Posting lists are sorted ascending, so store gaps between successive identifiers instead of raw identifiers. Keep the first identifier as is, then store differences. For a very common word such as the that appears in documents 1, 2, 5, and so on, gaps such as 1, 1, and 3 are tiny. Small numbers need fewer bits. A rare word such as arachnocentric may have a huge gap such as 248,100, but it occurs rarely, so its cost is paid rarely. Frequent terms get small gaps often. Rare terms get big gaps seldom. That asymmetry is what makes gap coding win.

The ideal width hint is simple. If average gap is , aim for about bits per gap. In words, if the gap is 7, covers it, so about 3 bits. If the gap needs up to , about 10 bits. Real codes round to byte shapes for speed.

Inputs and outputs. Input is a sorted list such as 824, 829, 215406. Output is a gap list such as 824, 5, 214577, where the first value stands as is and each later value is the difference from the prior identifier. The decoder adds gaps back to rebuild identifiers.

Variable byte coding (the byte-aligned variable-length code that uses 7 data bits plus 1 continuation bit per byte) is the practical code taught here. Call the top bit , the most significant bit of each byte. In words, 7 bits carry value and the 8th bit decides. If , more bytes follow for this number. If , this byte is the last byte of this number. The bit never counts toward the numeric value. It is only the stop-or-continue signal for the decoder.

Picture the gap distribution as a bar chart. Gap size grows along the horizontal axis. Count of gaps falls steeply along the vertical axis. A tall bar at gap 1 towers over a tiny bar at gap 248,100. One-sentence takeaway: most gaps are tiny, so a code that spends 1 byte on tiny gaps and 3 bytes on rare giants wins on average.

Scope: Gap plus variable bytes assumes sorted postings with skewed gaps from Zipf-like frequencies. Assumption: Decode stays byte-aligned for speed, accepting some waste against bit-level codes. When disk is the tightest limit, bit-level codes such as gamma trade slower decode for smaller size.

A common slip is to count the bit as place value 128. Drop first, then convert only the remaining 7 bits. Another slip is to treat gaps as identifiers. Every value after the first must be added back.

Gaps turn huge identifiers into mostly tiny differences, and variable bytes give tiny gaps 1 byte and rare giants more bytes. The worked bytes next prove the loop.

7.8.2 Worked Examples

Example 1 — First identifier 824 needs two bytes. Split 824 into 7-bit groups. Since , groups are 0000110 for 6 and 0111000 for 56. Prepend to the first group and to the last:

The first byte carries high bits with , meaning continue. The second byte carries low 7 bits with , meaning stop. While converting, ignore each bit and use only the seven value bits per byte. Join the value bits as . Answer: 824 encodes as 2 bytes. Sense-check: a value above 127 cannot fit 7 bits, so 2 bytes is the minimum.

Example 2 — Gap 5 needs one byte. Five in 7-bit binary is 0000101. Prepend to mark last byte, giving 10000101. Decoder sees at once, so it stops after one byte, drops , converts 0000101 to 5, and adds to the prior identifier. So . Answer: gap 5 is 10000101 and rebuilds 829. Sense-check: tiny gaps cost one byte, which is why frequent terms with gap-1 runs compress best.

Example 3 — Large gap 214577 needs three bytes. Write , so groups are 13, 12, 49. Bytes are 00001101 with , 00001100 with , and 10110001 with :

Drop the three bits, join the three 7-bit groups, convert to 214577, then add to the running identifier . Answer: 3 bytes for the giant gap. Sense-check: rare giants cost more bytes but occur rarely, so the average stays low.

Example 4 — Classroom decode drill 9, 395, 521. A byte vector is read 8 bits at a time. First group ends with , so stop. Dropping leaves value bits for 9. First document identifier is 9. Next group starts with , so continue. The following group has , so stop. Its value bits convert to 386. In-class speech briefly says 15,395 in one garbled aside, but the running addition plus the next step is the only chain consistent with the stated identifiers, so keep gap 386 here. Add to get . Next byte group converts to 126 with . Add to get . Answer: identifiers 9, 395, 521 from gaps 9, 386, 126. Sense-check: middle numbers are gaps, not identifiers, and each must be added back.

Example 5 — Overall postings ladder. Storing RCV1 postings at 32 bits is about 400 MB for 100,000,000 postings. Tight 20-bit fixed width is about 250 MB. Variable byte gap coding is about 116 MB in the reported experiment. Gamma codes can push to about 101 MB but sit beyond this session. Answer: 400 to 250 to 116 MB. Sense-check: gap plus variable length cuts postings to less than a third of the naive size, which directly cuts input output during merges.

7.8.3 Student Questions and Answers

Q: When in the top bit, do we still add its place value like 128 into the number?

A: No. The top bit is never part of the value. If it were counted, a gap of 5 with leading 1 would wrongly gain 128. Drop first, then convert only the remaining 7 bits. means keep reading. means stop and convert what was kept. Practice with 10000101: drop the leading 1, convert 0000101 with place values 1, 2, 4, 8, 16, 32, 64 to get 4 plus 1, which is 5.

A second doubt repeats around why the extra bit exists at all. Keep one canonical answer for it.

Q: Why keep the extra bit at all?

A: Without it the decoder sees only an undifferentiated run of zeros and ones and cannot tell where one gap ends and the next starts. The model only knows to read 8 bits at a time. marks the cut. First 8 bits with say take another byte. Next 8 bits with say stop here, convert, and start a fresh number at the next bit. One bit per byte buys self-delimiting codes with no extra table.

A third wording asks about back-to-back stops. Keep the same short rule.

Q: After a block ending in , does the next byte mean a new document at once?

A: Yes. Each closes one number. The very next bit starts the next gap. That is how the drill moves from identifier 9 to gap 386 to gap 126 with no extra separators. The first number stands alone. Every later number adds back.

7.8.4 Decoding Procedure in Order

First take 8 bits. Look at . If , keep the 7 value bits aside and read the next 8 bits. If , keep its 7 value bits and stop. Join kept groups in order with , convert the joined binary to decimal for the gap, then add to the prior identifier to get the true identifier. Repeat for the next 8 bits. The first number has no prior identifier, so it stands as is. Every later number is a gap that must be added back.

Exam note: Practice the exact loop of watch C, join value bits, convert, add back on 824 to 829 and on 9 to 395 to 521. State the ladder 400, 250, 116 MB with reasons. That closes postings compression and opens ranking, where counts start to matter as weights.

Variable byte gap codes underlie fast merge steps in real engines because less bytes read means less wait per query.

7.9 Ranked Retrieval and the Jaccard Coefficient

7.9.1 Mathematical Formulation

A library query returns 1,000 unordered hits. Who ranks them so the best ten come first?

Ranked retrieval (the setup that returns an ordered top list instead of an unordered matching set) replaces the old Boolean habit of answering 1 for match and 0 for no match. A library query for best data science books that returns 1,000 unordered hits forces the user to rank by hand. Modern expectation is the top 10 or 20 in order. Most users decide in about 8 seconds on a top result, reading the headline and moving on if it misses. Backend work exists to earn that fast click. That pressure is what search engine optimization lives on.

Term frequency (the count of a term in one document), written , and term weighting (the score for how much that term should matter) are the two ideas that carry the new model. A common word such as the can be frequent but weak. A rare word such as cryptocurrency can be rare but strong. Not all words deserve equal say. Think of votes where some voters studied the issue and others repeat slogans. Counting all votes equally misleads. Weighting votes by knowledge helps.

The first scoring try is the Jaccard coefficient (the overlap of two word sets divided by their union). Let be the query term set and be the document term set. Let be the count of shared distinct terms and the count of distinct terms in either set. Then:

In words, A intersection B by A union B, or overlap by union. Range is 0 to 1. Score is 1 when sets match exactly and 0 when they share nothing. Here sets hold distinct terms after pre-processing, so repeats collapse to one member before the ratio is taken.

Range check confirms sense. Identical sets give numerator equal to denominator, so 1. Disjoint sets give numerator 0, so 0. Boundary behavior stays inside 0 to 1 because an intersection can never outgrow its union.

Scope: Jaccard here scores sets of distinct terms after pre-processing. Assumption: Repeats, order, and length carry no weight in this first try. Those limits are the reason stronger weights follow.

A common slip is to feed raw counts into the same ratio. Sets keep unique members only. Two copies of march still give one member.

Jaccard turns overlap into a 0-to-1 score but sees only set membership. The worked queries expose what that blindness costs.

7.9.2 Worked Examples

Example 1 — Moonwalk query. Query set is moonwalk. Document is a review of a dance performance that repeats moonwalk many times plus other words. Intersection holds moonwalk, so the ratio can reach 1 on sets even though the repeat count is ignored. Answer: high Jaccard despite rich repeat evidence left unused. Sense-check: repeating a strong clue many times carries information, but Jaccard on sets cannot see it, which is the first named gap.

Example 2 — Ides of march query with three documents. Query terms after pre-processing are ides, of, march. Document 1 shares march once and has 6 distinct terms total with the query, so . Document 2 shares march, with march appearing twice in raw text but collapsing to one set member, and has 5 distinct terms total with the query, so . Document 3 shares march and has 7 distinct terms total with the query, so . Intuition wants document 2 to win by a wide margin because march repeats there, yet scores stay flat at , , and . Answer: 0.167, 0.20, 0.143 with almost no separation. Sense-check: length differences leak in only through union size, not through a length model, and repeats vanish entirely.

Picture three bars for the three documents at heights 0.167, 0.20, and 0.143. Bars sit nearly level while intuition expects the middle bar to tower. One-sentence takeaway: set overlap compresses a strong repeat signal into a near-tie.

7.9.3 Student Questions and Answers

Q: Document 2 has march twice, so why is the match still 1? And where does long march fit?

A: Sets keep unique members only. After pre-processing, two copies of march still give one member, so intersection stays 1. The comparison each time is query against one document, first query with document 1, then query with document 2, then query with document 3. Long is not in the query set used here, so it does not enter the intersection. To reward repeats the model must move from sets to counts, which is the next section.

A second wording asks whether one scattered hit still counts. Keep one canonical answer for that distinct confusion.

Q: If a long document of 800 words matches once, is that still a match?

A: On sets it still counts as overlap, but that is exactly the weakness. One hit in 800 words should not weigh the same as focused repeats in a short text. Jaccard has no term-frequency weight and no real length correction, so it overrates scattered single hits. A long document can collect a match by chance while a tight document with repeats gets no extra credit.

7.9.4 Why Jaccard Alone Falls Short

Two gaps are named. First, term frequency is ignored. Second, document length is ignored. A very long document can collect a match by chance, while a tight document with repeats gets no extra credit. The verdict kept from class is that Jaccard is a handy overlap check and can serve as an add-on, but it cannot rank alone. It also powers spelling and duplicate_outline checks elsewhere, such as k-gram overlap, but ranking needs weights that see repeats and length.

Exam note: Write , rework , , for ides of march, and state both limits: no term frequency and no length handling. That sets up the move from incidence to counts.

7.10 From Incidence Matrix to Count Matrix and Term Frequency

7.10.1 Mathematical Formulation

What changes if a 1 becomes a count? Everything about repeats starts to matter.

A term document incidence matrix (the binary table with 1 when a term occurs in a document and 0 when it does not) was the Boolean starting point. A count matrix (the same table holding occurrence counts instead of 0 or 1) is the next step. Replace each 1 with how many times the term occurs in that document. Now the system can tell that one term matters more in one document than in another. Think of attendance sheets against score sheets. Attendance marks present or absent. Score sheets record how many goals each player scored. Counts carry the weight that binary marks hide.

Let be term frequency, meaning raw count of term in document . The count matrix stores in row , column where the incidence matrix stored 0 or 1. Documents become vectors of counts, often sparse because most entries stay zero. Scoring can now favor the high-count document for a query term instead of tying all documents that merely mention it.

A bag of words (the model that counts words but drops order) comes with this step. Order is lost. John is quicker than Mary and Mary is quicker than John give the same multiset of words. Man biting a dog and dog bites a man also collide. Meaning flips while counts stay fixed. The classic TF IDF model taught next keeps the bag assumption, so it cannot fix order. Later models built on top address that gap. The limit is stated openly so no one expects order handling from counts alone.

Scope: Count vectors suit topical relevance where repeats signal focus. Assumption: Repeats add evidence but with shrinking returns, and order carries no signal for this model. Phrase or order-heavy needs sit outside this step.

A common slip is to expect the count matrix to fix order. It does not. It fixes repeat blindness while keeping order blindness.

Counts replace bits so repeats count. Order still does not. That pair of facts frames the worked collisions next.

7.10.2 Worked Examples

Example 1 — Count vector sketch. A document vector for a play holds entries such as 73, 157, 227, and 10 for successive terms. In-class speech garbles the exact term labels aligned to those counts, so keep the counts as stated and read them as successive term slots rather than assigning labels that were not stated with usable precision. Compare two documents on one term. Document A holds 157 copies. Document B holds 10 copies. The scorer now favors A for that term where the binary matrix tied them at 1 and 1. Answer: 157 beats 10 where 1 tied 1. Sense-check: sparsity stays since most entries are still zero, but buried signals surface because non-zero cells now carry weight.

Example 2 — Order collision. Take John is quicker than Mary against Mary is quicker than John. Bag counts match term for term: John 1, is 1, quicker 1, than 1, Mary 1. Retrieval scores match, yet the claim reverses. The same holds for dog bites man in both orders. Answer: identical vectors, opposite meanings. Sense-check: with almost no math, the pair fixes the bag limit in memory.

Picture two sentences as two word piles. Both piles hold the same colored chips in the same numbers. Only the string order differs. One-sentence takeaway: piles match while stories flip.

7.10.3 Why Raw Frequency Needs Dampening

Term frequency, written , meaning raw count of term in document , helps, but raw counts overshoot. A document with 10 copies of a word is more relevant than one with 1 copy, but not 10 times more relevant. A burst of the does not make the text 10 times more about anything. Relevance rises with repeats and then flattens. The session stops at this cliffhanger on purpose. The next session turns raw into a dampened weight and builds full TF IDF, which is also named as the exam boundary.

Exam note: State why raw cannot be used as is with the 10 against 1 example, define the count matrix against the incidence matrix, and give the John-Mary collision as the bag limit. That closes the bridge into dampened TF IDF next time.

Count vectors over binary incidence matrices are the step that lets scorers favor repeat-heavy documents, leading into TF IDF and later neural ranking stacks in real systems.

Exam Guidance Summary

Expect a calculation question from this block, likely blocking arithmetic, front-coding tails, or variable-byte decode with add-back. Practice blocking as block count times saving per block for , , and , landing at 7.1 MB, 6.95 MB, and about 6.875 MB from 7.6 MB. Practice front coding with automat plus tails a, e, ic, ion, diamond as suffix separator, and first-word length 8. Practice the decode loop of watch , join value bits, convert, add back on 824 to 829 and on the 9, 395, 521 chain with gaps 9, 386, 126.

Exam note: Rewrite the RCV1 ladder 11.2, 7.6, 7.1, 6.95, 6.875, and 5.9 MB with the trick behind each drop. Rewrite the Heaps derivation from to line by line. Rewrite Jaccard with the , , ides of march numbers and both limits, no term frequency and no length handling.

Syllabus runs till vector space model, with TF IDF opening next time plus a revision slot. Previous year papers are posted on the course portal for practice. Start early because the subject looks easy but holds many small facts that are easy to mix, such as diamond as suffix separator, first-word length 8 for automata, as stop, and gaps needing add-back. Raw with the 10 against 1 dampening point and the John-Mary bag limit are revision-ready as the bridge to next time.

Key Industry Applications

Memory-first index design keeps hot dictionary data in fast memory so queries avoid disk seeks, which matters for phones, laptops sharing memory with other apps, and enterprise servers over multiterabyte stores. RCV1-scale collections force estimation with Heaps law before full indexing to size servers and to pick pointer widths and compression settings. Zipf-shaped skew explains why a handful of frequent terms dominate posting storage and why gap codes target those long lists first.

Packed dictionary strings with term pointers underlie compact lookup tables in retrieval engines, cutting RCV1 from 11.2 MB to 7.6 MB in the worked chain. Blocking trades a little lookup walk for memory savings down to 7.1 MB and below, a standard space-against-speed choice tuned per domain. Front coding suits very large search engine dictionaries where prefix runs are common, reaching about 5.9 MB with blocking, while small projects often skip it because decode care outweighs the win.

Variable byte gap codes shrink RCV1 postings from about 400 MB toward about 116 MB in the stated comparison, which directly cuts input output during merges while keeping decode byte-aligned and fast. Gamma variants push to about 101 MB where disk matters more than speed. Ranked top-10 retrieval with 8-second user behavior drives search engine optimization and backend ranking work. Count vectors over binary incidence matrices let scorers favor repeat-heavy documents, the step that leads into TF IDF and later neural ranking stacks.

IR Lecture 7 notes · Index Compression and Ranked Retrieval

Information Retrieval· postgraduate· 2026-09-14

Sections Breakdown

1Why Index Compression Matters and Why It Must Stay Lossless

Memory against disk motive with cupboard packing picture; lossless rule with folding trap; vocabulary growth must be estimated

2Heaps Law for Estimating Vocabulary Size

Heaps law M = K T^B estimated from log log fit with K = 44 and B = 0.49 on RCV1

3Zipf Law for Term Frequencies

Zipf law links term rank to collection frequency and drives long posting lists

4What an Inverted Index Stores and What Can Be Compressed

Naive dictionary layout with term string, document frequency, and postings pointer totals 11.2 MB

5Dictionary as a String with Term Pointers

Dictionary as packed string with term pointers cuts RCV1 dictionary to 7.6 MB

6Blocking the Dictionary

Blocking shares one pointer per block but forces sequential search inside blocks

7Front Coding

Front coding stores shared prefix automat once with suffix tails and diamond separators

8Postings Compression with Gaps and Variable Byte Codes

Gaps with continuation bit let variable byte decoder split and rebuild postings

9Ranked Retrieval and the Jaccard Coefficient

Jaccard overlap scoring ignores frequency and length limits

10From Incidence Matrix to Count Matrix and Term Frequency

Count matrix replaces binary incidence with repeat counts under bag of words

Postgraduate students in Information Retrieval

Exam Revision Notes

Below is the distilled, exam-ready core. Every entry comes from the full explanation above. Use this section for rapid review; return to the main notes when a point needs more context.

Why Index Compression Matters and Why It Must Stay Lossless

Must-know: Compress to fit hot index parts in memory, using lossless codes only

Top pitfall: Treating dictionary bytes as unimportant because they look small next to postings

Self-check: Why must index compression stay lossless?

Connects to: 7.2, 7.4

Heaps Law for Estimating Vocabulary Size

Must-know: Heaps law M = K T^B with RCV1 fit M = 44 T^0.49; dictionary keeps growing but lags tokens

Top pitfall: Treating K and B as universal constants or mixing log bases mid-derivation

Self-check: Derive M = 44 T^0.49 from log10 M = 1.64 + 0.49 log10 T

Connects to: 7.1, 7.3

Zipf Law for Term Frequencies

Must-know: Zipf law cf_i = cf_1 / i explains few huge posting lists and many tiny ones

Top pitfall: Reading Zipf division as exact per-word promise instead of model shape

Self-check: If top term occurs 1,000,000 times, what does Zipf predict for rank 2 and 3?

Connects to: 7.2, 7.8

What an Inverted Index Stores and What Can Be Compressed

Must-know: Naive dictionary row costs 28 bytes per term, 11.2 MB on RCV1

Top pitfall: Confusing document frequency with collection frequency

Self-check: Redo 28 bytes and 11.2 MB from the three parts

Connects to: 7.1, 7.5

Dictionary as a String with Term Pointers

Must-know: Packed string drops dictionary to 19 bytes per term and 7.6 MB total

Top pitfall: Treating the 3-byte pointer as universal instead of recomputed per collection

Self-check: Why does the term pointer need 3 bytes on RCV1?

Connects to: 7.4, 7.6

Blocking the Dictionary

Must-know: Blocking with k = 4 saves 5 bytes per block to reach 7.1 MB; larger k saves more but slows lookup

Top pitfall: Growing block size without limit while ignoring linear scan cost

Self-check: Redo block size 8 arithmetic from block count times saving per block

Connects to: 7.5, 7.7

Front Coding

Must-know: Front coding stores automat once with tails a, e, ic, ion to reach 5.9 MB

Top pitfall: Reading diamond as whole-word gap or 8 as shared prefix length

Self-check: What do the leading 8 and the diamond marks mean?

Connects to: 7.6, 7.8

Postings Compression with Gaps and Variable Byte Codes

Must-know: Gaps plus variable byte codes cut RCV1 postings from 400 MB toward 116 MB

Top pitfall: Counting the C bit as value 128 or treating gaps as identifiers without adding back

Self-check: Decode 824 to 829 and the 9, 395, 521 chain with the C rule

Connects to: 7.3, 7.7

Ranked Retrieval and the Jaccard Coefficient

Must-know: Jaccard overlap by union ignores term frequency and document length

Top pitfall: Feeding raw counts into set ratio or expecting length correction from Jaccard

Self-check: Why do ides of march scores 1/6, 1/5, 1/7 stay flat despite repeats?

Connects to: 7.8, 7.10

From Incidence Matrix to Count Matrix and Term Frequency

Must-know: Count matrix stores tf counts; bag of words drops order; raw tf needs dampening

Top pitfall: Expecting count matrix to fix word order

Self-check: Why can raw tf with 10 against 1 not be used as is?

Connects to: 7.9

Was this lecture useful?

Loading comments…
🤖

BitsNotes AI Assistant

Subject Notes Assistant

Configure AI Chat

Choose how to access the chatbot
Have your own API key?

Switch to "Bring Your Own Key" tab above for unlimited access with any OpenAI-compatible provider.

🔑 Enter API key above to fetch live models from provider, or enter model name manually.
OpenAI-Compatible API Support

Choose any provider preset (Gemini, DeepSeek, Kimi, GLM, MiniMax, Qwen, OpenAI, Groq, Ollama, etc.) or enter a custom endpoint URL.

Security & Privacy First

Your API key is sent directly from your browser to your specified provider. BitsNotes servers never store or see your key.