附近人
- 附近人列表功能
- mysql
- redis GEO
- thinkphp
附近人列表功能
方案 | 优势 | 缺点 |
---|---|---|
Mysql外接正方形 | 逻辑清晰,实现简单,支持多条件筛选 | 效率较低,不适合大数据量,不支持按距离排序 |
Mysql+Geohash | 借助索引有效提高效率,支持多条件筛选 | 不支持按距离排序,存在数据库瓶颈 |
Redis+Geohash | 效率高,集成便捷,支持距离排序 | 不适合复杂对象存储,不支持多条件查询 |
mysql
轻量级 1w 以内
经纬度 ---> 四个临界点
redis GEO
地理位置操作
GEOADD 将指定的地理空间位置 经度纬度 名称 存储到指定key
GEORADIUS 以给定的经纬度为中心 找出某一半径内元素
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>