2019独角兽企业重金招聘Python工程师标准>>>

获取附近的人

mongodb实现方式:http://www.infoq.com/cn/articles/depth-study-of-Symfony2

mysql实现功能:http://www.wubiao.info/470

在此使用elasticsearch,简称es实现:

pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.heli</groupId><artifactId>ElasticSearch</artifactId><version>0.0.1-SNAPSHOT</version><packaging>jar</packaging><name>ElasticSearch</name><url>http://maven.apache.org</url><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><es.version>1.5.2</es.version><lucene.maven.version>4.10.4</lucene.maven.version></properties><dependencies><dependency><groupId>org.elasticsearch</groupId><artifactId>elasticsearch</artifactId><version>${es.version}</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.8.2</version><scope>test</scope></dependency></dependencies>
</project>

实体City:

package com.heli.es;public class City {private long id;// idprivate String city;// 城市名private double lat;// 纬度private double lon;// 经度private double[] location;// 经纬度数组,第一个元素纬度,第二个元素经度private String title;// 标题public City(long id, String city, double lon, double lat, String title) {super();this.id = id;this.city = city;this.lat = lat;this.lon = lon;this.title = title;}public long getId() {return id;}public void setId(long id) {this.id = id;}public double getLat() {return lat;}public void setLat(double lat) {this.lat = lat;}public double getLon() {return lon;}public void setLon(double lon) {this.lon = lon;}public String getCity() {return city;}public void setCity(String city) {this.city = city;}public double[] getLocation() {return location;}public void setLocation(double[] location) {this.location = location;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}}

测试类:

package com.heli.es;import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.index.query.FilterBuilders.geoDistanceRangeFilter;import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse;
import org.elasticsearch.action.bulk.BulkRequestBuilder;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.client.Requests;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.geo.GeoDistance;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.query.FilterBuilder;
import org.elasticsearch.index.query.QueryStringQueryBuilder;
import org.elasticsearch.node.Node;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.sort.GeoDistanceSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import static org.elasticsearch.node.NodeBuilder.*;public class ES {// 创建索引public static void createIndex(String indexName, String indexType) throws IOException {Client esClient = new TransportClient().addTransportAddress(new InetSocketTransportAddress("127.0.0.1", 9300));// 创建MappingXContentBuilder mapping = createMapping(indexType);System.out.println("mapping:" + mapping.string());// 创建一个空索引esClient.admin().indices().prepareCreate(indexName).execute().actionGet();PutMappingRequest putMapping = Requests.putMappingRequest(indexName).type(indexType).source(mapping);PutMappingResponse response = esClient.admin().indices().putMapping(putMapping).actionGet();if (!response.isAcknowledged()) {System.out.println("Could not define mapping for type [" + indexName + "]/[" + indexType + "].");} else {System.out.println("Mapping definition for [" + indexName + "]/[" + indexType + "] succesfully created.");}}// 创建mappingpublic static XContentBuilder createMapping(String indexType) {XContentBuilder mapping = null;try {mapping = jsonBuilder().startObject()// 索引库名(类似数据库中的表).startObject(indexType).startObject("properties")// ID.startObject("id").field("type", "long").endObject()// 城市.startObject("city").field("type", "string").endObject()// 位置.startObject("location").field("type", "geo_point").endObject()// 标题.startObject("title").field("type", "string").endObject().endObject().endObject().endObject();} catch (IOException e) {e.printStackTrace();}return mapping;}// 添加数据public static Integer addIndexData(String indexName, String indexType) {Client client = new TransportClient().addTransportAddress(new InetSocketTransportAddress("127.0.0.1", 9300));List<String> cityList = new ArrayList<String>();City city1 = new City(1L, "北京", 116.395645, 39.929986, "中国人民站起来了,北京人民可以天天站在天安门广场吃烤鸭了");City city2 = new City(2L, "天津", 117.210813, 39.143931, "中国人民站起来了,天津人民可以天天在迎宾广场吃麻花了");City city3 = new City(3L, "青岛", 120.384428, 36.105215, "中国人民站起来了,青岛人民可以天天在五四广场吃海鲜了,虾TM就是贵点儿,38元一只,38元最后一次!!!最后一次,不要错过今天");City city4 = new City(4L, "哈尔滨", 126.657717, 45.773225, "中国人民站起来了,哈尔滨人民可以天天站在索菲亚广场吃红肠了");City city5 = new City(5L, "乌鲁木齐", 87.564988, 43.840381, "中国人民站起来了,乌鲁木齐人民可以天天在人民广场啃羊腿了");City city6 = new City(6L, "三亚", 109.522771, 18.257776, "中国人民站起来了,三亚人民可以天天在明珠广场吃鲍鱼了,三亚人民这次没丢脸,脸让青岛政府去丢吧,让他们创城去吧!");cityList.add(obj2JsonUserData(city1));cityList.add(obj2JsonUserData(city2));cityList.add(obj2JsonUserData(city3));cityList.add(obj2JsonUserData(city4));cityList.add(obj2JsonUserData(city5));cityList.add(obj2JsonUserData(city6));// 创建索引库List<IndexRequest> requests = new ArrayList<IndexRequest>();for (int i = 0; i < cityList.size(); i++) {IndexRequest request = client.prepareIndex(indexName, indexType).setSource(cityList.get(i)).request();requests.add(request);}// 批量创建索引BulkRequestBuilder bulkRequest = client.prepareBulk();for (IndexRequest request : requests) {bulkRequest.add(request);}BulkResponse bulkResponse = bulkRequest.execute().actionGet();if (bulkResponse.hasFailures()) {System.out.println("批量创建索引错误!");}return bulkRequest.numberOfActions();}public static String obj2JsonUserData(City city) {String jsonData = null;try {// 使用XContentBuilder创建json数据XContentBuilder jsonBuild = XContentFactory.jsonBuilder();jsonBuild.startObject().field("id", city.getId()).field("city", city.getCity()).startArray("location").value(city.getLat()).value(city.getLon()).endArray().field("title", city.getTitle()).endObject();jsonData = jsonBuild.string();System.out.println(jsonData);} catch (IOException e) {e.printStackTrace();}return jsonData;}// 模糊查询public static void query(String query) {Client client = new TransportClient().addTransportAddress(new InetSocketTransportAddress("127.0.0.1", 9300));QueryStringQueryBuilder qsqb = new QueryStringQueryBuilder(query);// qsqb.analyzer("ik").field("title");qsqb.field("title");client.admin().indices().prepareRefresh().execute().actionGet();SearchResponse searchResponse = client.prepareSearch("testes").setTypes("xq").setQuery(qsqb)// .setScroll(new TimeValue(60000)).addFields("id", "title", "updatetime")// .addSort("updatetime", SortOrder.DESC).addSort("_score", SortOrder.DESC)// .addHighlightedField("title").setHighlighterEncoder("UTF-8").execute().actionGet();// 搜索耗时Float usetime = searchResponse.getTookInMillis() / 1000f;// 命中记录数Long hits = searchResponse.getHits().totalHits();System.out.println("查询到记录数=" + hits);for (SearchHit hit : searchResponse.getHits()) {// 打分Float score = hit.getScore();Integer id = Integer.parseInt(hit.getFields().get("id").value().toString());String title = hit.getFields().get("title").value().toString();System.out.println(title);}}// 获取附近的城市public static void testGetNearbyCities(Client client, String index, String type, double lat, double lon) {SearchRequestBuilder srb = client.prepareSearch(index).setTypes(type);// wx4g0th9p0gk 为北京的geohash 范围为lt(小于) 1500km内的数据FilterBuilder builder = geoDistanceRangeFilter("location").point(lon, lat).from("1km").to("1000km").optimizeBbox("memory").geoDistance(GeoDistance.PLANE);srb.setPostFilter(builder);// 获取距离多少公里 这个才是获取点与点之间的距离的GeoDistanceSortBuilder sort = SortBuilders.geoDistanceSort("location");sort.unit(DistanceUnit.KILOMETERS);sort.order(SortOrder.ASC);sort.point(lon, lat);srb.addSort(sort);SearchResponse searchResponse = srb.execute().actionGet();SearchHits hits = searchResponse.getHits();SearchHit[] searchHists = hits.getHits();System.out.println("北京附近的城市(" + hits.getTotalHits() + "个):");for (SearchHit hit : searchHists) {String city = (String) hit.getSource().get("city");String title = (String) hit.getSource().get("title");// 获取距离值,并保留两位小数点BigDecimal geoDis = new BigDecimal((Double) hit.getSortValues()[0]);Map<String, Object> hitMap = hit.getSource();// 在创建MAPPING的时候,属性名的不可为geoDistance。hitMap.put("geoDistance", geoDis.setScale(2, BigDecimal.ROUND_HALF_DOWN));System.out.println(city + "距离北京" + hit.getSource().get("geoDistance") + DistanceUnit.KILOMETERS.toString() + "---" + title);}}public static void main(String[] args) throws IOException {Client client = new TransportClient().addTransportAddress(new InetSocketTransportAddress("127.0.0.1", 9300));String index = "testes";String type = "xq";// createIndex("testes", "xq");// addIndexData("testes", "xq");//double lat = 39.929986;double lon = 116.395645;long start = System.currentTimeMillis();testGetNearbyCities(client, index, type, lat, lon);// query("*海鲜*");long end = System.currentTimeMillis();System.out.println((end - start) + "毫秒");client.close();}
}

输出结果:

北京附近的城市(2个):
天津距离北京98.69km---中国人民站起来了,天津人民可以天天在迎宾广场吃麻花了
青岛距离北京486.53km---中国人民站起来了,青岛人民可以天天在五四广场吃海鲜了,虾TM就是贵点儿,38元一只,38元最后一次!!!最后一次,不要错过今天
1192毫秒

注:server 和client版本使用的是1.5.2,如果server版本用elasticsearch-rtf-master,sort的时候总是报:

Exception in thread "main" org.elasticsearch.action.search.SearchPhaseExecutionException: Failed to execute phase [query], all shards failed; shardFailures {[alee59cPQNuzRP4go6-5vw][testes][4]: SearchParseException[[testes][4]: from[-1],size[-1]: Parse Failure [Failed to parse source [{"post_filter":{"geo_distance_range":{"location":"wx4g0th9p0gk","from":"1km","to":"2000km","include_lower":true,"include_upper":true,"distance_type":"arc","optimize_bbox":"memory"}},"sort":[{"_geo_distance":{"location":[{"lat":39.929986,"lon":116.395645}],"unit":"km","distance_type":"arc"}}]}]]]; nested: ElasticsearchParseException[Numeric value expected]; }{[alee59cPQNuzRP4go6-5vw][testes][0]: SearchParseException[[testes][0]: from[-1],size[-1]: Parse Failure [Failed to parse source [{"post_filter":{"geo_distance_range":{"location":"wx4g0th9p0gk","from":"1km","to":"2000km","include_lower":true,"include_upper":true,"distance_type":"arc","optimize_bbox":"memory"}},"sort":[{"_geo_distance":{"location":[{"lat":39.929986,"lon":116.395645}],"unit":"km","distance_type":"arc"}}]}]]]; nested: ElasticsearchParseException[Numeric value expected]; }{[alee59cPQNuzRP4go6-5vw][testes][1]: SearchParseException[[testes][1]: from[-1],size[-1]: Parse Failure [Failed to parse source [{"post_filter":{"geo_distance_range":{"location":"wx4g0th9p0gk","from":"1km","to":"2000km","include_lower":true,"include_upper":true,"distance_type":"arc","optimize_bbox":"memory"}},"sort":[{"_geo_distance":{"location":[{"lat":39.929986,"lon":116.395645}],"unit":"km","distance_type":"arc"}}]}]]]; nested: ElasticsearchParseException[Numeric value expected]; }{[alee59cPQNuzRP4go6-5vw][testes][2]: SearchParseException[[testes][2]: from[-1],size[-1]: Parse Failure [Failed to parse source [{"post_filter":{"geo_distance_range":{"location":"wx4g0th9p0gk","from":"1km","to":"2000km","include_lower":true,"include_upper":true,"distance_type":"arc","optimize_bbox":"memory"}},"sort":[{"_geo_distance":{"location":[{"lat":39.929986,"lon":116.395645}],"unit":"km","distance_type":"arc"}}]}]]]; nested: ElasticsearchParseException[Numeric value expected]; }{[alee59cPQNuzRP4go6-5vw][testes][3]: SearchParseException[[testes][3]: from[-1],size[-1]: Parse Failure [Failed to parse source [{"post_filter":{"geo_distance_range":{"location":"wx4g0th9p0gk","from":"1km","to":"2000km","include_lower":true,"include_upper":true,"distance_type":"arc","optimize_bbox":"memory"}},"sort":[{"_geo_distance":{"location":[{"lat":39.929986,"lon":116.395645}],"unit":"km","distance_type":"arc"}}]}]]]; nested: ElasticsearchParseException[Numeric value expected]; }

换成1.5.2结果就好了,还有

.point(lon, lat)

必须经度在前,纬度在后,不然查询为空,跟一朋友聊说这个可能是个bug

另外查询速度太慢,应该哪个地方配置的问题,回头下周研究研究,周末愉快。

经过试验,原来创建client消耗了1秒左右,查询80毫秒,非常快

借鉴http://blog.csdn.net/loveisnull/article/details/45914115

转载于:https://my.oschina.net/ydsakyclguozi/blog/515361

使用elasticsearch1.5.2查询指定距离范围内的城市(类似微信附近的人)相关推荐

  1. SpringBoot+ElasticSearch根据经纬度,简单搜索指定距离范围内的数据

    1. 创建geo_point类型字段映射: PUT test {"mappings": {"user": {"properties": {& ...

  2. MySql根据经纬度查询任意距离范围内数据

    sql代码#当前位置经纬度 经度:117.215637 纬度:39.1373367 #表中经纬度字段 经度:longitude 纬度:latitude select * from( SELECT id ...

  3. Android——TextView指定字符串颜色高亮,实现类似微信、支付宝搜索结果中搜索字段高亮的效果

    代码: /*** 设置指定字体高亮** @return CharSequence型字符串*/ public static CharSequence getHighLightText(Context c ...

  4. SQLServer查询指定日期

    一.取指定范围的数字 create view myview as select re=rand() --自定义函数:取得指定范围的随机数 create function mydata ( @a int ...

  5. pandas使用query函数查询指定日期索引对应的dataframe数据行(select rows using a single date in dataframe)

    pandas使用query函数查询指定日期索引对应的dataframe数据行(select rows using a single date in dataframe) 目录 pandas使用qu

  6. pandas使用query函数查询指定日期索引之间对应的dataframe数据行(select rows date index between a certain date interval)

    pandas使用query函数查询指定日期索引之间对应的dataframe数据行(select rows where date index between a certain date interva ...

  7. 第三课 查询指定id的单个对象

    1.       student.xml中添加:(上一课已加入下面代码) <!--查询指定id的对象--!> <select id="selectStudentById&q ...

  8. Ubuntu通过apt-get安装指定版本和查询指定软件有多少个版本

    一.通过apt-get安装指定版本 apt-get install <<package name>>=<<version>> 二.查询指定软件有多少个版 ...

  9. Oralce 数据库 - 查询数据库所有的表和视图实例演示,查询指定用户下所有表和视图方法

    查询数据库所有的表有下面两个方法. -- 查询数据库所有的表 select * from all_tables; select * from all_tab_comments where table_ ...

最新文章

  1. 1803无法升级到2004_Win10再度误伤“友军”:升级五月更新后OneDrive同步报错
  2. html post no js,接受POST请求的Node.js服务器
  3. 【uoj#225】[UR #15]奥林匹克五子棋 构造
  4. 英国政府发人工智能深度报告,力图保持领先地位
  5. 关于css加div布局和表格布局,菜鸟学习笔记:表格布局和div+css布局
  6. java 读取 文本块_Java文本块
  7. BOM对象有哪些,列举window对象?
  8. paip.多个TOMCAT共存在一台主机上配置方法
  9. 卡巴斯基7.0如何设置授权文件
  10. 查询CI框架的版本号
  11. win11安装更新错误0x800f081f怎么解决?
  12. openlayers6【五】地图图层数据来源 source 详解
  13. 好书分享、能量传递-《软技能 代码之外的生存指南》自我营销篇
  14. OpenStack组件部署之Placement
  15. 苹果手机黑屏一直转圈怎么办
  16. linux 网络 指示灯 亮,Linux网络子系统中GRO的实现
  17. 小米AX6S刷OpenWrt和开启OpenClash,及刷回官网固件
  18. 鲜为人知而又实用的 Linux 命令大全
  19. VSCODE 配置cl.exe编译器
  20. python的for语句中i未被定义_python 报错 类名没有被定义

热门文章

  1. 关于arduino的各种网站
  2. 「SQL面试题库」 No_55 销售分析 I
  3. uni-app 跳转至手机浏览器
  4. 输入框有值无法输入问题
  5. 过账期间未清和关帐过帐期间设置
  6. 计算机未响应硬盘,最近电脑打开磁盘或文件夹老程序未响应为什么啊,有什么办法可以解决?...
  7. 关于C语言函数的简单理解
  8. 平面设计零基础怎么设计出一个完美的名片
  9. 输入框技巧 禁用输入法 禁用提示 提示归类
  10. MindManager2020永久激活版如何绘制思维导图