Capstone — Building a Real Search & Analytics Feature

Elasticsearch / OpenSearch

Chapter 11 · Capstone: Building a Real Search & Analytics Feature

Ten chapters covered what makes this engine genuinely different, closing two real loops (postgres1-6's own deferred search comparison, and its own faceted-search callout) along the way. This capstone builds one real, working product search feature — but only after confirming, using search1-10's own framework, that building it here is actually justified.

The Scenario

An e-commerce company with a genuinely large product catalog is deciding whether to build a dedicated product search feature. Applying search1-10's own five-question framework directly: search is the storefront's own primary feature, not a secondary convenience (question 1 → yes); the catalog is genuinely large enough to benefit from real horizontal distribution (question 2 → yes); faceted filtering (category, brand, price) is a first-class, heavily-used requirement for this storefront (question 3 → yes); relevance quality genuinely affects conversion and revenue (question 4 → yes); and the team is prepared to operate a separate system and keep it synced with the real product database (question 5 → assumed yes). Unlike search1-10's own two exercise scenarios — both genuine "no" cases — this is a real, complete "yes" case, closing that chapter's own framework from the other direction.

The Mapping

PUT /products
{
  "mappings": {
    "properties": {
      "name": { "type": "text", "fields": { "keyword": { "type": "keyword" } } },
      "description": { "type": "text" },
      "category": { "type": "text", "fields": { "keyword": { "type": "keyword" } } },
      "brand": { "type": "text", "fields": { "keyword": { "type": "keyword" } } },
      "price": { "type": "float" }
    }
  }
}

This mapping is explicit and deliberate, not left to dynamic inference — avoiding both search1-3's own dynamic-mapping gotcha and search1-7's own analyzed-field aggregation gotcha directly, by giving category and brand a keyword sub-field specifically for exact filtering and aggregation, alongside their own analyzed text version for full-text search.

The Combined Query

POST /products/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "multi_match": {
            "query": "wireless mouse",
            "fields": ["name^3", "description"]
          }
        }
      ],
      "filter": [
        { "term": { "category.keyword": "Electronics" } },
        { "term": { "brand.keyword": "Logitech" } },
        { "range": { "price": { "gte": 10, "lte": 60 } } }
      ]
    }
  },
  "aggs": {
    "by_category": { "terms": { "field": "category.keyword" } },
    "by_brand": { "terms": { "field": "brand.keyword" } },
    "price_ranges": {
      "range": {
        "field": "price",
        "ranges": [ { "to": 25 }, { "from": 25, "to": 50 }, { "from": 50 } ]
      }
    }
  }
}

name^3 boosts matches in the product name three times higher than matches in the description — search1-6's own boosting material, applied for real. The must clause drives relevance-ranked results; the filter clauses narrow by exact, non-scoring criteria against the keyword sub-fields; the aggs block computes category, brand, and price-range facet counts over that same filtered result set, in the same single request.

Why This Works — Tracing the Mechanism

The ranked results come from BM25 scoring (search1-6) computed via the inverted index (search1-4). The facet counts come from aggregations (search1-7) computed in parallel across shards (search1-8). The whole request executes as fast as it does specifically because of the distributed, parallel architecture search1-8 covered — every piece of this capstone traces back to a specific, real mechanism this course actually explained, not just a feature list.

Chapter Attribution

Capstone elementChapter
Confirming a dedicated engine is justified for this use casesearch1-10
Explicit mapping, keyword sub-fields avoiding two prior gotchassearch1-3, search1-7
multi_match, bool query with must/filtersearch1-5
Field boosting (name^3)search1-6
Nested terms/range aggregations for facetssearch1-7
Parallel execution across shards making it fast at scalesearch1-8
Underlying inverted index and BM25 scoring mechanismsearch1-4, search1-6
Honest scope note
This capstone does not build an actual data-sync pipeline from a real source-of-truth database — search1-1's own warn-box named this as real, necessary, ongoing engineering work, and it remains a genuinely separate project of its own, out of scope here. It also doesn't build autocomplete/suggest functionality, typo-tolerance/fuzzy-matching tuning, or a real cluster deployment/production-hardening walkthrough — search1-8's own sharding/replication material stayed conceptual throughout this course. This capstone demonstrates exactly what search1-10's own framework confirmed was justified for this specific scenario — not a claim that every possible feature of a production search system is "done."
The throughline, closed
search1-1 opened this course by naming the inverted index and relevance scoring as this engine's own primary, founding design center — not a bolt-on feature. This capstone is the proof: one real request, genuinely combining search, filtering, relevance, and analytics, built entirely on the mechanisms this course actually explained.

Hands-On Exercises

Exercise 1

Walk through this chapter's own application of search1-10's five-question framework to the e-commerce scenario, and explain why this capstone represents a genuine "yes" case, complementing search1-10's own two "no" exercise scenarios.

📄 View solution
Exercise 2

Explain why the capstone's own mapping gives category and brand a keyword sub-field, tying your answer to both search1-3's dynamic-mapping gotcha and search1-7's analyzed-field aggregation gotcha, with a concrete example of what would go wrong without it.

📄 View solution
Exercise 3

Using this chapter's own "Why This Works" section, trace the combined query's own results back to the specific underlying mechanisms (inverted index, BM25, sharding) covered earlier in this course.

📄 View solution

Chapter 11 Quick Reference — Course Complete

  • search1-10's own framework applied first, confirming a dedicated engine is genuinely justified for this scenario — a real "yes" case
  • Explicit mapping with keyword sub-fields deliberately avoids search1-3's and search1-7's own gotchas
  • One combined request: relevance-ranked, boosted, faceted, and filtered — search1-5/6/7 working together
  • Fast at scale because of search1-8's own distributed, parallel shard execution
  • Honest scope note: no real data-sync pipeline, no autocomplete, no fuzzy matching, no production deployment walkthrough
  • This closes the full 11-chapter Elasticsearch/OpenSearch course, and the entire Databases subject's own bucket list