Design a Restaurant Search and Filter System

Problem Design the object model for a restaurant search and filter system: a user submits a query plus an arbitrary combination of filters, and gets back a ranked, sortable list of restaurants.

Requirements

  • search(query, filters) -> List<Restaurant> — returns a ranked result list
  • Filters composable in any combination: cuisine, price range, rating, delivery time, distance
  • sortBy(field) — order results by rating, distance, or price
  • addRestaurant(restaurant) / updateRestaurant(id, fields) — admin operations
  • Adding a new filter type must not require editing existing filter code

Core design

  • Entities: Restaurant (id, name, cuisines, priceTier, rating, location, isOnline), Menu and MenuItem, and a SearchQuery value object carrying text plus the active filter set.
  • Chain of Responsibility for the filter pipeline: each Filter implements apply(candidates) -> candidates and delegates to the next link. Filters become independently testable and arbitrarily composable, and a new filter is a new class rather than another branch in a growing conditional.
  • Strategy for sorting: SortStrategy.compare(a, b) with RatingSort, DistanceSort, PriceSort implementations selected at request time.
  • Builder for SearchQuery — with five optional filters, a builder avoids both a telescoping constructor and a parameter object full of nulls.
  • SearchEngine orchestrates: build query -> run the filter chain over candidates -> rank -> apply sort strategy -> paginate.
  • Ranking and sorting are deliberately distinct: ranking is relevance scoring (text match, popularity, personalization), sorting is an explicit user override. Conflating them is a common design smell here.

Discussion points

  • Filter ordering inside the chain is a performance decision, not a correctness one: run the cheapest and most selective filters (price tier, cuisine) before expensive geo-distance computation.
  • Distance filtering does not belong in a linear scan — discuss a geo index (geohash, quadtree, R-tree) to shrink the candidate set before the chain runs.
  • Trade-off: chain-of-responsibility filtering in application code is flexible and testable, but pushing predicates into a search index (Elasticsearch/Solr) is what actually scales past a naive scan. Discuss where the boundary sits.
  • Edge cases: empty result sets, filters that contradict each other, pagination stability when the underlying data changes mid-scroll, and rating ties under sort.
  • Concurrency: addRestaurant mutating the candidate set while searches read it — discuss an immutable snapshot per query.
  • Extension: personalization and per-user ranking, which break the pure-function assumption of the sort strategy.
asked …
LeaderboardSalaryAccount