Skip to main content

Command Palette

Search for a command to run...

AI System Design: DoorDash Search System

LLM + Knowledge Graph + Hybrid Retrieval

Updated
5 min readView as Markdown

In the previous artcile, we undestood how search queries can differ a lot and how a small change can mean completely for the user. Let's now see the real use cases and how companies tackled the issue on a large production scale with millions of search queries.

One interesting part of DoorDash's approach is how they use RAG differently from the usual pattern.

Instead of simply retrieving documents and giving them to an LLM to generate an answer, retrieval is used to constrain what the LLM can output.

Let's see how this works in practice.

DoorDash

Imagine searching for:

"large spicy paneer pizza without onions"

The search system needs to understand that:

large
→ size

spicy
→ preference

paneer pizza
→ food / ingredient

without onions
→ exclusion

The interesting part is what DoorDash does with this information.

Instead of asking an LLM to search the entire catalog, DoorDash uses LLMs mainly to understand the query and connect it to a structured knowledge graph. The actual retrieval remains largely powered by existing search infrastructure.

The Architecture

The key idea is that the LLM isn't replacing the search engine.

Enriching the Catalog Offline

DoorDash already had a knowledge graph containing structured information about food items and restaurants and things like dish type, cuisine, dietary preferences, flavor, and brand.

So when a new menu item appears, an LLM can process it offline and extract useful attributes.

For example:

"Family Size Smoky BBQ Chicken Pizza"

→ Category: Pizza
→ Size: Family
→ Flavor: Smoky BBQ
→ Ingredient: Chicken

Those attributes become part of the knowledge graph.

Restaurant Catalog
        │
        ▼
       LLM
        │
        ▼
  Extract Attributes
        │
        ▼
 Knowledge Graph

This work happens before the user searches, so the runtime system doesn't have to repeatedly perform the same expensive reasoning.

Understanding the User Query

Now the user searches:

"large spicy paneer pizza without onions"

The LLM can turn this into structured pieces:

large
→ size

spicy
→ preference

paneer pizza
→ category / ingredient

without onions
→ exclusion

But there's another problem.

The LLM shouldn't start inventing categories that don't exist in DoorDash's system.

This is where entity linking comes in.

Entity Linking

Suppose a user searches for:

"extra cheesy pizza"

The system might already have concepts such as:

Cheese
Extra Cheese
Cheese Topping

Instead of asking the LLM to freely generate a category, DoorDash first retrieves relevant concepts from its existing taxonomy and then asks the LLM to choose the appropriate one.

Conceptually

The described system retrieves roughly the top 100 nearby taxonomy concepts and constrains the LLM to choose from them.

This is an interesting use of RAG.

We're not using retrieval to give the LLM documents and ask it to write an answer.

We're using retrieval to define the set of answers the LLM is allowed to choose from.

RAG becomes a guardrail for the LLM.

Once the query has been converted into concepts, the LLM has mostly done its job.

The system now has something like:

Category  → Pizza
Size      → Large
Preference → Spicy
Ingredient → Paneer
Exclude   → Onion

This structured representation can now go through the existing retrieval system.

Structured Query
       │
       ▼
Hybrid Retrieval
       │
       ▼
Candidate Items
       │
       ▼
Filtering
       │
       ▼
Ranking
       │
       ▼
Results

This is where DoorDash's architecture differs from the "just embed the query and run vector search" approach.

The LLM understands what the user said.

The search system determines what can actually satisfy it.

Why Keep the Traditional Search Stack?

Because the two systems are good at different things.

LLMs are useful for:

Understanding language
Resolving ambiguity
Mapping phrases to concepts

The existing search infrastructure is already designed for:

Indexing
Retrieval
Filtering
Ranking
Low-latency execution

So DoorDash didn't need to rebuild the entire search system around an LLM.

The LLM was introduced at the part of the pipeline where it provided the most value: understanding the user's query and connecting it to the existing knowledge graph.

The architecture can therefore be summarized as:

User Language
      │
      ▼
     LLM
      │
      ▼
Structured Concepts
      │
      ▼
Knowledge Graph
      │
      ▼
Existing Search System
      │
      ├── Retrieval
      ├── Filtering
      └── Ranking
      │
      ▼
    Results

This also explains why DoorDash's LLM integration stays relatively close to the edge of the system. Most of the runtime remains classical, while much of the LLM work happens offline or during query parsing.

The Bigger Lesson

The interesting thing about DoorDash isn't simply that they added an LLM to search.

It's where they chose to use it.

DoorDash already had a knowledge graph and a search system that could work with structured concepts. The LLM was used to bridge the gap between the way users naturally express their intent and the structured representation the existing system understands.

Human Language
      ↓
LLM
      ↓
Structured Concepts
      ↓
Existing Search System

This is a useful way to think about adding LLMs to production systems:

The question is not how much of the system can be replaced with an LLM. The question is where the LLM fits best in the system you already have.

For DoorDash, that place was query understanding.

The result is a hybrid architecture where the LLM handles language, while the existing search infrastructure continues to handle the parts it was already built to do well.

And DoorDash isn't the only way to approach the problem.

Instacart took the LLM integration one step further.

A

Retrieval used to constrain what the model can output, rather than to feed it context, is the part worth pulling out - it turns an open generation problem into a closed one over a known taxonomy, and hallucinating a food category that does not exist in the catalogue simply stops being possible. Different failure surface entirely. The without onions half of that query is the interesting bit, because negation is where pure embedding similarity is weakest: not onions and onions sit close together in vector space since they appear in near-identical sentences. Mapping it to a structured exclusion filter is the only reliable handling, and it is a good argument for why an entity-and-constraint layer earns its place next to semantic search rather than being replaced by a bigger model. Worth noting the latency budget too - a search box has maybe a couple of hundred milliseconds before it feels broken, so an LLM in the hot path usually means the parse is cached per query pattern rather than run per keystroke.