使用elasticsearch1.5.2实现查找附近的人

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>

用户实体:

package com.heli.es;

public class User {

	private long id;// id
	private String name;// 姓名
	private double lat;// 纬度
	private double lon;// 经度
	private double[] location;// hashcode

	public User(long id, String name, double lat, double lon) {
		super();
		this.id = id;
		this.name = name;
		this.lat = lat;
		this.lon = lon;
	}
	public long getId() {
		return id;
	}
	public void setId(long id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	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 double[] getLocation() {
		return location;
	}
	public void setLocation(double[] location) {
		this.location = location;
	}
}

测试类:

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.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;

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.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;
/**
 * 实现附近的人功能,最大限额1000人,1米到100米范围内的人
 */
public class ES4 {

	// 创建索引
	public static void createIndex(String indexName, String indexType) throws IOException {
		Client esClient = new TransportClient().addTransportAddress(new InetSocketTransportAddress("127.0.0.1", 9300));
		// 创建Mapping
		XContentBuilder 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.");
		}
	}

	// 创建mapping
	public static XContentBuilder createMapping(String indexType) {
		XContentBuilder mapping = null;
		try {
			mapping = jsonBuilder().startObject()
					// 索引库名(类似数据库中的表)
					.startObject(indexType).startObject("properties")
					// ID
					.startObject("id").field("type", "long").endObject()
					// 姓名
					.startObject("name").field("type", "string").endObject()
					// 位置
					.startObject("location").field("type", "geo_point").endObject()
			.endObject().endObject().endObject();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return mapping;
	}

	// 添加数据
	public static Integer addIndexData100000(String indexName, String indexType) {
		Client client = new TransportClient().addTransportAddress(new InetSocketTransportAddress("127.0.0.1", 9300));
		List<String> cityList = new ArrayList<String>();

		double lat = 39.929986;
		double lon = 116.395645;
		for (int i = 0; i < 100000; i++) {
			double max = 0.00001;
			double min = 0.000001;
			Random random = new Random();
			double s = random.nextDouble() % (max - min + 1) + max;
			DecimalFormat df = new DecimalFormat("######0.000000");
			// System.out.println(s);
			String lons = df.format(s + lon);
			String lats = df.format(s + lat);
			Double dlon = Double.valueOf(lons);
			Double dlat = Double.valueOf(lats);

			User city1 = new User(i, "郭德纲"+i, dlat, dlon);
			cityList.add(obj2JsonUserData(city1));
		}
		// 创建索引库
		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(User user) {
		String jsonData = null;
		try {
			// 使用XContentBuilder创建json数据
			XContentBuilder jsonBuild = XContentFactory.jsonBuilder();
			jsonBuild.startObject().field("id", user.getId()).field("name", user.getName()).startArray("location").value(user.getLat()).value(user.getLon()).endArray()
					.endObject();
			jsonData = jsonBuild.string();
			System.out.println(jsonData);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return jsonData;
	}

	// 获取附近的人
	public static void testGetNearbyPeople(Client client, String index, String type, double lat, double lon) {
		SearchRequestBuilder srb = client.prepareSearch(index).setTypes(type);
		srb.setFrom(0).setSize(1000);//1000人
		// lon, lat位于谦的坐标,查询距离于谦1米到1000米
		FilterBuilder builder = geoDistanceRangeFilter("location").point(lon, lat).from("1m").to("100m").optimizeBbox("memory").geoDistance(GeoDistance.PLANE);
		srb.setPostFilter(builder);
		// 获取距离多少公里 这个才是获取点与点之间的距离的
		GeoDistanceSortBuilder sort = SortBuilders.geoDistanceSort("location");
		sort.unit(DistanceUnit.METERS);
		sort.order(SortOrder.ASC);
		sort.point(lon, lat);
		srb.addSort(sort);

		SearchResponse searchResponse = srb.execute().actionGet();

		SearchHits hits = searchResponse.getHits();
		SearchHit[] searchHists = hits.getHits();
		 // 搜索耗时
        Float usetime = searchResponse.getTookInMillis() / 1000f;
		System.out.println("于谦附近的人(" + hits.getTotalHits() + "个),耗时("+usetime+"秒):");
		for (SearchHit hit : searchHists) {
			String name = (String) hit.getSource().get("name");
			List<Double> location = (List<Double>)hit.getSource().get("location");
			// 获取距离值,并保留两位小数点
			BigDecimal geoDis = new BigDecimal((Double) hit.getSortValues()[0]);
			Map<String, Object> hitMap = hit.getSource();
			// 在创建MAPPING的时候,属性名的不可为geoDistance。
			hitMap.put("geoDistance", geoDis.setScale(0, BigDecimal.ROUND_HALF_DOWN));
			System.out.println(name+"的坐标:"+location + "他距离于谦" + hit.getSource().get("geoDistance") + DistanceUnit.METERS.toString());
		}

	}
	public static void main(String[] args) throws IOException {
		Client client = new TransportClient().addTransportAddress(new InetSocketTransportAddress("127.0.0.1", 9300));
		String index = "es";
		String type = "people";
		//createIndex(index, type);
		//addIndexData100000(index, type);

		double lat = 39.929986;
		double lon = 116.395645;
		long start = System.currentTimeMillis();
		//query("郭", index, type);
		testGetNearbyPeople(client, index, type, lat, lon);
		long end = System.currentTimeMillis();
		System.out.println((end - start) + "毫秒");
		//client.close();// 1.5.2用完不用关闭
	}
}

查询结果:

于谦附近的人(69个),耗时(0.016秒):
郭德纲17413的坐标:[39.929999, 116.395658]他距离于谦2m
郭德纲79407的坐标:[39.930006, 116.395665]他距离于谦2m
郭德纲26009的坐标:[39.93003, 116.395689]他距离于谦5m
郭德纲90577的坐标:[39.930041, 116.3957]他距离于谦7m
郭德纲4479的坐标:[39.930049, 116.395708]他距离于谦8m
郭德纲59538的坐标:[39.930068, 116.395727]他距离于谦10m
郭德纲56225的坐标:[39.930072, 116.395731]他距离于谦10m
郭德纲78623的坐标:[39.930075, 116.395734]他距离于谦11m
郭德纲21402的坐标:[39.930092, 116.395751]他距离于谦13m
郭德纲98117的坐标:[39.930098, 116.395757]他距离于谦14m
郭德纲92957的坐标:[39.9301, 116.395759]他距离于谦14m
郭德纲75291的坐标:[39.930101, 116.39576]他距离于谦14m
郭德纲84154的坐标:[39.930121, 116.39578]他距离于谦16m
郭德纲73369的坐标:[39.93016, 116.395819]他距离于谦21m
郭德纲38979的坐标:[39.930174, 116.395833]他距离于谦23m
郭德纲78569的坐标:[39.930193, 116.395852]他距离于谦25m
郭德纲15100的坐标:[39.930207, 116.395866]他距离于谦27m
郭德纲3864的坐标:[39.930218, 116.395877]他距离于谦28m
郭德纲66276的坐标:[39.930237, 116.395896]他距离于谦30m
郭德纲90141的坐标:[39.930243, 116.395902]他距离于谦31m
郭德纲29377的坐标:[39.930249, 116.395908]他距离于谦32m
郭德纲54727的坐标:[39.930253, 116.395912]他距离于谦32m
郭德纲10456的坐标:[39.930292, 116.395951]他距离于谦37m
郭德纲48968的坐标:[39.930298, 116.395957]他距离于谦38m
郭德纲20625的坐标:[39.930305, 116.395964]他距离于谦39m
郭德纲58066的坐标:[39.930307, 116.395966]他距离于谦39m
郭德纲76596的坐标:[39.930308, 116.395967]他距离于谦39m
郭德纲73185的坐标:[39.930323, 116.395982]他距离于谦41m
郭德纲26093的坐标:[39.930331, 116.39599]他距离于谦42m
郭德纲76719的坐标:[39.930331, 116.39599]他距离于谦42m
郭德纲27200的坐标:[39.930337, 116.395996]他距离于谦43m
郭德纲48983的坐标:[39.930337, 116.395996]他距离于谦43m
郭德纲21808的坐标:[39.930356, 116.396015]他距离于谦45m
郭德纲70386的坐标:[39.930356, 116.396015]他距离于谦45m
郭德纲56140的坐标:[39.93036, 116.396019]他距离于谦45m
郭德纲19567的坐标:[39.930365, 116.396024]他距离于谦46m
郭德纲9499的坐标:[39.930366, 116.396025]他距离于谦46m
郭德纲11682的坐标:[39.930381, 116.39604]他距离于谦48m
郭德纲19372的坐标:[39.930382, 116.396041]他距离于谦48m
郭德纲12508的坐标:[39.930383, 116.396042]他距离于谦48m
郭德纲56554的坐标:[39.930385, 116.396044]他距离于谦48m
郭德纲79324的坐标:[39.930389, 116.396048]他距离于谦49m
郭德纲30910的坐标:[39.930394, 116.396053]他距离于谦50m
郭德纲45095的坐标:[39.930412, 116.396071]他距离于谦52m
郭德纲73533的坐标:[39.930422, 116.396081]他距离于谦53m
郭德纲46509的坐标:[39.930422, 116.396081]他距离于谦53m
郭德纲81262的坐标:[39.93044, 116.396099]他距离于谦55m
郭德纲30077的坐标:[39.930448, 116.396107]他距离于谦56m
郭德纲61049的坐标:[39.930456, 116.396115]他距离于谦57m
郭德纲16607的坐标:[39.930458, 116.396117]他距离于谦57m
郭德纲50464的坐标:[39.930467, 116.396126]他距离于谦58m
郭德纲7272的坐标:[39.930468, 116.396127]他距离于谦59m
郭德纲82133的坐标:[39.93047, 116.396129]他距离于谦59m
郭德纲46350的坐标:[39.930472, 116.396131]他距离于谦59m
郭德纲40185的坐标:[39.930502, 116.396161]他距离于谦63m
郭德纲28020的坐标:[39.930515, 116.396174]他距离于谦64m
郭德纲75873的坐标:[39.93052, 116.396179]他距离于谦65m
郭德纲83959的坐标:[39.930527, 116.396186]他距离于谦66m
郭德纲5175的坐标:[39.930529, 116.396188]他距离于谦66m
郭德纲15511的坐标:[39.930531, 116.39619]他距离于谦66m
郭德纲61721的坐标:[39.930535, 116.396194]他距离于谦67m
郭德纲54860的坐标:[39.930549, 116.396208]他距离于谦68m
郭德纲38391的坐标:[39.93055, 116.396209]他距离于谦69m
郭德纲5603的坐标:[39.930555, 116.396214]他距离于谦69m
郭德纲70588的坐标:[39.930579, 116.396238]他距离于谦72m
郭德纲12256的坐标:[39.930583, 116.396242]他距离于谦73m
郭德纲93219的坐标:[39.930598, 116.396257]他距离于谦74m
郭德纲80353的坐标:[39.930607, 116.396266]他距离于谦75m
郭德纲19737的坐标:[39.930617, 116.396276]他距离于谦77m
82毫秒

注: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秒左右,10万个基数查询82毫秒,非常快

时间: 2024-10-25 11:50:11

使用elasticsearch1.5.2实现查找附近的人的相关文章

查找附近的人。

这次和于大山写了个查找附近的人,功能是使用同一软件的人可以将地理位置信息上传到服务器,其他人可通过查找的功能将指定距离内的人的相关信息(包括地理位置信息)查找出来. 其实没什么技术含量,整个工程中最核心的地方就是用到了百度地图提供的lbs接口,通过这个接口访问百度地图提供的数据库,可以实现对表的增删改查等命令,也可以精确的计算gps之间的距离. 工程分为服务器与客户端,客户端可以上传GPS信息,服务器可以通过上传的信息对数据库的GPS进行更新与添加,客户端可以通过发送GPS定位信息让服务器返回附

查找附近的人-1

<?php  require_once('geohash.class.php'); $geo=new Geohash; $gps=array(); for($i=0;$i<=100;$i++){  $g=array((rand(1000000,1001000)/100000),(rand(2000000,2001000)/100000));     $gps[]=$g; } foreach ($gps as $k => $v) {  echo $encode=$geo->encod

PHP之路——geohash查找附近的人

<?php class location { public function getLat($number, $small, $big, $temp = 20){ $temp--; $average = ($big + $small) / 2; if ($temp == 0) { if ($average <= $number) { return '1'; } else { return '0'; } } if ($average <= $number) { return '1' . $

在家谱中查找关系远近

[问题描述] 同姓氏中国人见面常说的一句话是"我们五百年前可能是一家".从当前目录下的文件in.txt中读入一家谱,从标准输入读入两个人的名字(两人的名字肯定会在家谱中出现),编程查找判断这两个人相差几辈,若同辈,还要查找两个人共同的最近祖先以及与他(她)们的关系远近.假设输入的家谱中每人最多有两个孩子,例如下图是根据输入形成的一个简单家谱: 通过该家谱,可以看到wangliang.wangguoping和wangguoan都有两个孩子,wangtian.wangxiang和wangs

二分查找,查指定值、小于k的最大值,大于k的最大值

我们经常会用到二分查找 二分查找应该很多人都会写了,今天要写一个用二分查找找到小于k的最大值的时候看了很久不懂他设计的思路,后来想通了,记录一下. 所以这篇主要是讲 用二分查找找到小于k的最大值和大于k的最大值. 二分查找查找指定值 这个挺简单的,直接上代码吧 //获取值是k的位置,找不到则返回-1 public static int getK(int[] a, int k){ if(a.length == 0){ return -1; } int l = 0; int r = a.length

ObjectC----实现简单的通讯录(增删改查)

// Created By 郭仔 2015年04月09日21:27:50 经过两天的低迷,状态在慢慢的回归了,生活还要继续,人生还需奋斗! 祝:好人一生平安!!! ======================================================================== 题目描述: 1.创建AddressBook类. 1)使?用字典作为容器,字典的Key值为分组名(姓名?首字?母,?大写),value值为数组,数组 中存放联系?人(Person实例).(5分

LINQ To SQL 语法及实例大全

LINQ to SQL语句(1)之Where Where操作 适用场景:实现过滤,查询等功能. 说明:与SQL命令中的Where作用相似,都是起到范围限定也就是过滤作用的,而判断条件就是它后面所接的子句. Where操作包括3种形式,分别为简单形式.关系条件形式.First()形式.下面分别用实例举例下: 1.简单形式: 例如:使用where筛选在伦敦的客户 var q = from c in db.Customers where c.City == "London" select c

微信公开课(北京站)速记 微信、微信支付、O2O的定义与关联

本文为4月29日微信公开课(北京站)微信产品部演讲全文速记,讲述了微信官方对微信.微信支付.O2O的定义与关联等问题的看法与观点. 作者:微信产品部 刘涵涛 吴毅 去年夏天有一个全民打飞机的盛况,这实际上是微信的第一款社交类手游,它通过微信大平台的海量用户,一上线之后就有过亿的用户,甚至在淘宝上面都有代客打游戏的服务,通过这个游戏大家突然想到,微信以前是一个沟通工具,微信竟然也可以玩儿,甚至出现了这样一个段子,如果要自己的排行榜排在前面,最简单的方法是把玩这个游戏的好朋友全部踢掉. 微信红包大家

PAT 团体程序设计天梯赛-练习集 题解(凑零钱,堆栈,社交集群)

开始准备cccc(cry)天梯赛了,第一周训练题,把官网挂出的训练题刷完了,对pat有了一点点的熟悉感. L1-1  就不说了... L1-2 打印沙漏 一个变量保存空格数,一个变量保存沙漏符号数,打印就行了,但这题话说wrong好几次啊,坑点是沙漏符号后面不打印空格,orz... <span style="font-size:14px;">#include<iostream> #include<stdio.h> #include<math.h