京东外卖,探索「距离最近」排序背后的秘密

关注我的公众号:【编程朝花夕拾】,可获取首发内容。

1、引言

京东外卖于‌2025年2月11日正式开放,标志着京东正式进军外卖行业。浏览页面时,在筛选项里面看到了「距离最近」的筛选项,点了一下就按照商户和当前位置正序排列了。

这个功能其实其他外卖类、旅游类、地图类的APP中经常看到。今天我们一起聊一下背后的技术方案。

2、背后的技术

地理位置(Geolocation)距离的不再是简单的距离比较,而是实时的经纬度的计算。因为你在不同的地方,商家离你的位置都是变化的。

Geolocation的简称是GEO。地球经纬度,将地球看做一个球体。将A、B两点的作为一个剖面,就会得到一个圆形,A、B两点的之间的距离不再试一条直线,而是一条弧线。两点的距离就是这个弧长。

常用的计算方式,离不开数学的三角函数:

  • 球面余弦定理:适用于远距离计算,但近距离可能有舍入误差
  • Vincenty公式:基于椭球模型,精度更高但计算复杂
  • Haversine公式:平衡精度与复杂度的最佳选择,适用于导航、地图服务等常见场景

了解一下晦涩难懂的Haversine公式:

看着复杂,其实按照参数代入即可。当然这个不是今天的目的。

Java作为一门面向对象的语言,可以不用关注具体的实现,只要有现成的工具,调用即可。

3、问题难点

了解了经纬度的计算,无论是我们自己编码、套用公式还是使用一些在线工具根据两点计算出距离,这些都不能满足类似「京东外卖」这样的排序。

因为排序功能是针对全量的数据。如果单纯的计算出距离,不说海量万级数据都有可能将内存榨干,更不用说影响用户体验了。

难点来了:如何通过经纬度实时计算给万级数据排序呢?

4、Mysql 5.7.6+

Mysql 是大部分程序员都会接触的数据库,用来存储数据。Mysql5.7.6 版本 开始正式支持基于地理坐标系(如WGS84)的经纬度计算功能,关键改进是引入了 ST_Distance_Sphere 函数,用于计算球面距离(即地球表面的实际距离)。

数据准备:

上海(POINT(121.4737, 31.2304))、北京(POINT(116.4074, 39.9042))

mysql 复制代码
SELECT ST_Distance_Sphere(
    POINT(116.4074, 39.9042),  -- 北京
    POINT(121.4737, 31.2304)    -- 上海
) AS distance_meters;
-- 结果约为 1,066,000 米(约1066公里)

距离正序排列的使用:

mysql 复制代码
-- 单位米
SELECT
    id,
    latitude,
    longitude,
    ST_DISTANCE_SPHERE(
        POINT(target_longitude, target_latitude),
        POINT(longitude, latitude)
    ) AS distance
FROM table_name 
ORDER BY distance ASC;

5、Redis GEO

Redis中的GEO数据类型是Redis3.2.0开始有的。

实战用到的函数:GEORADIUS

shell 复制代码
# 根据当前经纬度获取方圆范围内的成员
GEORADIUS key longitude latitude radius M | KM | FT | MI [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count [ANY]] [ASC | DESC] [STORE key | STOREDIST key]

参数含义:

  • WITHCOORD 获取经纬度
  • WITHDIST 获取距离
  • WITHHASH 获取成员Hash
  • COUNT 限制罗列的成员数量
  • ASE | DESC 排序
  • STORE key 将返回的地理位置信息保存到一个key里面
  • STOREDIST key 将返回的目标距离保存到一个key里面

实战:

假设当前的地点位置:上海(POINT(121.4737, 31.2304)

shell 复制代码
# 查询cities这个key中距离上海(POINT(121.4737, 31.2304) 50公里以内的元素,并正序排列
GEORADIUS cities 121.4737 31.2304 50 KM WITHDIST ASC

像了解关于Redis GEO更多知识可以查看以往文章:

mp.weixin.qq.com/s/MbQXBvN2k...

6、小结

上面介绍两种最常用且简单的方法,你还知道其他方法么?评论区留言讨论。

方法再多,只不过使我们使用的工具或者手段。日常中你可能平时常见的一个小功能,背后可能都有极其复杂的技术支撑。比如我们进场使用的地图,已经接入北斗导航,背后的技术更是不言而喻。

相关推荐
数字人直播1 分钟前
稳了!青否数字人分享3大精细化AI直播搭建方案!
前端·后端
掘金一周13 分钟前
被老板逼出来的“表格生成器”:一个前端的自救之路| 掘金一周 8.21
前端·人工智能·后端
SimonKing33 分钟前
开源新锐:SQL玩转搜索引擎?Manticore颠覆你的认知
java·后端·程序员
ejinxian1 小时前
MySQL/Kafka数据集成同步,增量同步及全量同步
数据库·mysql·kafka
MaxHua2 小时前
数据库入门指南与实战进阶-Mysql篇
后端
用户4099322502122 小时前
FastAPI的死信队列处理机制:为何你的消息系统需要它?
后端·ai编程·trae
用户4822137167752 小时前
C++——纯虚函数、抽象类
后端
张同学的IT技术日记2 小时前
必看!用示例代码学 C++ 基础入门,快速掌握基础知识,高效提升编程能力
后端
林太白2 小时前
Nuxt3 功能篇
前端·javascript·后端
得物技术3 小时前
营销会场预览直通车实践|得物技术
后端·架构·测试