案例分析-单车定位

数据

单车日志数据

这个数据是单车用户使用的后台记录数据,主要是开锁,保修等日志记录。字段说明如下:

  • 触发事件
  • 访问的url
  • 时间
  • 用户的id
  • 经度
  • 维度
  • 省份
  • 城市
  • 区(县)

原始数据如下所示:

{"event_type":0,"page":"/pages/index/index","time":"2018-03-14 12:35:14","uid":"oDK8U0c_VZqQTMVsab9oM219vZpw","longitude":126.67032,"latitude":45.767525,"province":"黑龙江省","city":"哈尔滨市","district":"南岗区"}
{"event_type":0,"page":"/pages/recharge/recharge","money":"100","channel":"wx","time":"2018-03-14 12:35:18","uid":"oDK8U0c_VZqQTMVsab9oM219vZpw","longitude":126.67032,"latitude":45.767525,"province":"黑龙江省","city":"哈尔滨市","district":"南岗区"}
{"page":"/pages/index/index","event_type":1,"time":"2018-03-14 12:35:22","uid":"oF-8j0aNka8IQYCZsxyrO6X7jzqY","longitude":112.12255,"latitude":32.009,"province":"湖北省","city":"襄阳市","district":"襄城区"}
{"event_type":0,"page":"/pages/index/index","time":"2018-03-14 12:35:20","uid":"oDK8U0c_VZqQTMVsab9oM219vZpw","longitude":126.67032,"latitude":45.767525,"province":"黑龙江省","city":"哈尔滨市","district":"南岗区"}

位置信息数据

位置信息数据主要是北京的经纬度对应的位置信息数据,存储形式是csv(csv是以逗号分隔的文本数据)
字段的说明都在文件的一行,文件的第一行是表头,即文件字段的名字。
文件样例数据为:
北京poi数据图片

项目说明

需求

单车位置信息太宽泛了,希望能够得到更为精准的地理位置信息。

依赖说明

	<!-- json解析工具 -->
	<dependency>
	    <groupId>com.alibaba</groupId>
	    <artifactId>fastjson</artifactId>
	    <version>1.2.47</version>
	</dependency>
	<!-- geohash -->
	<dependency>
	    <groupId>ch.hsr</groupId>
	    <artifactId>geohash</artifactId>
	    <version>1.3.0</version>
	</dependency>
	
  	<!-- httpclient -->
	<dependency>
	    <groupId>commons-httpclient</groupId>
	    <artifactId>commons-httpclient</artifactId>
	    <version>3.1</version>
	</dependency>

项目原理图

单车定位项目流程图

geoHash原理介绍

geoHash算法是将经纬度信息的二维数据转换成为一维数据的一种算法,主要使用的是逼近思想,具体的说明可以进群看更为详细的文档。
geoHash算法使用测试

package cn.pengpeng.day03.test;

import ch.hsr.geohash.GeoHash;
/**
 * 测试geohash
 * @author pengpeng
 */
public class TestGeoHash {
	public static void main(String[] args) {
		String geohash = GeoHash.withCharacterPrecision(45.767525, 126.67032, 8).toBase32();
		System.out.println(geohash);
	}
}

httpClient使用说明

HttpClient是用来模拟浏览器上网请求数据的工具,

可以通过url进行网络访问从而获取所需要的数据。
HttpClient的使用如下说明:

package cn.pengpeng.day03.test;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.methods.GetMethod;

public class TestHttpClient {
	public static void main(String[] args) throws Exception {
		String uri = "这里可以填入需要访问的url";
		//可以类似于浏览器对象
		HttpClient httpClient = new HttpClient();
		//uri 资源统一定位     url也是uri的一种
		HttpMethod method = new GetMethod(uri);
		//执行,类似于浏览器访问指定的网址
		httpClient.executeMethod(method);
		//返回结果
		String ret = method.getResponseBodyAsString();
		System.out.println(ret);
	}
}

百度地图接口调用说明

这里面有些数据本地仓库是没有收录的,所以需要从网络中获取,所以需要从百度地图上获取,(这里可以使用其他的地图来获取,只需要看下其他的地图的接口是怎么使用的。)
百度地图提供很多的地图开发方式,以及接入方式,本地使用的是百度的web接口api提供的逆地理位置接口(根据经纬度查出相对应的地址信息)。这里需要注册下,申请开发者的key。
具体的接入方式,以及key的使用方式都在百度网站上有详细的说明,传入的参数,以及返回参数的说明都很详细。
百度web服务接口
百度逆地理位置

开发流程

工具类

这里面实现了经纬度转化为一维数据的操作,和通过url来总网络上获取具体位置信息的数据。

package cn.pengpeng.day03.util;

import java.io.IOException;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.methods.GetMethod;

import ch.hsr.geohash.GeoHash;

public class Util {
	public static void main(String[] args) {
		String json = getAddrJsonByNet(126.67032, 45.767525);
		System.out.println(json);
	}
	
	/**
	 * 经纬信息,转换成geohash
	 * @param longitude
	 * @param latitude
	 */
	public static String getGeoHash(double longitude, double latitude) {
		String ret = GeoHash.withCharacterPrecision(latitude, longitude, 8).toBase32();
		return ret;
	}
	
	/**
	 * 通过经纬度信息获取到返回的json数据
	 * @param longitude 经度
	 * @param latitude 维度
	 * @return geohash值
	 */
	public static String getAddrJsonByNet(double longitude, double latitude){
		String uri = "http://api.map.baidu.com/geocoder/v2/?callback=renderReverse&location="+latitude+","+longitude+"&output=json&pois=1&ak=eZ9AW83ni3SKy34ypAEoQLqU1tov7Un1";
		HttpClient client = new HttpClient();
		HttpMethod method = new GetMethod(uri);	
		try {
			client.executeMethod(method);
			String ret = method.getResponseBodyAsString();
			String substring = ret.substring("renderReverse && renderReverse(".length()-2, ret.length()-1);
			return substring;
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}
}

使用到的JavaBean

封装单车数据

package cn.pengpeng.day03.bean;

/**
 * 单车日志信息封装
 * @author pengpeng
 */
public class BikeBean {
	//{"event_type":0,"page":"/pages/index/index","time":"2018-03-14 12:35:14",
	//"uid":"oDK8U0c_VZqQTMVsab9oM219vZpw","longitude":126.67032,"latitude":45.767525,"province":"黑龙江省",
	//"city":"哈尔滨市","district":"南岗区"}
	private int event_type;
	private String page;
	private String time;
	private String uid;
	private double longitude;
	private double latitude;
	private String province;
	private String city;
	private String district;
	public int getEvent_type() {
		return event_type;
	}
	public void setEvent_type(int event_type) {
		this.event_type = event_type;
	}
	public String getPage() {
		return page;
	}
	public void setPage(String page) {
		this.page = page;
	}
	public String getTime() {
		return time;
	}
	public void setTime(String time) {
		this.time = time;
	}
	public String getUid() {
		return uid;
	}
	public void setUid(String uid) {
		this.uid = uid;
	}
	public double getLongitude() {
		return longitude;
	}
	public void setLongitude(double longitude) {
		this.longitude = longitude;
	}
	public double getLatitude() {
		return latitude;
	}
	public void setLatitude(double latitude) {
		this.latitude = latitude;
	}
	public String getProvince() {
		return province;
	}
	public void setProvince(String province) {
		this.province = province;
	}
	public String getCity() {
		return city;
	}
	public void setCity(String city) {
		this.city = city;
	}
	public String getDistrict() {
		return district;
	}
	public void setDistrict(String district) {
		this.district = district;
	}
	@Override
	public String toString() {
		return "BikeBean [event_type=" + event_type + ", page=" + page + ", time=" + time + ", uid=" + uid
				+ ", longitude=" + longitude + ", latitude=" + latitude + ", province=" + province + ", city=" + city
				+ ", district=" + district + "]";
	}
}

以下三个bean是封装的网络结果bean

package cn.pengpeng.day03.bean;
/**
 * 从百度地图获取的数据封装
 * @author pengpeng
 */
public class ResultBean {
	private int status;
	private Result result;
	public int getStatus() {
		return status;
	}
	public void setStatus(int status) {
		this.status = status;
	}
	public Result getResult() {
		return result;
	}
	public void setResult(Result result) {
		this.result = result;
	}
	@Override
	public String toString() {
		return "ResultBean [status=" + status + ", result=" + result + "]";
	}
}
package cn.pengpeng.day03.bean;

/**
 * 从百度地图获取的json数据进行封装
 * @author pengpeng
 */
public class Result {
	private String formatted_address;
	private AddressComponent addressComponent;
	public String getFormatted_address() {
		return formatted_address;
	}
	public void setFormatted_address(String formatted_address) {
		this.formatted_address = formatted_address;
	}
	public AddressComponent getAddressComponent() {
		return addressComponent;
	}
	public void setAddressComponent(AddressComponent addressComponent) {
		this.addressComponent = addressComponent;
	}
	@Override
	public String toString() {
		return "Result [formatted_address=" + formatted_address + ", addressComponent=" + addressComponent + "]";
	}
}
package cn.pengpeng.day03.bean;

public class AddressComponent {
	private String country;
	private String province;
	private String city;
	private String district;
	private String town;
	private String street;
	private String street_number;
	public String getCountry() {
		return country;
	}
	public void setCountry(String country) {
		this.country = country;
	}
	public String getProvince() {
		return province;
	}
	public void setProvince(String province) {
		this.province = province;
	}
	public String getCity() {
		return city;
	}
	public void setCity(String city) {
		this.city = city;
	}
	public String getDistrict() {
		return district;
	}
	public void setDistrict(String district) {
		this.district = district;
	}
	public String getTown() {
		return town;
	}
	public void setTown(String town) {
		this.town = town;
	}
	public String getStreet() {
		return street;
	}
	public void setStreet(String street) {
		this.street = street;
	}
	public String getStreet_number() {
		return street_number;
	}
	public void setStreet_number(String street_number) {
		this.street_number = street_number;
	}
	@Override
	public String toString() {
		return "AddressComponent [country=" + country + ", province=" + province + ", city=" + city + ", district="
				+ district + ", town=" + town + ", street=" + street + ", street_number=" + street_number + "]";
	}
}

构建本地仓库

本地仓库是根据bj-poi.csv文件进行一些列的操作进行构建的。主要是过滤掉一些不需要的字段,并且对经纬度信息进行转换。

具体代码如下:

package cn.pengpeng.day03;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.InputStreamReader;

import cn.pengpeng.day03.util.Util;

/**
 * 本地仓库生成
 * @author pengpeng
 *
 */
public class Repository {
	public static void main(String[] args){
		try {
			String inpath = "d:\\data\\bj-poi-1.csv";
			String outpath = "d:\\data\\Repository.tsv";
			//乱码怎么解决
			BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(inpath), "gbk"));
			BufferedWriter bw = new BufferedWriter(new FileWriter(outpath));
			br.readLine();//跳过第一行
			String line = null;
			//玉竹园小区1里5号楼,地名地址信息;门牌信息;楼栋号,116.150359,39.724234,北京市房山区拱辰街道昊天嘉园玉竹园一里,北京市,10,房山区,长虹东路,110111,
			while((line = br.readLine())!=null){
				try {
					String[] split = line.split(",");
					String name = split[0];
					double longitude = Double.parseDouble(split[2]);//经度
					double latitude = Double.parseDouble(split[3]);//维度
					String city = split[5];
					String district = split[7];
					
					//geohash转换
					String geoHash = Util.getGeoHash(longitude,latitude);
					String ret = geoHash+"\t"+city+"\t"+city+"\t"+district+"\t"+name;
					bw.write(ret);
					bw.newLine();
				} catch (Exception e) {
					e.printStackTrace();
				}	
			}
			br.close();
			bw.flush();
			bw.close();	
		} catch (Exception e) {
			e.printStackTrace();
		}	
	}
}

查找位置信息

查找位置信息数据,主要是读取bikes.log单车日志数据,然后到仓库查找和去百度地图查找。

package cn.pengpeng.day03;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.HashMap;
import java.util.Map;

import com.alibaba.fastjson.JSON;

import cn.pengpeng.day03.bean.AddressComponent;
import cn.pengpeng.day03.bean.BikeBean;
import cn.pengpeng.day03.bean.ResultBean;
import cn.pengpeng.day03.util.Util;

/**
 * 核心逻辑
 * @author pengpeng
 *
 */
public class TestMain {
	static Map<String, String> map = null;
	static{
		map = loadRepositoryData();
	}
	
	public static void main(String[] args) {
		String path = "d:\\data\\bikes.log";
		try (BufferedReader br =new BufferedReader(new FileReader(path));){
			String line = null;
			while((line = br.readLine())!=null){
				//解析数据
				BikeBean bikeBean = JSON.parseObject(line, BikeBean.class);
				//获取经纬度信息
				double longitude = bikeBean.getLongitude();
				double latitude = bikeBean.getLatitude();
				//查找数据
				String ret = findAddr(longitude,latitude);
				
				System.out.println(ret);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 根据经纬度信息,查找到具体的位置信息
	 * 1:本地查找
	 * 2:网络中查找
	 * @param longitude
	 * @param latitude
	 * @return
	 */
	private static String findAddr(double longitude, double latitude) {
		//本地查找
		String ret = findAddrByLocal(longitude,latitude);
		if(ret == null){
			//本地查找不到的时候去网络中查找
			ret = findAddrByNet(longitude,latitude);
		}
		return ret;
	}

	/**
	 * 从网络中查找数据
	 * @param longitude
	 * @param latitude
	 * @return
	 */
	private static String findAddrByNet(double longitude, double latitude) {
		//获取json   
		String addrJsonByNet = Util.getAddrJsonByNet(longitude, latitude);
		if(addrJsonByNet == null){
			return null;
		}
		ResultBean retBean = JSON.parseObject(addrJsonByNet, ResultBean.class);
		//字段提取,组合
		AddressComponent addressComponent = retBean.getResult().getAddressComponent();
		String geoHash = Util.getGeoHash(longitude, latitude);
		String ret =geoHash+"\t"+addressComponent.getProvince()+"\t"+addressComponent.getCity()+"\t"+addressComponent.getDistrict()+"\t"
			+ addressComponent.getTown()+addressComponent.getStreet()+addressComponent.getStreet_number();
		//写到本地中     注意:追加数据
		
		//写到内存(map)中一份
		map.put(geoHash, ret);
		return ret;
	}

	/**
	 * 本地查找数据
	 * @param longitude
	 * @param latitude
	 * @return
	 */
	private static String findAddrByLocal(double longitude, double latitude) {
		String geoHash = Util.getGeoHash(longitude, latitude);
		String ret = map.get(geoHash);
		return ret;
	}

	/**
	 * 加载仓库数据
	 */
	public static Map<String, String> loadRepositoryData(){
		Map<String, String> map = new HashMap<>();
		String path = "d:\\data\\Repository.tsv";
		try (BufferedReader br =new BufferedReader(new FileReader(path));){
			String line = null;
			while((line = br.readLine())!=null){
				String geoHash = line.split("\t")[0];
				map.put(geoHash, line);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return map;
	}
}

本文由鹏鹏出品
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值