附近人
- 附近人列表功能
- mysql
- redis GEO
- thinkphp
附近人列表功能
方案 | 优势 | 缺点 |
---|---|---|
Mysql外接正方形 | 逻辑清晰,实现简单,支持多条件筛选 | 效率较低,不适合大数据量,不支持按距离排序 |
Mysql+Geohash | 借助索引有效提高效率,支持多条件筛选 | 不支持按距离排序,存在数据库瓶颈 |
Redis+Geohash | 效率高,集成便捷,支持距离排序 | 不适合复杂对象存储,不支持多条件查询 |
mysql
轻量级 1w 以内 经纬度 ---> 四个临界点
redis GEO
地理位置操作GEOADD 将指定的地理空间位置 经度纬度 名称 存储到指定keyGEORADIUS 以给定的经纬度为中心 找出某一半径内元素
thinkphp
// 假设您已经获取了用户的经纬度和需要搜索的距离范围
$lng = $_GET['lng']; // 用户的经度
$lat = $_GET['lat']; // 用户的纬度
$distance = $_GET['distance']; // 需要搜索的距离范围,单位为千米// 计算经纬度范围
$earth = 6378.137; // 地球半径
$pi = 3.1415926535898; // 圆周率
$lng_min = $lng - rad2deg($distance / $earth / cos(deg2rad($lat)));
$lng_max = $lng + rad2deg($distance / $earth / cos(deg2rad($lat)));
$lat_min = $lat - rad2deg($distance / $earth);
$lat_max = $lat + rad2deg($distance / $earth);// 查询商品表,根据距离排序,取前10条数据
$goods = Db::name('goods')->field("*, (2 * $earth * asin(sqrt(pow(sin($pi * ($lat - lat) / 360), 2) + cos($pi * $lat / 180) * cos(lat * $pi / 180) * pow(sin($pi * ($lng - lng) / 360), 2)))) as distance")->where('lng', 'between', [$lng_min, $lng_max])->where('lat', 'between', [$lat_min, $lat_max])->order('distance', 'asc')->limit(10)->select();// 返回推荐商品的数据
return json($goods);<html>
<head><meta charset="utf-8"><title>商品推荐</title><style>.goods {display: flex;flex-wrap: wrap;justify-content: space-around;margin: 20px;}.item {width: 200px;height: 300px;border: 1px solid #ccc;margin: 10px;padding: 10px;box-sizing: border-box;}.item img {width: 180px;height: 180px;}.item h3 {font-size: 16px;margin: 10px 0;}.item p {font-size: 14px;color: #666;}</style>
</head>
<body><div class="goods"></div><script>// 假设您已经获取了用户的经纬度和需要搜索的距离范围var lng = 120.15; // 用户的经度var lat = 30.28; // 用户的纬度var distance = 10; // 需要搜索的距离范围,单位为千米// 发送Ajax请求,获取推荐商品的数据var xhr = new XMLHttpRequest();xhr.open('GET', 'http://localhost/goods?lng=' + lng + '&lat=' + lat + '&distance=' + distance);xhr.onreadystatechange = function() {if (xhr.readyState == 4 && xhr.status == 200) {var data = JSON.parse(xhr.responseText);// 渲染商品列表var goods = document.querySelector('.goods');goods.innerHTML = '';for (var i = 0; i < data.length; i++) {var item = document.createElement('div');item.className = 'item';item.innerHTML = `<img src="${data[i].image}" alt="${data[i].name}"><h3>${data[i].name}</h3><p>价格:${data[i].price}元</p><p>距离:${data[i].distance.toFixed(2)}千米</p>`;goods.appendChild(item);}}};xhr.send();</script>
</body>
</html>