使用elasticsearch1.5.2實現查找附近的人

POM: java

<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>



Entity:
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;
    }
}



Test類:
package com.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結果就行了,還有 apache


.point(lon, lat)

  必須經度在前,緯度在後,否則查詢爲空,跟一朋友聊說這個多是個bug json

  另外查詢速度太慢,應該哪一個地方配置的問題,通過試驗,原來建立client消耗了1秒左右,10萬個基數查詢82毫秒,很是快 app

相關文章
相關標籤/搜索