LeetLLM
My PlanLearnGlossaryTracksPracticeBlog
LeetLLM

Your go-to resource for mastering AI & LLM systems.

Product

  • Learn
  • Glossary
  • Tracks
  • Practice
  • Blog
  • RSS

Legal

  • Terms of Service
  • Privacy Policy

© 2026 LeetLLM. All rights reserved.

All Topics
Your Progress
0%

0 of 177 articles completed

🛠️Computing Foundations0/9
Git, Shell, Linux for AIDocker for Reproducible AIPython for AI EngineeringNumPy and Tensor ShapesCUDA for ML TrainingMPS & Metal for ML on MacData Structures for AISQL and Data ModelingAlgorithms for ML Engineers
📊Math & Statistics0/8
Gradients and BackpropVectors, Matrices & TensorsLinear Algebra for MLAdam, Momentum, SchedulersProbability for Machine LearningStatistics and UncertaintyDistributions and SamplingHypothesis Tests, Intervals, and pass@k
📚Preparation & Prerequisites0/13
Neural Networks from ScratchCNNs from ScratchTraining & BackpropagationSoftmax, Cross-Entropy & OptimizationRNNs, LSTMs, GRUs, and Sequence ModelingAutoencoders and VAEsThe Transformer Architecture End-to-EndLanguage Modeling & Next TokensFrom GPT to Modern LLMsPrompt Engineering FundamentalsCalling LLM APIs in ProductionFirst AI App End-to-EndThe LLM Lifecycle
🧮ML Algorithms & Evaluation0/11
Linear Regression from ScratchLogistic Regression and MetricsDecision Trees, Forests, and BoostingReinforcement Learning BasicsValidation and LeakageClustering and PCACore Retrieval AlgorithmsDecoding AlgorithmsExperiment Design and A/B TestingPyTorch Training LoopsDataset Pipelines and Data Quality
📦Production ML Systems0/6
Feature Engineering for Production MLBatch and Streaming Feature PipelinesGradient Boosted Trees in ProductionRanking and Recommendation SystemsForecasting and Anomaly DetectionMonitoring Predictive Models
🧪Core LLM Foundations0/8
The Bitter Lesson & ComputeBPE, WordPiece, and SentencePieceStatic to Contextual EmbeddingsPerplexity & Model EvaluationFile Ingestion for AIChunking StrategiesLLM Benchmarks & LimitationsInstruction Tuning & Chat Templates
🧰Applied LLM Engineering0/24
Dimensionality Reduction for EmbeddingsCoT, ToT & Self-Consistency PromptingFunction Calling & Tool UseMCP & Tool Protocol StandardsContext EngineeringPrompt Injection DefenseResponsible AI GovernanceData Labeling and Human FeedbackEvaluating AI AgentsProduction RAG PipelinesHybrid Search: Dense + SparseReranking and Cross-Encoders for RAGRAG Evaluation for Reliable AnswersLLM-as-a-Judge EvaluationBias & Fairness in LLMsHallucination Detection & MitigationLLM Observability & MonitoringExperiment Tracking with MLflow and W&BPrompt Optimization with DSPyModel Versioning & DeploymentSemantic Caching & Cost OptimizationLLM Cost Engineering & Token EconomicsModel Gateways, Routing, and FallbacksDesign an Automated Support Agent
🎓Portfolio Capstones0/9
Capstone: Delivery ETA PredictionCapstone: Product RankingCapstone: Demand ForecastingCapstone: Image Damage ClassifierCapstone: Production ML PipelineCapstone: Document QACapstone: Eval DashboardCapstone: Fine-Tuned ClassifierCapstone: Reproducible ML Study
🧠Transformer Deep Dives0/8
Sentence Embeddings & Contrastive LossEmbedding Similarity & QuantizationScaled Dot-Product AttentionVision Transformers and Image EncodersPositional Encoding: RoPE & ALiBiLayer Normalization: Pre-LN vs Post-LNMechanistic InterpretabilityDecoding Strategies: Greedy to Nucleus
🧬Advanced Training & Adaptation0/16
Scaling Laws & Compute-Optimal TrainingPre-training Data at ScaleBuild GPT from Scratch LabJAX for PyTorch ResearchersContinued Pretraining for Domain ShiftSynthetic Data PipelinesSupervised Fine-Tuning PipelineMixed Precision TrainingDistributed Training: FSDP & ZeROLoRA & Parameter-Efficient TuningReward Modeling from Preference DataRLHF & DPO AlignmentConstitutional AI & Red TeamingRLVR & Verifiable RewardsKnowledge Distillation for LLMsModel Merging and Weight Interpolation
🤖Advanced Agents & Retrieval0/16
Vector DB Internals: HNSW & IVFAdvanced RAG: HyDE & Self-RAGGraphRAG & Knowledge GraphsRAG Security & Access ControlStructured Output GenerationReAct & Plan-and-ExecuteGuardrails & Safety FiltersCode Generation & SandboxingComputer-Use / GUI / Browser AgentsHuman-in-the-Loop Agent ArchitectureAI Coding Workflow with AgentsAgent Memory & PersistenceAgent Failure & RecoveryRecursive Language Models (RLM)Multi-Agent OrchestrationCapstone: Production Agent
⚡Inference & Production Scale0/19
Inference: TTFT, TPS & KV CacheMulti-Query & Grouped-Query AttentionKV Cache & PagedAttentionPrefix Caching and Prompt CachingFlashAttention & Memory EfficiencyContinuous Batching & SchedulingScaling LLM InferenceModel Parallelism for LLM InferenceModel Quantization: GPTQ, AWQ & GGUFLocal LLM DeploymentSLM Specialization & Edge DeploymentSpeculative DecodingLong Context Window ManagementMixture of Experts ArchitectureMamba & State Space ModelsReasoning & Test-Time ComputeAdvanced MLOps & DevOps for AIGPU Serving & AutoscalingA/B Testing for LLMs
🏗️System Design Capstones0/9
Content Moderation SystemCode Completion SystemMulti-Tenant LLM PlatformLLM-Powered Search EngineVision-Language Models & CLIPMultimodal LLM ArchitectureDiffusion Models: Images & TextReal-Time Voice AI AgentReasoning & Test-Time Compute
🎤AI Lab Interviewing0/4
AI Lab Coding Interview: Python SystemsAI Lab System Design InterviewAI Lab Behavioral InterviewAI Lab Technical Presentation
🔬Project Deep Dives0/17
Deep Dive - vLLMDeep Dive - SkyRLDeep Dive - FlashAttentionDeep Dive - FlashInferDeep Dive - DeepGEMMDeep Dive - NCCLDeep Dive - MegatronDeep Dive - DeepSpeedDeep Dive - RayDeep Dive - MLflowDeep Dive - PyTorchDeep Dive - TransformersDeep Dive - SGLangDeep Dive - slimeDeep Dive - DeepEPDeep Dive - TinkerDeep Dive - Light-PEFT
Back to Topics
LearnComputing FoundationsData Structures for AI
⚙️EasyMLOps & Deployment

Data Structures for AI

Choose lists, inverted indexes, heaps, queues, and caches by the operations an AI system must serve.

12 min read
Learning path
Step 7 of 177 in the full curriculum
MPS & Metal for ML on MacSQL and Data Modeling

Personalize this lesson

Adapt explanations and teaching visuals to your background and preferred voice.

Data structures decide what an AI system can find, update, rank, and reuse quickly. If the structure matches the operation, a retriever can jump to the right model note, a background worker can process embedding jobs in order, and a retrieval cache can reuse ranked document IDs without serving stale results.

An engineer searches an internal model-serving notebook and types:

token hit

Behind the scenes, the system has thousands of technical notes. It can't read each note from start to finish under a tight latency budget. It needs a way to jump straight to the handful of notes that mention those words.

That jump is the job of a data structure. Arrays and tensors are good when position is the whole story: if you know row 2, column 1, you can land on the value instantly. CUDA and MPS explain where those tensors execute. Many systems start somewhere else: a word like token, a repeated query like token hit, or a stream of jobs waiting to be processed.

Production AI products don't use one data structure for every job. A lexical retriever can index terms, an ingestion worker can queue jobs, and a retrieval cache can reuse ranked IDs only while their source documents remain current. Each structure exists because a particular operation repeats.

Picking a structure by the operation it must serve

Ask one question before you pick a structure: what operation must it serve?

  • Do I need ordered items?
  • Do I need exact lookup by key?
  • Do I need uniqueness?
  • Do I need the best few results?
  • Do I need first-in, first-out (FIFO) work?
  • Do I need to reuse previous results safely?

That's the real skill behind data structures. You aren't memorizing names. You're matching an operation to a shape.

Worked retrieval path for query token hit: three technical notes become posting lists token->{0,2} and hit->{2}, candidates narrow to docs 0 and 2, and top-k ranks doc 2 first. Worked retrieval path for query token hit: three technical notes become posting lists token->{0,2} and hit->{2}, candidates narrow to docs 0 and 2, and top-k ranks doc 2 first.
The retrieval path narrows work before ranking: documents become posting lists, posting lists produce a small candidate set, and top-k keeps the best few IDs.

Position-based access works when coordinates are known. Here the query starts with a term, a top-k request, or a work queue, so the shape has to change.

A tiny retrieval story

One tiny technical-note search story carries the rest of the lesson. The documents are small enough to trace by hand, but the ideas scale to the retrieval layer inside a retrieval-augmented generation (RAG) system, where a large language model (LLM) answers with retrieved evidence.

doc idtext
0token cache eviction
1gradient checkpointing memory
2token hit cache

User query:

token hit

This story appears five times:

  1. A list scan to show the smallest correct solution.
  2. A dictionary of sets to make term lookup fast.
  3. A heap to keep the top results.
  4. A queue to show first-in, first-out work.
  5. A cache to show safe reuse.

The list scan: the smallest working version

A list is the right starting point because the data is tiny and the order of documents is stable.

If you scan each document by hand, the match counts look like this:

doc idcontains tokencontains hittotal matches
0101
1000
2112

Document 2 should rank above document 0.

For beginners, a list scan isn't "wrong." It's the smallest working version. The mistake is staying with a full scan after the question has changed.

When the corpus grows from 3 documents to 3 million, a query like token hit shouldn't force the system to reread each document. A full scan touches every document, so its cost grows in proportion to the corpus size. A dictionary lookup, by contrast, is expected amortized O(1) for the term key: it hashes the key directly to its slot.[1]Reference 1Designing Data-Intensive Applications.https://dataintensive.net/ That doesn't make the whole search constant-time. After the O(1) term lookup, scanning the posting list is O(|postings[term]|), so common terms whose postings are Θ(corpus) still dominate end-to-end lexical retrieval. The retriever then ranks the resulting candidates. The next chapter formalizes this gap with Big-O notation; for now, focus on the entry point: the data structure must let the query enter the system in its natural form, by term, not by document position.

Building an inverted index

The query starts with a term such as token. That means the system should jump from a term to the matching documents.

This is what an inverted index does.

An inverted index maps each term to its posting list. A posting records a matching document ID; larger indexes can store additional information such as term positions or term frequency. In this first version, a Python set[int] is enough because our score asks only whether each query term appears in each document.[2]Reference 2Introduction to Information Retrieval.https://nlp.stanford.edu/IR-book/

Build the index by hand

Split each document into terms and store the matching document IDs:

termdocument IDs
token{0, 2}
cache{0, 2}
eviction{0}
gradient{1}
checkpointing{1}
memory{1}
hit{2}

Now the query can enter through the index:

query termposting list
token{0, 2}
hit{2}

Turn those posting lists into match counts:

doc idmatches from tokenmatches from hitfinal score
0101
2112

Document 2 wins because it matches both terms. Document 0 still matters because it matches one term.

Why a set lives inside the dictionary

The dictionary solves exact term lookup. The set solves uniqueness.

Suppose document 2 were token token hit. The posting list for token should still contain document 2 once, not twice. That's why the value is a set of document IDs instead of a list of document IDs.

This is a good beginner habit:

  • Dictionary asks: "given this key, where is the value?"
  • Set asks: "have I already seen this item?"

Production lexical indexes commonly keep ordered, compressed posting lists and richer statistics. The Python set is a teaching choice: it makes membership and duplicate prevention visible before you optimize storage or intersections.[2]Reference 2Introduction to Information Retrieval.https://nlp.stanford.edu/IR-book/

A repeated term is the smallest proof. In the demo below, document 2 says token twice, but membership in the token posting set still contributes one document ID.

posting-list-membership.py
1from collections import defaultdict 2 3docs_with_repeat = [ 4 "token cache eviction", 5 "gradient checkpointing memory", 6 "token token hit", 7] 8postings: dict[str, set[int]] = defaultdict(set) 9 10for doc_id, text in enumerate(docs_with_repeat): 11 for term in text.split(): 12 postings[term].add(doc_id) 13 14print("token postings", sorted(postings["token"])) 15print("document 2 counted once", len(postings["token"]) == 2)
Output
1token postings [0, 2] 2document 2 counted once True

Ranking with a heap

Once documents have scores, the system needs the best few results. It doesn't need a full sorted report about the corpus.

That's the moment for a heap.

For our tiny example, scores are:

doc idscore
22
01

A heap keeps the top k results easy to retrieve. In retrieval systems, that matters because you often want the best 5, 10, or 20 candidates, rather than a fully sorted candidate list.

For a stream of scored candidates, keep a min-heap capped at k items. The weakest retained score stays at the root. When a stronger candidate arrives, replace that weakest item instead of sorting every candidate seen so far.

Real rankers also need an explicit tie-break rule. The heap demo and the retriever lab below both prefer the lower document ID when scores tie so their output stays deterministic. The min-heap key stores score first and negative ID second, so higher scores win and lower IDs win ties when Python compares tuples.

bounded-top-k-heap.py
1import heapq 2 3candidate_scores = [(0, 1), (2, 2), (3, 3)] 4k = 2 5top_k: list[tuple[int, int]] = [] 6 7for doc_id, score in candidate_scores: 8 # Same key rule as search(): higher score wins; lower doc_id wins ties. 9 candidate = (score, -doc_id) 10 if len(top_k) < k: 11 heapq.heappush(top_k, candidate) 12 elif candidate > top_k[0]: 13 evicted = heapq.heapreplace(top_k, candidate) 14 print("evicted", (evicted[0], -evicted[1])) 15 16print("top k", [(score, -doc_key) for score, doc_key in sorted(top_k, reverse=True)])
Output
1evicted (1, 0) 2top k [(3, 3), (2, 2)]

The retriever pipeline

The pieces fit together in a single flow:

Lexical retrieval path showing query terms becoming posting lists, document match counts, and a top-k heap that returns the best technical notes. Lexical retrieval path showing query terms becoming posting lists, document match counts, and a top-k heap that returns the best technical notes.
The query enters as terms, the index returns posting lists, scores accumulate per document, and the heap keeps only the best candidates.

A query enters as plain text, splits into terms, and uses the index to turn each term into a posting list. Scores accumulate per document, and the heap returns the best k document IDs. This same pattern sits inside RAG systems, where a language model reads only the best supporting chunks instead of the whole corpus.

Building a tiny retriever

Start with the slow version so you can see what the index is replacing. Then add the index and heap.

Put this in data_structures_demo.py. This first tokenizer lowercases and splits on whitespace. Production tokenizers also handle punctuation and language-specific rules, but keeping normalization tiny makes the structure visible. Returning a set means this example scores binary term membership: each distinct query term contributes at most once.

data_structures_demo.py
1from collections import defaultdict 2import heapq 3 4docs = [ 5 "token cache eviction", 6 "gradient checkpointing memory", 7 "token hit cache", 8] 9 10def tokenize(text: str) -> set[str]: 11 return set(text.lower().split()) 12 13def slow_search(query: str) -> list[tuple[int, int]]: 14 terms = tokenize(query) 15 matches: list[tuple[int, int]] = [] 16 for doc_id, text in enumerate(docs): 17 words = tokenize(text) 18 score = sum(term in words for term in terms) 19 if score: 20 matches.append((doc_id, score)) 21 return matches 22 23index: dict[str, set[int]] = defaultdict(set) 24for doc_id, text in enumerate(docs): 25 for term in tokenize(text): 26 index[term].add(doc_id) 27 28def search(query: str, k: int = 2) -> list[int]: 29 if not query.strip(): 30 return [] 31 32 scores: dict[int, int] = defaultdict(int) 33 for term in tokenize(query): 34 for doc_id in index.get(term, set()): 35 scores[doc_id] += 1 36 37 best = heapq.nlargest( 38 k, 39 scores.items(), 40 key=lambda item: (item[1], -item[0]), 41 ) 42 return [doc_id for doc_id, _score in best] 43 44print("slow scan", slow_search("token hit")) 45print("posting list", sorted(index["token"])) 46print("search", search("token hit"))
Output
1slow scan [(0, 1), (2, 2)] 2posting list [0, 2] 3search [2, 0]

Read the data movement

JobStructureWhy it fits
keep the original corpus orderlistthe documents start as an ordered sequence
jump from term to matching docsdictionary of setsthe query starts with a term
count how many terms matcheddictionary of integerseach document needs a score
keep the best few resultsheapthe system wants top-k rather than a full sorted list

The heap key uses score first and negative document ID second. Higher scores win; lower IDs win ties. That small rule makes repeated runs predictable.

That table is more important than the syntax.

What happens beyond retrieval: queues and caches

Retrieval is one place where data structures show up in AI systems.

Queues for background work

New documents arrive and need to be split into chunks, then encoded as embedding vectors before they can enter a semantic index. For one class of equal-priority jobs, arrival order is a clean baseline. Production queues may add priorities, retries, and dead-letter handling, but they still need an explicit ordering contract.

That's a queue.

queues-for-background-work.py
1from collections import deque 2 3embedding_jobs = deque(["doc-3", "doc-4", "doc-5"]) 4next_job = embedding_jobs.popleft() 5 6print("next job", next_job) 7print("remaining", list(embedding_jobs))
Output
1next job doc-3 2remaining ['doc-4', 'doc-5']

The rule is simple:

  • append new work on one side
  • pop the oldest work from the other side

That's first-in, first-out behavior. If you accidentally process newest work first, users may see random delays or starvation in old jobs.

For a durable worker, FIFO order is only one promise. A stateful request lane should record each accepted event in a durable transaction, then preserve this invariant: every accepted job is pending, running, completed, or explicitly failed, never silently lost between memory and storage. The in-memory deque demonstrates ordering but provides no durability by itself.

This failure case makes the ordering bug visible. New jobs belong at the tail; putting them at the front lets recent uploads jump ahead of old work.

queue-order-failure.py
1from collections import deque 2 3fifo_jobs = deque(["oldest-doc"]) 4fifo_jobs.extend(["new-doc-a", "new-doc-b"]) 5 6newest_first_jobs = deque(["oldest-doc"]) 7newest_first_jobs.appendleft("new-doc-a") 8newest_first_jobs.appendleft("new-doc-b") 9 10print("FIFO runs", fifo_jobs.popleft()) 11print("wrong order runs", newest_first_jobs.popleft())
Output
1FIFO runs oldest-doc 2wrong order runs new-doc-b

Caches for repeated queries

If users ask the same question repeatedly, recomputing retrieval results per request wastes work.

A retrieval cache stores prior ranked document IDs so the system can reuse them.

caches-for-repeated-queries.py
1cache: dict[tuple[int, str], list[int]] = {} 2corpus_version = 1 3query = "token hit" 4 5cache_key = (corpus_version, query) 6if cache_key not in cache: 7 cache[cache_key] = search(query) 8 9print("cached", cache[cache_key])
Output
1cached [2, 0]

Why the key includes version

cache key partwhy it exists
queryseparates one repeated request from another
corpus_versionforces refresh after the document collection changes

If document 2 stops mentioning token, the cached ranking [2, 0] becomes fast and wrong. A version number, timestamp, or explicit invalidation rule tells the system when old results must be dropped.

Run the failure before relying on the fix. A text-only key finds yesterday's ranking after an update; a versioned key misses and forces recomputation.

cache-invalidation-failure.py
1query = "token hit" 2old_version = 1 3new_version = 2 4 5text_only_cache = {query: [2, 0]} 6versioned_cache = {(old_version, query): [2, 0]} 7 8print("text-only stale hit", query in text_only_cache) 9print("versioned stale hit", (new_version, query) in versioned_cache)
Output
1text-only stale hit True 2versioned stale hit False

Common mistakes

Beginners often don't choose the wrong structure because they lack vocabulary. They choose it because the first working code feels good enough.

SymptomLikely causeFix
query gets slower as documents growthe code still scans the whole list per querybuild an index keyed by the query field
same document appears more than oncea list was used where uniqueness mattersstore posting lists as sets
old jobs starvework is being popped in the wrong orderuse a FIFO queue and test the order explicitly
cached result looks right until documents changecache has no version or invalidation ruletie the cache key to corpus updates
ranking feels mysteriousscores are hidden inside loopsprint one query's per-document score table

The fastest way to debug is still the same: trace one tiny example by hand.

Protect the promises with tests

These tests protect the structures, rather than the final answer alone:

protect-the-promises-with-tests.py
1from collections import deque 2 3def test_token_lookup_has_two_docs(): 4 assert index["token"] == {0, 2} 5 6def test_empty_query_returns_empty_list(): 7 assert search("") == [] 8 9def test_token_hit_ranks_doc_2_first(): 10 assert search("token hit")[0] == 2 11 12def test_search_normalizes_case(): 13 assert search("Token HIT") == [2, 0] 14 15def test_queue_is_fifo(): 16 jobs = deque(["doc-3", "doc-4"]) 17 assert jobs.popleft() == "doc-3" 18 19test_token_lookup_has_two_docs() 20test_empty_query_returns_empty_list() 21test_token_hit_ranks_doc_2_first() 22test_search_normalizes_case() 23test_queue_is_fifo() 24print("five structural tests passed")
Output
1five structural tests passed

Each test checks one promise:

  • the index maps terms to the right documents
  • empty input is predictable
  • ranking follows visible score logic
  • query normalization is consistent
  • queue order stays first-in, first-out

Checking your reasoning

Try these before you look at the solution sketches.

  1. Add a fourth document: hit latency token.
  2. Predict sorted(index["token"]).
  3. Predict search("token hit").
  4. Run search("attention") and explain why it shouldn't crash.
  5. Change document 2 so it no longer contains token, then explain what must happen to the cache.

Solution sketches

Use these to check your reasoning, not to skip the exercise.

Practice itemWhat a good answer should show
Add hit latency tokentoken and hit both gain the new document ID.
Predict sorted(index["token"])[0, 2, 3] after the new document is added.
Predict search("token hit")[2, 3]. Documents 2 and 3 tie with score 2, so the lower document ID wins the deterministic tie-break.
Query attentionindex.get(term, set()) returns an empty set, so the function returns [] instead of crashing.
Change document 2Rebuild the affected posting lists and drop cache entries tied to the old corpus version.

If your answer feels fuzzy, go back to the score table. Good data-structure reasoning should look inspectable on paper before it looks clever in code.

Matching structures to operations

Most beginner confusion disappears once you ask one concrete question:

What operation must stay fast and predictable?

Use that question to pick the structure:

If the job is...Reach for...
keep things in their original orderlist
jump from key to valuedictionary
guarantee uniqueness or fast membershipset
keep the best few resultsheap
process work in arrival orderqueue
reuse prior results safelycache

Later retrieval systems combine exact term postings with approximate nearest-neighbor indexes over embedding vectors. The selection rule stays the same: choose a structure that matches the lookup and update operations you need.

Moving to durable databases

Data structures decide which candidates enter the model's field of view.

That's why data structures come before databases. First you need to know which structure makes a lookup fast. Then you're ready to put those structures behind durable tables, joins, transactions, and vector search.

Complete the lesson

Mastery Check

Answer every question, then check your score. Score 75% or higher to mark this lesson complete.

1.A technical-note search system stores millions of documents. Queries begin with terms such as token, and the retriever must jump from each term to the unique document IDs containing it instead of scanning every document. Which data structure matches this lookup operation?
2.An index was built from document 5, token token hit, and document 6, token cache. The retriever uses binary term membership: each distinct query term can add at most 1 point per document. For query token hit, which score table is correct if posting lists store document IDs as sets?
3.An indexed retriever has documents 0: token cache eviction, 1: gradient checkpointing memory, 2: token hit cache, and 3: hit latency token. It scores one point for each distinct query term in a document, returns k=2 IDs, and breaks score ties by lower document ID. For query token hit, which result is correct?
4.You are keeping the top 3 scored chunks with a capped min-heap. It currently retains A at 0.52, B at 0.68, and C at 0.91, so A is the weakest retained item. A new candidate D arrives with score 0.74. What should happen?
5.An ingestion deque starts from left to right as doc-10, doc-11. A developer inserts doc-12 with appendleft() and takes the next job with popleft(). Which outcome follows?
6.A retriever caches the ranked IDs for query token cache as [4, 1] while corpus_version is 7. Later document 4 is edited and the corpus becomes version 8. Which cache design avoids serving the old ranking as a valid hit?
7.A request lane tracks reserved[request] and served[request] with the invariant served[request] <= reserved[request]. For req-1, reserved is 2 and served is 1. A serve event for quantity 2 arrives. What should the transition do?
8.A queue worker keeps an in-memory completed_event_ids set. It writes embedding event embed-91, then crashes before adding embed-91 to the set. The broker retries embed-91. Why can the retry duplicate the write, and what fixes this at the production boundary?

8 questions remaining.

Next Step
Continue to SQL, Databases, and Data Modeling for AI

You can now choose in-memory structures for term lookup, top-k ranking, ordered work, and safe reuse. The next chapter moves those access patterns into durable tables, constraints, transactions, permissions, and vector-aware queries that can serve more than one process.

PreviousMPS & Metal for ML on Mac
Share this article
XFacebookLinkedInBlueskyRedditHacker NewsEmail
References

Designing Data-Intensive Applications.

Kleppmann, M. · 2017

Introduction to Information Retrieval.

Manning, C. D., Raghavan, P., Schutze, H. · 2008 · Cambridge University Press

Discussion

Questions and insights from fellow learners.

Discussion loads when you reach this section.