最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

java 使用ElasticSearch完成百萬(wàn)級(jí)數(shù)據(jù)查詢附近的人功能

 更新時(shí)間:2018年01月13日 16:45:42   作者:天涯淚小武  
本篇文章主要介紹了java 使用ElasticSearch完成百萬(wàn)級(jí)數(shù)據(jù)查詢附近的人功能,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧

上一篇文章介紹了ElasticSearch使用Repository和ElasticSearchTemplate完成構(gòu)建復(fù)雜查詢條件,簡(jiǎn)單介紹了ElasticSearch使用地理位置的功能。

這一篇我們來(lái)看一下使用ElasticSearch完成大數(shù)據(jù)量查詢附近的人功能,搜索N米范圍的內(nèi)的數(shù)據(jù)。

準(zhǔn)備環(huán)境

本機(jī)測(cè)試使用了ElasticSearch最新版5.5.1,SpringBoot1.5.4,spring-data-ElasticSearch2.1.4.

新建Springboot項(xiàng)目,勾選ElasticSearch和web。

pom文件如下

<?xml version="1.0" encoding="UTF-8"?> 
<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.tianyalei</groupId> 
  <artifactId>elasticsearch</artifactId> 
  <version>0.0.1-SNAPSHOT</version> 
  <packaging>jar</packaging> 
 
  <name>elasticsearch</name> 
  <description>Demo project for Spring Boot</description> 
 
  <parent> 
    <groupId>org.springframework.boot</groupId> 
    <artifactId>spring-boot-starter-parent</artifactId> 
    <version>1.5.4.RELEASE</version> 
    <relativePath/> <!-- lookup parent from repository --> 
  </parent> 
 
  <properties> 
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> 
    <java.version>1.8</java.version> 
  </properties> 
 
  <dependencies> 
    <dependency> 
      <groupId>org.springframework.boot</groupId> 
      <artifactId>spring-boot-starter-data-elasticsearch</artifactId> 
    </dependency> 
    <dependency> 
      <groupId>org.springframework.boot</groupId> 
      <artifactId>spring-boot-starter-web</artifactId> 
    </dependency> 
 
    <dependency> 
      <groupId>org.springframework.boot</groupId> 
      <artifactId>spring-boot-starter-test</artifactId> 
      <scope>test</scope> 
    </dependency> 
    <dependency> 
      <groupId>com.sun.jna</groupId> 
      <artifactId>jna</artifactId> 
      <version>3.0.9</version> 
    </dependency> 
  </dependencies> 
 
  <build> 
    <plugins> 
      <plugin> 
        <groupId>org.springframework.boot</groupId> 
        <artifactId>spring-boot-maven-plugin</artifactId> 
      </plugin> 
    </plugins> 
  </build>  
</project> 

新建model類Person

package com.tianyalei.elasticsearch.model;  
import org.springframework.data.annotation.Id; 
import org.springframework.data.elasticsearch.annotations.Document; 
import org.springframework.data.elasticsearch.annotations.GeoPointField; 
 
import java.io.Serializable; 
 
/** 
 * model類 
 */ 
@Document(indexName="elastic_search_project",type="person",indexStoreType="fs",shards=5,replicas=1,refreshInterval="-1") 
public class Person implements Serializable { 
  @Id 
  private int id; 
 
  private String name; 
 
  private String phone; 
 
  /** 
   * 地理位置經(jīng)緯度 
   * lat緯度,lon經(jīng)度 "40.715,-74.011" 
   * 如果用數(shù)組則相反[-73.983, 40.719] 
   */ 
  @GeoPointField 
  private String address; 
 
  public int getId() { 
    return id; 
  } 
 
  public void setId(int id) { 
    this.id = id; 
  } 
 
  public String getName() { 
    return name; 
  } 
 
  public void setName(String name) { 
    this.name = name; 
  } 
 
  public String getPhone() { 
    return phone; 
  } 
 
  public void setPhone(String phone) { 
    this.phone = phone; 
  } 
 
  public String getAddress() { 
    return address; 
  } 
 
  public void setAddress(String address) { 
    this.address = address; 
  } 
} 

我用address字段表示經(jīng)緯度位置。注意,使用String[]和String分別來(lái)表示經(jīng)緯度時(shí)是不同的,見(jiàn)注釋。

import com.tianyalei.elasticsearch.model.Person; 
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;  
public interface PersonRepository extends ElasticsearchRepository<Person, Integer> { 
 
} 

看一下Service類,完成插入測(cè)試數(shù)據(jù)的功能,查詢的功能我放在Controller里了,為了方便查看,正常是應(yīng)該放在Service里

package com.tianyalei.elasticsearch.service;  
import com.tianyalei.elasticsearch.model.Person; 
import com.tianyalei.elasticsearch.repository.PersonRepository; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate; 
import org.springframework.data.elasticsearch.core.query.IndexQuery; 
import org.springframework.stereotype.Service; 
import java.util.ArrayList; 
import java.util.List; 
 
@Service 
public class PersonService { 
  @Autowired 
  PersonRepository personRepository; 
  @Autowired 
  ElasticsearchTemplate elasticsearchTemplate; 
 
  private static final String PERSON_INDEX_NAME = "elastic_search_project"; 
  private static final String PERSON_INDEX_TYPE = "person"; 
 
  public Person add(Person person) { 
    return personRepository.save(person); 
  } 
 
  public void bulkIndex(List<Person> personList) { 
    int counter = 0; 
    try { 
      if (!elasticsearchTemplate.indexExists(PERSON_INDEX_NAME)) { 
        elasticsearchTemplate.createIndex(PERSON_INDEX_TYPE); 
      } 
      List<IndexQuery> queries = new ArrayList<>(); 
      for (Person person : personList) { 
        IndexQuery indexQuery = new IndexQuery(); 
        indexQuery.setId(person.getId() + ""); 
        indexQuery.setObject(person); 
        indexQuery.setIndexName(PERSON_INDEX_NAME); 
        indexQuery.setType(PERSON_INDEX_TYPE); 
 
        //上面的那幾步也可以使用IndexQueryBuilder來(lái)構(gòu)建 
        //IndexQuery index = new IndexQueryBuilder().withId(person.getId() + "").withObject(person).build(); 
 
        queries.add(indexQuery); 
        if (counter % 500 == 0) { 
          elasticsearchTemplate.bulkIndex(queries); 
          queries.clear(); 
          System.out.println("bulkIndex counter : " + counter); 
        } 
        counter++; 
      } 
      if (queries.size() > 0) { 
        elasticsearchTemplate.bulkIndex(queries); 
      } 
      System.out.println("bulkIndex completed."); 
    } catch (Exception e) { 
      System.out.println("IndexerService.bulkIndex e;" + e.getMessage()); 
      throw e; 
    } 
  } 
} 

注意看bulkIndex方法,這個(gè)是批量插入數(shù)據(jù)用的,bulk也是ES官方推薦使用的批量插入數(shù)據(jù)的方法。這里是每逢500的整數(shù)倍就bulk插入一次。

package com.tianyalei.elasticsearch.controller;  
import com.tianyalei.elasticsearch.model.Person; 
import com.tianyalei.elasticsearch.service.PersonService; 
import org.elasticsearch.common.unit.DistanceUnit; 
import org.elasticsearch.index.query.GeoDistanceQueryBuilder; 
import org.elasticsearch.index.query.QueryBuilders; 
import org.elasticsearch.search.sort.GeoDistanceSortBuilder; 
import org.elasticsearch.search.sort.SortBuilders; 
import org.elasticsearch.search.sort.SortOrder; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.data.domain.PageRequest; 
import org.springframework.data.domain.Pageable; 
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate; 
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder; 
import org.springframework.data.elasticsearch.core.query.SearchQuery; 
import org.springframework.web.bind.annotation.GetMapping; 
import org.springframework.web.bind.annotation.RestController; 
import java.text.DecimalFormat; 
import java.util.ArrayList; 
import java.util.List; 
import java.util.Random; 
 
@RestController 
public class PersonController { 
  @Autowired 
  PersonService personService; 
  @Autowired 
  ElasticsearchTemplate elasticsearchTemplate; 
 
  @GetMapping("/add") 
  public Object add() { 
    double lat = 39.929986; 
    double lon = 116.395645; 
    List<Person> personList = new ArrayList<>(900000); 
    for (int i = 100000; i < 1000000; 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);  
      Person person = new Person(); 
      person.setId(i); 
      person.setName("名字" + i); 
      person.setPhone("電話" + i); 
      person.setAddress(dlat + "," + dlon); 
      personList.add(person); 
    } 
    personService.bulkIndex(personList); 
 
//    SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(QueryBuilders.queryStringQuery("spring boot OR 書籍")).build(); 
//    List<Article> articles = elas、ticsearchTemplate.queryForList(se、archQuery, Article.class); 
//    for (Article article : articles) { 
//      System.out.println(article.toString()); 
//    } 
 
    return "添加數(shù)據(jù)"; 
  } 
 
  /** 
   * 
   geo_distance: 查找距離某個(gè)中心點(diǎn)距離在一定范圍內(nèi)的位置 
   geo_bounding_box: 查找某個(gè)長(zhǎng)方形區(qū)域內(nèi)的位置 
   geo_distance_range: 查找距離某個(gè)中心的距離在min和max之間的位置 
   geo_polygon: 查找位于多邊形內(nèi)的地點(diǎn)。 
   sort可以用來(lái)排序 
   */ 
  @GetMapping("/query") 
  public Object query() { 
    double lat = 39.929986; 
    double lon = 116.395645;  
    Long nowTime = System.currentTimeMillis(); 
    //查詢某經(jīng)緯度100米范圍內(nèi) 
    GeoDistanceQueryBuilder builder = QueryBuilders.geoDistanceQuery("address").point(lat, lon) 
        .distance(100, DistanceUnit.METERS); 
 
    GeoDistanceSortBuilder sortBuilder = SortBuilders.geoDistanceSort("address") 
        .point(lat, lon) 
        .unit(DistanceUnit.METERS) 
        .order(SortOrder.ASC); 
 
    Pageable pageable = new PageRequest(0, 50); 
    NativeSearchQueryBuilder builder1 = new NativeSearchQueryBuilder().withFilter(builder).withSort(sortBuilder).withPageable(pageable); 
    SearchQuery searchQuery = builder1.build();  
    //queryForList默認(rèn)是分頁(yè),走的是queryForPage,默認(rèn)10個(gè) 
    List<Person> personList = elasticsearchTemplate.queryForList(searchQuery, Person.class);  
    System.out.println("耗時(shí):" + (System.currentTimeMillis() - nowTime)); 
    return personList; 
  } 
} 

看Controller類,在add方法中,我們插入90萬(wàn)條測(cè)試數(shù)據(jù),隨機(jī)產(chǎn)生不同的經(jīng)緯度地址。

在查詢方法中,我們構(gòu)建了一個(gè)查詢100米范圍內(nèi)、按照距離遠(yuǎn)近排序,分頁(yè)每頁(yè)50條的查詢條件。如果不指明Pageable的話,ESTemplate的queryForList默認(rèn)是10條,通過(guò)源碼可以看到。

啟動(dòng)項(xiàng)目,先執(zhí)行add,等待百萬(wàn)數(shù)據(jù)插入,大概幾十秒。

然后執(zhí)行查詢,看一下結(jié)果。

第一次查詢花費(fèi)300多ms,再次查詢后時(shí)間就大幅下降,到30ms左右,因?yàn)镋S已經(jīng)自動(dòng)緩存到內(nèi)存了。

可見(jiàn),ES完成地理位置的查詢還是非常快的。適用于查詢附近的人、范圍查詢之類的功能。

后記,在后來(lái)的使用中,Elasticsearch2.3版本時(shí),按上面的寫法出現(xiàn)了geo類型無(wú)法索引的情況,進(jìn)入es的為String,而不是標(biāo)注的geofiled。在此記錄一下解決方法,將String類型修改為GeoPoint,且是org.springframework.data.elasticsearch.core.geo.GeoPoint包下的。然后需要在創(chuàng)建index時(shí),顯式調(diào)用一下mapping方法,才能正確的映射為geofield。

如下

if (!elasticsearchTemplate.indexExists("abc")) { 
      elasticsearchTemplate.createIndex("abc"); 
      elasticsearchTemplate.putMapping(Person.class); 
    } 

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 全面了解Java中的內(nèi)部類和匿名類

    全面了解Java中的內(nèi)部類和匿名類

    下面小編就為大家?guī)?lái)一篇全面了解Java中的內(nèi)部類和匿名類。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-07-07
  • 詳解JAVA調(diào)用WCF服務(wù)的示例代碼

    詳解JAVA調(diào)用WCF服務(wù)的示例代碼

    這篇文章主要介紹了詳解JAVA調(diào)用WCF服務(wù)的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-09-09
  • 最簡(jiǎn)單的java生成word文檔方法

    最簡(jiǎn)單的java生成word文檔方法

    這篇文章主要介紹了java生成word文檔最簡(jiǎn)單的方法,首先說(shuō)明,使用該方法時(shí),盡量不要使用wps新建word文檔,經(jīng)測(cè)試,手機(jī)不能兼容,出現(xiàn)很多格式問(wèn)題,office則手機(jī)可以很好的兼容,所以,本文以office做教程
    2021-08-08
  • JVM致命錯(cuò)誤日志詳解(最新推薦)

    JVM致命錯(cuò)誤日志詳解(最新推薦)

    這篇文章主要介紹了JVM致命錯(cuò)誤日志詳解,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-06-06
  • JVM指令的使用深入詳解

    JVM指令的使用深入詳解

    這篇文章主要給大家介紹了關(guān)于JVM指令使用的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-01-01
  • IDEA上實(shí)現(xiàn)JDBC編程的方法步驟

    IDEA上實(shí)現(xiàn)JDBC編程的方法步驟

    本文主要介紹了IDEA上實(shí)現(xiàn)JDBC編程的方法步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06
  • springboot代碼,注解配置獲取yml,properties文件的map即鍵值對(duì)

    springboot代碼,注解配置獲取yml,properties文件的map即鍵值對(duì)

    這篇文章主要介紹了springboot代碼,注解配置獲取yml,properties文件的map即鍵值對(duì),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • 如何使用idea里面自帶的翻譯插件

    如何使用idea里面自帶的翻譯插件

    這篇文章主要介紹了idea里面自帶的翻譯插件,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-11-11
  • selenium-java實(shí)現(xiàn)自動(dòng)登錄跳轉(zhuǎn)頁(yè)面方式

    selenium-java實(shí)現(xiàn)自動(dòng)登錄跳轉(zhuǎn)頁(yè)面方式

    利用Selenium和Java語(yǔ)言可以編寫一個(gè)腳本自動(dòng)刷新網(wǎng)頁(yè),首先,需要確保Google瀏覽器和Chrome-Driver驅(qū)動(dòng)的版本一致,通過(guò)指定網(wǎng)站下載對(duì)應(yīng)版本的瀏覽器和驅(qū)動(dòng),在Maven項(xiàng)目中添加依賴,編寫腳本實(shí)現(xiàn)網(wǎng)頁(yè)的自動(dòng)刷新,此方法適用于需要頻繁刷新網(wǎng)頁(yè)的場(chǎng)景,簡(jiǎn)化了操作,提高了效率
    2024-11-11
  • SpringBoot異步處理的四種實(shí)現(xiàn)方式

    SpringBoot異步處理的四種實(shí)現(xiàn)方式

    本篇文章我們以SpringBoot中異步的使用(包括:異步調(diào)用和異步方法兩個(gè)維度)來(lái)進(jìn)行講解,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-05-05

最新評(píng)論

尤溪县| 石景山区| 东辽县| 长泰县| 蕲春县| 长兴县| 台东县| 苏尼特左旗| 新宁县| 侯马市| 中卫市| 广汉市| 上犹县| 嘉峪关市| 大渡口区| 盖州市| 肇源县| 清涧县| 西平县| 长岭县| 九龙县| 安乡县| 聂拉木县| 迁西县| 舒兰市| 宾阳县| 广宗县| 黄山市| 公主岭市| 樟树市| 北碚区| 九寨沟县| 元朗区| 南投市| 循化| 桓台县| 化德县| 双江| 桐乡市| 肃南| 防城港市|