附近卖家实现1.0

xiaoxiao2021-02-28  58

该接口采用数据库函数读取封装形式

优点:采用ORACLE控件计算函数,距离读取精确,编码简单;缺点:大批量数据(数据达到几十万之后)做附近位置读取时导致数据读取缓慢

实现代码:

1.数据库函数创建:

create or replace function get_distance( jd1 number, wd1 number, jd2 number, wd2 number ) return number is--返回米 begin if jd1 is not null and wd1 is not null and jd2 is not null and wd2 is not null then return ROUND(sdo_geom.sdo_distance(mdsys.sdo_geometry(2001, 8307, mdsys.sdo_point_type(jd1, wd1, 0), null, null), mdsys.sdo_geometry(2001, 8307, mdsys.sdo_point_type(jd2, wd2, 0), null, null), 0.005)); else --return 0; --return 99999; return null; end if; end;

2.一般附近数据查询有范围限制,如果直接使用函数进行距离范围限制会导致数据查询缓慢,因此我们先取当前坐标点范围4个坐标点内的大概范围数据,再对这个范围内数据做距离计算

     1)取当前坐标周围4个角落的经纬度

/** * @title * @date 2017年3月15日 * @author niuchuang * @param longitude 经度 * @param latitude 纬度 * @param dis 距离 米 * @return */ public static Map<String,Double> getDtFwSj(Double longitude, Double latitude, Double dis) { Map<String,Double> _map=new HashMap<String,Double>(); if (longitude!=null && latitude!=null && dis!=null) { // 先计算查询点的经纬度范围 double r = 6371;// 地球半径千米 // double dis = 0.5;// 0.5千米距离 dis = dis / 1000;// 米转换千米 double dlng = 2 * Math.asin(Math.sin(dis / (2 * r)) / Math.cos(latitude * Math.PI / 180)); dlng = dlng * 180 / Math.PI;// 角度转为弧度 /* double dlng = 2 * Math.asin(Math.sin(dis / (2 * r)) / Math.cos(latitude)); // 转换弧度 dlng = dlng * (180/Math.PI); */ double dlat = dis / r; // 转换弧度 dlat = dlat * 180 / Math.PI; // 处理余弦值为负数 double minlng = dlng > 0 ? longitude - dlng : longitude + dlng; double maxlng = dlng > 0 ? longitude + dlng : longitude - dlng; double minlat = dlat > 0 ? latitude - dlat : latitude + dlat; double maxlat = dlat > 0 ? latitude + dlat : latitude - dlat; _map.put("minjd", minlng); _map.put("maxjd", maxlng); _map.put("minwd", minlat); _map.put("maxwd", maxlat); } return _map; }

  2)SQL查询封装

public String getSql(Map paramMap,List<Object[]> _valueObject){ Object valueObject[]=new Object[]{}; //附近条件 Double longitude=MapUtils.getDouble(paramMap, "longitude"),latitude=MapUtils.getDouble(paramMap, "latitude"),dis=MapUtils.getDouble(paramMap, "dis"); String colum="id,qymc,qybm,address,jd,wd"; StringBuilder sql=new StringBuilder(); sql.append("select ").append(colum).append(" from b_qyxx cyqy where 1=1"); //4个坐标点内数据限制,大概的数据查询限制,避免直接使用数据库函数导致查询缓慢 Map<String,Double> dtfw=WxApiUtil.getDtFwSj(longitude, latitude, dis); if (longitude!=null && latitude!=null && dis!=null && dis!=-1) { double minlng = MapUtils.getDouble(dtfw, "minjd", 0d); double maxlng = MapUtils.getDouble(dtfw, "maxjd", 0d); double minlat = MapUtils.getDouble(dtfw, "minwd", 0d); double maxlat = MapUtils.getDouble(dtfw, "maxwd", 0d); sql.append(" and (cyqy.jd between ? and ?) and (cyqy.wd between ? and ?)"); valueObject = ArrayUtils.add(valueObject, minlng); valueObject = ArrayUtils.add(valueObject, maxlng); valueObject = ArrayUtils.add(valueObject, minlat); valueObject = ArrayUtils.add(valueObject, maxlat); } //对模糊查询进行转译,避免查传入“%”出查询出没有“%”的数据 String qymc=MapUtils.getString(paramMap, "qymc"); if (StringUtils.isNotBlank(qymc)){ sql.append(" and qymc like ? escape '\\'"); valueObject = ArrayUtils.add(valueObject, "%"+qymc.replaceAll("\\%", "\\\\%")+"%"); } //该处共使用3层SQL查询封装;第一层:读取当前坐标点范围附近4个人坐标点内数据,进行简单的数据过滤,避免直接使用函数造成查询缓慢;第二层:在第一层的基础上通过数据库函数度取出距离信息;第三层: //在前两层的基础上,通过第二层得到的距离对范围再做一次精确限制(未在第二层做限制是因为如果做限制需调用两次函数),后面直接加距离排序即可 sql=new StringBuilder("select sel.*,abs(get_distance(jd,wd,"+longitude+","+latitude+")) jl_length from ("+sql+") sel"); sql=new StringBuilder("select dp.* from ("+sql.toString()+") dp where jl_length<="+dis); //sql=new StringBuilder("select dp.* from (select sel.*,abs(get_distance(jd,wd,"+longitude+","+latitude+")) jl_length from ("+sql+") sel) dp where jl_length<="+dis); sql.append(" order by jl_length asc "); _valueObject.add(valueObject); return sql.toString(); }

转载请注明原文地址: https://www.6miu.com/read-76679.html

最新回复(0)