Skip to content

Widhian Bramantya

coding is an art form

Menu
  • About Me
Menu
elasticsearch

Finding Nearby Merchants in a Ride-Hailing App Using Elasticsearch Polygon Search

Posted on October 6, 2025October 5, 2025 by admin

Step 5 (Optional) Refine with Exact Distance

To improve accuracy for the top few results,
you can do a second step: calculate real distance for, say, top 100 merchants only.

GET merchants/_search
{
  "sort": [
    {
      "_geo_distance": {
        "location": { "lat": -6.20, "lon": 106.81 },
        "order": "asc",
        "unit": "km"
      }
    }
  ],
  "size": 10
}

This gives the closest 10 merchants by true distance, while the heavy filtering already happened using the fast polygon method.

Step 6 Automating Polygon Generation with Pipeline

You can also automate this inside Elasticsearch using an ingest pipeline.
Each time you insert or update merchant location, the pipeline can pre-compute
a bounding polygon (for example, the 5-km delivery area).

PUT _ingest/pipeline/add_bounding_polygon
{
  "processors": [
    {
      "script": {
        "lang": "painless",
        "source": """
          double R = 6371.0;
          double radius = 5.0;
          int sides = 32;
          double lat = ctx.location.lat * Math.PI / 180;
          double lon = ctx.location.lon * Math.PI / 180;
          List points = new ArrayList();
          for (int i = 0; i < sides; i++) {
            double angle = 2 * Math.PI * i / sides;
            double dx = radius * Math.cos(angle) / R;
            double dy = radius * Math.sin(angle) / (R * Math.cos(lat));
            double lat_i = ctx.location.lat + dy * 180 / Math.PI;
            double lon_i = ctx.location.lon + dx * 180 / Math.PI;
            points.add([lon_i, lat_i]);
          }
          points.add(points.get(0));
          ctx.delivery_area = ["type": "polygon", "coordinates": [points]];
        """
      }
    }
  ]
}

Then when indexing:

POST merchants/_doc?pipeline=add_bounding_polygon
{ "name": "Boba Shop", "location": { "lat": -6.22, "lon": 106.84 } }

Now every merchant has a delivery_area polygon stored automatically.

Step 7 Querying Merchants by Delivery Area

When a user makes an order:

{
  "lat": -6.21,
  "lon": 106.82
}

You can search:

"geo_shape": {
  "delivery_area": {
    "shape": {
      "type": "point",
      "coordinates": [106.82, -6.21]
    },
    "relation": "contains"
  }
}

This returns all merchants whose delivery area includes the user’s location.
This approach is perfect for “Which restaurants deliver to me?” queries.

Performance Summary

MethodDescriptionSpeedAccuracy
geo_distanceTrue radius, Haversine mathSlowPerfect
Polygon (geo_shape)Approximated circleFast1-5% error
Polygon + RefinePolygon filter + real distance for top resultsBalancedHigh
Pre-generated delivery_areaEach merchant has pre-computed polygonVery fastHigh

Conclusion

In real-time apps like food delivery or ride-hailing,
speed matters more than mathematical perfection.

See also  Basic Concept of ElasticSearch (Part 3): Translog, Flush, and Refresh

By replacing heavy radius math with polygon approximation,
you get:

  • 10× faster queries
  • Small and predictable error margin
  • Easy scaling to millions of merchants

Later, you can refine only the top results with exact distance.
This combination keeps both performance and accuracy in balance.

“Fast enough and close enough, that’s what users expect.”

Related posts:

Blue-Green Deployment in Elasticsearch: Safe Reindexing and Zero-Downtime Upgrades

Basic Concept of ElasticSearch (Part 2): Architectural Perspective

Index Lifecycle Management (ILM) in Elasticsearch: Automatic Data Control Made Simple

Pages: 1 2
Category: ElasticSearch

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Linkedin

Widhian Bramantya

Recent Posts

  • Smart Automation in PostgreSQL: Managing Time-Based Data with pg_partman and pg_cron
  • Understanding PostgreSQL WAL, Slot, Publication, LSN, and Replication Lag
  • PostgreSQL Write-Ahead Log (WAL): Durability, Performance Tuning, and Recovery Explained
  • PostgreSQL Replication Deep Dive: From High Availability to Multi-Master Clusters
  • Finding Nearby Merchants in a Ride-Hailing App Using Elasticsearch Polygon Search
  • Advanced Text Search in Elasticsearch: N-Gram, Reverse, Fuzzy, and Search-as-you-type
  • Understanding and Customizing Analyzers in Elasticsearch
  • Log Management at Scale: Integrating Elasticsearch with Beats, Logstash, and Kibana
  • Index Lifecycle Management (ILM) in Elasticsearch: Automatic Data Control Made Simple
  • Blue-Green Deployment in Elasticsearch: Safe Reindexing and Zero-Downtime Upgrades
  • Maintaining Super Large Datasets in Elasticsearch
  • Elasticsearch Best Practices for Beginners
  • Implementing the Outbox Pattern with Debezium
  • Production-Grade Debezium Connector with Kafka (Postgres Outbox Example – E-Commerce Orders)
  • Connecting Debezium with Kafka for Real-Time Streaming
  • Debezium Architecture – How It Works and Core Components
  • What is Debezium? – An Introduction to Change Data Capture
  • Offset Management and Consumer Groups in Kafka
  • Partitions, Replication, and Fault Tolerance in Kafka
  • Delivery Semantics in Kafka: At Most Once, At Least Once, Exactly Once

Recent Comments

No comments to show.

Archives

  • October 2025
  • September 2025
  • August 2025
  • November 2021
  • October 2021
  • August 2021
  • July 2021
  • June 2021
  • March 2021
  • January 2021

Categories

  • Debezium
  • Devops
  • ElasticSearch
  • Golang
  • Kafka
  • Lua
  • NATS
  • PostgreSQL
  • Programming
  • RabbitMQ
  • Redis
  • VPC
© 2026 Widhian Bramantya | Powered by Minimalist Blog WordPress Theme