附近卖家实现1.0

41 篇文章 2 订阅

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

优点:采用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();
	}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值