php根据经纬度确定附近的人,优化附近的人,根据经纬度计算距离离我最近的人(数据量大)...

在很多的APP或者移动互联网的应用中,地图经纬度和用户地理位置以及附近的人常常吸引到用户的使用。

如果是全国的用户,这个时候又恰巧需要按照由近到远的分页展示。已知我的经纬度(可能是实时定位获取的),也知道其他用户(可能是商家)的经纬度.

常规思路:取出所有数据的经纬度,进行计算距离,并php数组排序截取分页。但是问题发生了,当数据量很大的时候,就会存在取数据很多,计算两点间的距离也很耗时,这样就会存在性能的瓶颈。会导致cpu和内存负荷过高,甚至服务器宕机等。

下面是优化后的思路:根据我的经纬度加减一定的经纬度,在数据库里面取出来,如果没取到数据就继续扩大范围,直到取到数据。对于这个相应的参数和扩大的范围根据你的需要去设置。我在此处设置为,第一次经纬度绝对值为1,5,10,50,100,200(其实可以不用到200,经度为正负180,纬度为正负90,如果你是国内应用的话,这个更加可以细化,请自己去百度地图上取值。)

下面直接上代码(有些粗糙,欢迎各位进行优化,需要的话可以写个递归)此处使用ThinkPHP框架

//获取附近的人

public function nearbyFriends(){

header('Content-Type:text/html;Charset=UTF-8'); //字符编码

$lat = I("lat");//纬度

$lng = I("lng");//经度

$page = I("page") ? I("page") : 1;

$rows = 20;

$where = " state=1 ";//状态正常的朋友

if($lat && $lng){//有经纬度

$lat1 = $lat + 1; $lat_1 = $lat - 1;

$lng1 = $lng + 1; $lng_1 = $lng - 1;

$where1 = $where . " AND lat>'{$lat_1}' AND lat'{$lng_1}' AND lng

$askCnt = M("member_list")->where($where1)->count("id");//统计未读消息数

if($askCnt < 500 ){

$lat1 = $lat + 5; $lat_1 = $lat - 5;

$lng1 = $lng + 5; $lng_1 = $lng - 5;

$where5 = $where . " AND lat>'{$lat_1}' AND lat'{$lng_1}' AND lng

$askCnt = M("member_list")->where($where5)->count("id");//统计未读消息数

if($askCnt < 500 ){

$lat1 = $lat + 10; $lat_1 = $lat - 10;

$lng1 = $lng + 10; $lng_1 = $lng - 10;

$where10 = $where . " AND lat>'{$lat_1}' AND lat'{$lng_1}' AND lng

$askCnt = M("member_list")->where($where10)->count("id");//统计未读消息数

if($askCnt < 500 ){

$lat1 = $lat + 50; $lat_1 = $lat - 50;

$lng1 = $lng + 50; $lng_1 = $lng - 50;

$where50 = $where . " AND lat>'{$lat_1}' AND lat'{$lng_1}' AND lng

$askCnt = M("member_list")->where($where50)->count("id");//统计未读消息数

if($askCnt < 500 ){

$lat1 = $lat + 100; $lat_1 = $lat - 100;

$lng1 = $lng + 100; $lng_1 = $lng - 100;

$where100 = $where . " AND lat>'{$lat_1}' AND lat'{$lng_1}' AND lng

$askCnt = M("member_list")->where($where100)->count("id");//统计未读消息数

}

}

}

}

}

if($askCnt){//取到500条数据---根据经纬度

$gap_where = $where . " AND lat>'{$lat_1}' AND lat'{$lng_1}' AND lng

}else{//根据经纬度没取到数据

$gap_where = $where;

}

$offset = floor($page / 25);//每次取500条

$dbPageSize = ($offset+1) * 500;//取500条进行计算排序

$arr = M("member_list")->where($gap_where)->limit("{$offset},{$dbPageSize}")->select();

//echo M("member_list")->_sql();

if($arr){

foreach ($arr as $key => $value) {

if($lat != 0 && $lng != 0 && $value['lat'] && $value['lng']){

$my_map = $lat.','.$lng;

$vip_map = $value['lat'].','.$value['lng'];

$distance = $this->getDistance($my_map,$vip_map);

}else{

$distance = mt_rand(100,2000);//给个随机的距离

}

//排序的arr

$arrSort[$value['id']] = $distance;

$arr[$key]['distance'] = $distance;

if($distance >= 1000){

if($distance < 1000000){//8.88km

$arr[$key]['distance'] = round($distance/1000,2)."km";

}else{//102km

$arr[$key]['distance'] = ceil($distance/1000)."km";

}

}else{//385m

$arr[$key]['distance'] = $distance."m";

}

}

asort($arrSort);

$newArr = array();//所有的

foreach($arrSort as $kk => $vv){

foreach($arr as $kkk =>$vvv){

if($kk == $vvv['id']){

$newArr[] = $vvv;

}

}

}

$start = ($page-1)*$rows;//计算每次分页的开始位置

$total = count($newArr); //总的记录数

$countPage = ceil($total/$rows); //计算总页面数

$pageData = array();

$pageData = array_slice($newArr,$start,$rows);// 最后一个值为true 保留原来键

$data_list["firends"] = $pageData;

$this->result_print(1,"获取附近的人成功!",$data_list);

}else{

$this->result_print(0,"未找到附近的人!");

}

}

附上计算两点间距离的方法

//求两者经纬度之间的距离-- my_map 我的经纬度---map 商家经纬度

public function getDistanceNew($my_map,$map){

if(!strstr($my_map,',')){ return '未知'; }//找到分号再进行

if(!strstr($map,',')){ return '未知'; }//找到分号再进行

$myMap = explode(',',$my_map);

$mapArr = explode(',',$map);

$lat1 = $myMap['1'];

$lng1 = $myMap['0'];

$lat2 = $mapArr['1'];

$lng2 = $mapArr['0'];

//将角度转为狐度

$radLat1 = deg2rad($lat1);//deg2rad()函数将角度转换为弧度

$radLat2 = deg2rad($lat2);

$radLng1 = deg2rad($lng1);

$radLng2 = deg2rad($lng2);

$a = $radLat1 - $radLat2;

$b = $radLng1 - $radLng2;

$s = 2*asin(sqrt(pow(sin($a/2),2)+cos($radLat1)*cos($radLat2)*pow(sin($b/2),2)))*6378.137*1000;

return round($s);

}

0c6e7dfcfec2882cbdce85d42a749b10.png

你可以根据你的用户数据进行颗粒度细化。根据你的需求进行优化你的数据吧。

有兴趣的人会redis的也可以研究研究 http://redisdoc.com/geo/georadius.html

很多人就像山川,像河流。山川不曾回应,河流一去不返,却依然在你生命里,波澜壮阔。

在Java中,你可以使用Haversine公式来计算给定经纬度和半径的范围内的用户。 下面是一个示例代码,展示了如何使用Haversine公式计算范围内的用户: ```java import java.util.ArrayList; import java.util.List; public class UserLocation { private double latitude; private double longitude; public UserLocation(double latitude, double longitude) { this.latitude = latitude; this.longitude = longitude; } public double getLatitude() { return latitude; } public double getLongitude() { return longitude; } } public class UserLocationCalculator { private static final int EARTH_RADIUS = 6371; // Earth's radius in kilometers public List<UserLocation> getUsersInRadius(List<UserLocation> users, double latitude, double longitude, double radius) { List<UserLocation> usersInRadius = new ArrayList<>(); for (UserLocation user : users) { double distance = calculateDistance(latitude, longitude, user.getLatitude(), user.getLongitude()); if (distance <= radius) { usersInRadius.add(user); } } return usersInRadius; } private double calculateDistance(double lat1, double lon1, double lat2, double lon2) { double dLat = Math.toRadians(lat2 - lat1); double dLon = Math.toRadians(lon2 - lon1); double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) * Math.sin(dLon / 2) * Math.sin(dLon / 2); double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); return EARTH_RADIUS * c; } } ``` 你可以使用`getUsersInRadius()`方法来获取给定经纬度和半径范围内的用户。传入用户列表、目标经纬度和半径,返回在范围内的用户列表。 注意:此代码使用的距离单位为千米。如果要使用其他单位(如英里),请相应地调整代码中的地球半径常量和距离计算结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值