Administrator
Published on 2025-05-31 / 1 Visits
0
0

System Design Study Note | Designing a Proximity Service (Yelp, Google Places)

πŸ“Œ 1️⃣ Introduction

Proximity Service is a key component in many modern applications:

  • Yelp: Find nearby restaurants and shops

  • Google Places: Return nearby location data for developers

In this lesson, we will design a high-availability, high-performance, scalable proximity service.


🎯 2️⃣ Requirements Analysis

βœ… Functional Requirements

1️⃣ Given a user’s location (latitude, longitude) and a search radius, return nearby businesses

2️⃣ Business owners can create, update, delete businesses (updates can appear next day β€” no real-time requirement)

3️⃣ Users can view detailed business information


πŸš€ Non-Functional Requirements

  • Low latency: Users should get quick responses

  • High availability: Handle traffic spikes

  • System scale:

    • 100 million DAU

    • 200 million businesses

    • Average QPS β‰ˆ 5,000


🧩 3️⃣ High-Level System Architecture

The system consists of two main services:

1️⃣ Location-Based Service

  • Handles proximity queries

  • Read-heavy, write-free

  • Horizontally scalable (Stateless)

2️⃣ Business Service

  • Handles CRUD operations on business data

  • Write traffic is low; reads can be optimized with caching


API Design

  • GET /nearby

    • Input: latitude, longitude, radius

    • Output: List of nearby businesses

    • Note: Pagination omitted for simplicity; should be included in production

  • CRUD API

    • For managing business objects

    • Business detail requires a separate API call


πŸ—ƒοΈ 4️⃣ Database Design

Business Table

  • Stores detailed business information

  • Estimated size β‰ˆ 1~2 TB

Geospatial Index Table

  • Columns: geohash + business_id (optional: latitude/longitude)

  • Estimated size β‰ˆ 6 GB

  • Can fit in memory; use Read Replicas for read scalability


🌍 5️⃣ Geohash β€” How It Works

Principle:

1️⃣ Alternate binary partitioning of latitude and longitude

2️⃣ Generate a 01 sequence based on whether each value falls into lower/upper half of its range

3️⃣ Every 5 bits β†’ encode to base32 character β†’ Geohash string

4️⃣ Use prefix matching + 8 neighboring grids to query nearby businesses


Benefits:

βœ… Fast lookup with simple DB indexing

βœ… Works with common relational databases

βœ… Naturally supports different search radii through variable Geohash precision


Cautions:

  • Must query 8 neighboring grids to avoid missing edge cases

  • Grid distortion at high latitudes


🚦 6️⃣ Sample Query Flow

User searches for restaurants within a 500m radius:

1️⃣ Determine appropriate Geohash precision (length 6 β‰ˆ 500m)

2️⃣ Query the current Geohash grid and its 8 neighbors

3️⃣ Retrieve business IDs and coordinates

4️⃣ Calculate actual distance β†’ rank β†’ return results


πŸ§‘β€πŸ’» 7️⃣ Geohash Encoding Pseudocode (Java Style)

public class GeohashEncoder {

    private static final String BASE32 = "0123456789bcdefghjkmnpqrstuvwxyz";

    public static String encode(double latitude, double longitude, int precision) {
        double[] latRange = { -90.0, 90.0 };
        double[] lngRange = { -180.0, 180.0 };

        boolean isEven = true;
        int bit = 0;
        int ch = 0;
        StringBuilder geohash = new StringBuilder();

        int[] bits = { 16, 8, 4, 2, 1 };

        while (geohash.length() < precision) {
            double mid;
            if (isEven) {
                mid = (lngRange[0] + lngRange[1]) / 2;
                if (longitude > mid) {
                    ch |= bits[bit];
                    lngRange[0] = mid;
                } else {
                    lngRange[1] = mid;
                }
            } else {
                mid = (latRange[0] + latRange[1]) / 2;
                if (latitude > mid) {
                    ch |= bits[bit];
                    latRange[0] = mid;
                } else {
                    latRange[1] = mid;
                }
            }

            isEven = !isEven;

            if (bit < 4) {
                bit++;
            } else {
                geohash.append(BASE32.charAt(ch));
                bit = 0;
                ch = 0;
            }
        }

        return geohash.toString();
    }

    // Example usage
    public static void main(String[] args) {
        String geohash = GeohashEncoder.encode(37.4219999, -122.0840575, 6);
        System.out.println("Geohash: " + geohash);
    }
}


🏁 8️⃣ Summary

This lesson walks through the core design of a Proximity Service:

  • Service decomposition (Location vs Business)

  • Geohash-based spatial indexing

  • Storage optimization

  • Scalability considerations (read replicas, caching)

These design patterns are applicable to many real-world applications like Yelp, Google Places, Uber, DoorDash, and other location-based services πŸš—πŸ“.


Comment