一. 开始介绍: Redis GEO 1.Redis GEO 主要用于存储地理位置信息,并对存储的信息进行操作,该功能在 Redis 3.2 版本新增。
Redis GEO | 操作方法 |
---|
geoadd | 添加地理位置的坐标 | geopos | 获取地理位置的坐标 | geodist | 计算两个位置之间的距离 | georadius | 根据用户给定的经纬度坐标来获取指定范围内的地理位置集合 | georadiusbymember | 根据储存在位置集合里面的某个地点获取指定范围内的地理位置集合 | geohash | 返回一个或多个位置对象的 geohash 值 |
2.geoadd
geoadd 用于存储指定的地理空间位置,可以将一个或多个经度(longitude)、纬度(latitude)、位置名称(member)添加到指定的 key 中。
3.geopos
geopos 用于从给定的 key 里返回所有指定名称(member)的位置(经度和纬度),不存在的返回 nil。
4.geodist
geodist 用于返回两个给定位置之间的距离。
最后一个距离单位参数说明:
m :米,默认单位。
km :千米。
mi :英里。
ft :英尺。
5.georadius
georadius 以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素。
m :米,默认单位。
km :千米。
mi :英里。
ft :英尺。
WITHDIST: 在返回位置元素的同时, 将位置元素与中心之间的距离也一并返回。
WITHCOORD: 将位置元素的经度和维度也一并返回。
WITHHASH: 以 52 位有符号整数的形式, 返回位置元素经过原始 geohash 编码的有序集合分值。 这个选项主要用于底层应用或者调试, 实际中的作用并不大。
COUNT 限定返回的记录数。
ASC: 查找结果根据距离从近到远排序。
DESC: 查找结果根据从远到近排序。
二. Redis6 + PHP 实现附近门店思路
1.首先在项目后台创建店铺的时候,一定要接通百度地图api,返回相对输入店铺地址的经纬度,保存到数据库后才能实现,没有经纬度无法实现 本人用的是laravel框架~~
-
百度地图api地址 : https://lbsyun.baidu.com/index.php?title=webapi -
接下来是测试数据,如果对读者们有帮助,可以在实际项目中更具自己的思路加强改进~ -
-
如果之前创建店铺的时候保存了经纬度,这个数据可以在数据库中读取,id是门店的id,longitude 经度,latitude纬度 -
-
如果仔细的读者应该发现了,在这里用的语法是上文介绍过的,在这里只是把名称换成了店铺id,后面比较好和门店进行绑定 -
-
可以看到redis库中已经有我们填写的测试数据了,接下来我们结合上文所说到的georadius方法进行取值 -
-
这里使用的是asc升序排序,还有desc降序排序,一般附近门店第一个显示的是最近门店,所以用asc升序排序,单位是km 比较好查询 -
-
显示的是km单位,把数据拿到后可以 *1000 改成m单位,更具自己的项目需求进行改变 -
在这里遍历用店铺id做为数组的key -
-
在这将门店距离数据和门店信息数据组合 -
-
最后组合成的数据,已经可以在前端小程序中渲染附近门店距离啦,这只是测试数据哦,真实数据要更具自己项目数据进行结合 对读者有帮助的话 帮我点个赞哦 期待留言~~ -
-
成品效果哦~~ -
(ps: 最后可以设防,读取数据库门店信息条数和redis 储存的门店经纬度数据总数 进行对比,如果一致,则直接读取redis数据,否则重新查询数据库,将数据重新赋值给redis,可以减少数据库io查询)
代码块
$store_location = array(
0 => array(
'id' => 1,
'longitude' => '113.956843',
'latitude' => '22.575094',
),
1 => array(
'id' => 2,
'longitude' => '113.957746',
'latitude' => '22.574877',
),
2 => array(
'id' => 3,
'longitude' => '113.957036',
'latitude' => '22.575545',
),
);
foreach ($store_location as $K => $item) {
Redis::GeoAdd('store_location', $item['longitude'], $item['latitude'], $item['id']);
}
$positions = Redis::GeoRadius('store_location', 113.955964, 22.574741, 1000, 'km', 'WITHDIST', 'asc');
$positions_container = [];
foreach ($positions as $k => $v) {
$positions_container[$v[0]] = $v;
}
$stores = array(
0 => array(
'id' => 1,
'name' => 'ck',
),
1 => array(
'id' => 2,
'name' => 'myj',
),
2 => array(
'id' => 3,
'name' => 'tyb',
),
);
$store_info = [];
foreach ($stores as $k => $v) {
foreach ($positions_container as $kk => $vv) {
if ($kk = $v['id']) {
$store_info[$kk]['id'] = $v['id'];
$store_info[$kk]['name'] = $v['name'];
$store_info[$kk]['apart'] = ($positions_container[$kk][1] * 1) * 1000;
}
}
}
$column = array_column($store_info, 'apart');
array_multisort($column, SORT_ASC, $store_info);
dd($store_info);
public function queryOfflineStore()
{
$longitude = req::get('longitude');
$latitude = req::get('latitude');
if (empty($longitude) && empty($latitude)) {
return $this->resFailed(400, '请授权开启定位');
}
try {
$offline_store_info = offlineStore::checkPosition($longitude, $latitude);
return $this->resSuccess($offline_store_info);
} catch (\Exception $e) {
return $this->resFailed(400, $e->getMessage());
}
}
public static function checkPosition(String $longitude, String $latitude, array $data = [])
{
$offline_store = self::queryOfflineStoreInfo($data);
if (!empty($offline_store)) {
foreach ($offline_store as $key => $items) {
Redis::GeoAdd('offline_location', $items['latitude'], $items['longitude'], $items['id']);
}
$offline_location = Redis::GeoRadius('offline_location', $longitude, $latitude, 10000, 'km', 'WITHDIST', 'asc');
$store_info = self::eachOfflineLocation($offline_location, $offline_store);
return $store_info;
} else {
return $offline_store;
}
}
private static function queryOfflineStoreInfo(array $data = [])
{
$offline_store = DB::table('shop_real_stores')
->select([
'id',
'name',
'brief',
'mes',
'province',
'city',
'area',
'street',
'longitude',
'latitude',
'distribution',
'business_hours',
'address',
'phone',
'image_url',
'longitude',
'latitude',
])
->where(['status' => 1])
->lists();
return $offline_store;
}
private static function eachOfflineLocation(array $param, array $offline_store_info)
{
$positions_container = [];
foreach ($param as $k => $v) {
$positions_container[$v[0]] = $v;
}
$store_info = [];
foreach ($offline_store_info as $k => $v) {
foreach ($positions_container as $kk => $vv) {
if ($kk = $v['id']) {
$store_info[$k]['id'] = $v['id'];
$store_info[$k]['name'] = $v['name'];
$store_info[$k]['brief'] = $v['brief'];
$store_info[$k]['mes'] = $v['mes'];
$store_info[$k]['province'] = $v['province'];
$store_info[$k]['city'] = $v['city'];
$store_info[$k]['area'] = $v['area'];
$store_info[$k]['street'] = $v['street'];
$store_info[$k]['distribution'] = $v['distribution'];
$store_info[$k]['business_hours'] = json_decode($v['business_hours']);
$store_info[$k]['address'] = $v['address'];
$store_info[$k]['phone'] = $v['phone'];
$store_info[$k]['image_url'] = explode(',', $v['image_url']);
$store_info[$k]['apart'] = ($positions_container[$kk][1] * 1) * 1000;
$store_info[$k]['score'] = '5.0';
$store_info[$k]['longitude'] = $v['longitude'];
$store_info[$k]['latitude'] = $v['latitude'];
}
}
}
$apart_column = array_column($store_info, 'apart');
array_multisort($apart_column, SORT_ASC, $store_info);
$store_info = self::queryStoreRemark($store_info);
return $store_info;
}
private static function queryStoreRemark (array $offline_store_info)
{
$offline_store_ids = array_column($offline_store_info, 'id');
$store_remark = DB::table('shop_offline_store_remark')
->select([
'id',
'offline_store_id',
'total_score',
])
->where(['is_show' => 0])
->whereIn('id', $offline_store_ids)
->lists();
if (!empty($store_remark)) {
foreach ($offline_store_info as $k => $store_info) {
$offline_store_info[$k]['children'] = [];
foreach ($store_remark as $kk => $remark) {
if ($remark['offline_store_id'] == $store_info['id']) {
$offline_store_info[$k]['children'][] = $remark;
}
}
}
$score_num = [];
foreach ($offline_store_info as $k => $store_info) {
$score_num[$store_info['id']][] = count($store_info['children']);
}
foreach ($offline_store_info as $k => $store_info) {
$total_score = 0;
foreach ($store_info['children'] as $kk => $cld) {
foreach ($score_num as $kkk => $num) {
if ($kkk == $cld['offline_store_id']) {
$offline_store_info[$k]['score'] = ($total_score += $cld['total_score']) / $num[0];
}
}
}
unset($offline_store_info[$k]['children']);
}
return $offline_store_info;
} else {
return $offline_store_info;
}
}
|