在实习的项目中,获取视频列表时,需要实现一个按照附近视频获取列表的接口,通过爬文,一般有如下三种解决方法:
由于项目使用的 mysql5.5 数据库,所以采用的第一种方法,主要是需要确定查询的范围,即经度的范围和纬度的范围。
而一般我们所说的附近是一个圆形区域,我们先查询其最小的矩形区域内的视频,然后再计算这些视频的距离,剔除掉范围外的数据。
1.根据用户经纬度和范围,计算出矩形最大最小经纬度
private static double EARTH_RADIUS = 6378.137;// 地球半径
private static double rad(double d) {
return d * Math.PI / 180.0;//角度和弧度互换:1度=π/180
}
public static double[] getAround(double lat, double lon, int raidus) {//经度、纬度、范围
Double latitude = lat;
Double longitude = lon;
Double degree = (24901 * 1609) / 360.0;//2*PI*6378137 = 24901 * 1609,计算每一度有多长
double raidusMile = raidus;
Double dpmLat = 1 / degree;
Double radiusLat = dpmLat * raidusMile;//将radius转为度数
Double minLat = latitude - radiusLat;
Double maxLat = latitude + radiusLat;
Double mpdLng = degree * Math.cos(rad(latitude));
Double dpmLng = 1 / mpdLng;
Double radiusLng = dpmLng * raidusMile;
Double minLng = longitude - radiusLng;
Double maxLng = longitude + radiusLng;
return new double[] {minLat, minLng, maxLat, maxLng};
}
2.根据两点的经纬度计算距离:
public static double GetDistance(double lat1, double lng1, double lat2, double lng2) {
double radLat1 = rad(lat1);
double radLat2 = rad(lat2);
double a = radLat1 - radLat2;
double b = rad(lng1) - rad(lng2);
double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2)
+ Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
s = s * EARTH_RADIUS;
s = s * 1000;
s = Math.round(s * 10000) / 10000;
s = Math.ceil(s / 100) / 10;
return s;
}
3.数据库查询
可以通过example类简化我们的代码:
public List<Video> getByNearBy(BigDecimal longitude, BigDecimal latitude) {
VideoExample example= new VideoExample();
Criteria cri = example.createCriteria();
double[] raidus = GetLatAndLngUtil.getAround(latitude.doubleValue(), longitude.doubleValue(),configInfo.getRaidus());
//加入范围条件
cri.andLatitudeBetween(new BigDecimal(raidus[0]), new BigDecimal(raidus[2]));
cri.andLongitudeBetween(new BigDecimal(raidus[1]), new BigDecimal(raidus[3]));
List<Video> list = videoMapper.SelectByExample(criteria);//获取矩形范围内的记录
List<Video> res = new ArrayList<Video>();
for (Video video: list) {//筛选出在圆形范围内的记录
double distance = GetLatAndLngUtil.GetDistance(latitude.doubleValue(), longitude.doubleValue(),
moment.getLatitude().doubleValue(), moment.getLongitude().doubleValue());
res.add(video);
}
return res;
}
https://blog.csdn.net/universe_ant/article/details/74785989
MySQL 在 5.7 之后的版本支持了空间索引,也就是说我们可以索引来查找包含符合条件的空间数据的记录。
空间数据:
示例:
1.创建字段 location 类型为 POINT,并创建空间索引:
CREATE TABLE `demo` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(20) NOT NULL DEFAULT '',
`location` point NOT NULL,
PRIMARY KEY (`id`),
SPATIAL KEY `sp_index` (`location`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
2.插入记录:
INSERT INTO points VALUES (1,'testlocation',POINT(116.397389,39.908149));
3.查询记录:
# 定义范围,即定义一个面
SET @rect = CONCAT('POLYGON((116.373871 39.915786,116.417645 39.916444,116.41816 39.900841,116.374214 39.900182,116.373871 39.915786))');
# 用定义的面进行范围查询
select name,X(location),Y(location),Astext(location) from demo where INTERSECTS( location, GEOMFROMTEXT(@rect) ) ;