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 priceaddRestaurant(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),MenuandMenuItem, and aSearchQueryvalue object carrying text plus the active filter set. - Chain of Responsibility for the filter pipeline: each
Filterimplementsapply(candidates) -> candidatesand 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)withRatingSort,DistanceSort,PriceSortimplementations 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. SearchEngineorchestrates: 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:
addRestaurantmutating 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 …