基于redis的geo类型实现“附近的xx”功能

发布于 2022-12-12 14:34:04阅读 786

这里假设要实现的是“附近的地铁站”功能,key为list,member为地铁站id

首先,你需要在redis里维护一个geo的列表(本质上是sorted set),当每个地铁站的经纬度有更新时,就使用

#地铁站id=1
#顺便提一下,相同key,member,不同经纬度,GEOADD会自动更新的
127.0.0.1:6379> GEOADD list CH 13.361389 38.115556 "1"

列表接口的实现

客户端会传一个经纬度,页码,每页条数,关键词(搜索后排序先不考虑)

生成模拟数据

$redis = new Redis();
$redis->connect("docker-redis", 6379);

$addrs=[
    ['name'=>'1北京四惠地铁站', 'id'=>1, 'long'=>116.495676, 'lat'=>39.908789],
    ['name'=>'2北京大望路地铁站', 'id'=>2, 'long'=>116.475835, 'lat'=>39.908278],
    ['name'=>'3北京国贸地铁站', 'id'=>3, 'long'=>116.459729, 'lat'=>39.908432],
    ['name'=>'4北京永安里地铁站', 'id'=>4, 'long'=>116.450334, 'lat'=>39.908478],
    ['name'=>'5北京建国门地铁站', 'id'=>5, 'long'=>116.434768, 'lat'=>39.908587],
    ['name'=>'6北京东单地铁站', 'id'=>6, 'long'=>116.418504, 'lat'=>39.908366],
    ['name'=>'7北京王府井地铁站', 'id'=>7, 'long'=>116.411565, 'lat'=>39.908106],
    ['name'=>'8北京西单地铁站', 'id'=>8, 'long'=>116.376302, 'lat'=>39.907194],
    ['name'=>'9北京复兴门地铁站', 'id'=>9, 'long'=>116.357757, 'lat'=>39.90715],
    ['name'=>'10北京南礼士路地铁站', 'id'=>10, 'long'=>116.352589, 'lat'=>39.907247],
    ['name'=>'11北京木樨地地铁站', 'id'=>11, 'long'=>116.337475, 'lat'=>39.907471],
    ['name'=>'12北京军事博物馆地铁站', 'id'=>12, 'long'=>116.321411, 'lat'=>39.90744],
];
$args=[];
foreach ($addrs as $v){
    $args[]=$v['long'];
    $args[]=$v['lat'];
    $args[]=$v['id'];
}
$ok=$redis->geoAdd('list',
...$args
);

查询

$r = $redis->geoRadiusByMember('list', 1, 1800, 'km', [
    'count' => 100,
//    'store'=>'list2',
    'storedist'=>'list3',
    'asc',
//    'WITHCOORD',
//    'WITHDIST',
//    'WITHHASH'
]);
$page=$_GET['page'];
$max=$_GET['max'];
$start = ($page-1) * $max;
$r=$redis->zRange('list3', $start, ($start + $max) - 1, true);//分数升序,取全部
var_dump(array_keys($r));

//todo:cw where id in(1,2)

$j=[
    ['name'=>'1北京四惠地铁站', 'id'=>1, 'long'=>116.495676, 'lat'=>39.908789],
    ['name'=>'2北京大望路地铁站', 'id'=>2, 'long'=>116.475835, 'lat'=>39.908278],
    ['name'=>'3北京国贸地铁站', 'id'=>3, 'long'=>116.459729, 'lat'=>39.908432],
];
$arr=[];
foreach ($r as $id=>$v){
    foreach ($j as $k=>$item){
        if ($item['id']==$id) $j[$k]['dist']=round($v, 2);
    }
}
$dist=array_column($j, 'dist');
array_multisort($dist, SORT_DESC, $j);
var_dump($j);

广而告之,我的新作品《语音助手》上架Google Play了,欢迎下载体验