O artigo anterior apresentou que o Elasticsearch usa o repositório e o ElasticsearchTemplate para criar condições complexas de consulta e apresenta brevemente a função do Elasticsearch para usar a localização geográfica.
Neste artigo, vamos dar uma olhada na função de usar o Elasticsearch para preencher as grandes consultas de dados próximas e procurar dados dentro do intervalo de n-meter.
Prepare o meio ambiente
O teste nativo usa a versão mais recente do Elasticsearch versão 5.5.1, Springboot1.5.4 e Spring-Data-ELASTICSearch2.1.4.
Crie um novo projeto de troca, verifique o Elasticsearch e a Web.
O arquivo POM é o seguinte
<? xml versão = "1.0" coding = "utf-8"?> <Projeto xmlns = "http://maven.apache.org/pom/4.0.0" xmlns: xsi = "http://www.ww3.org/2001/xmlschaMance 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> <Versão> 0.0.1-SNAPSHOT </Version> <batyaging> jar </acheging> <name> ElasticSearch </name> <cription> Projeto Demo para boot de primavera </cription> </iromer> <puerpid> org.springframework.boot </frupid> <stifactId> spring-boot-starter-Parent </artiftIf Lookup Parent de Repository-> </axer> <Properts> <Project.build.sourceEncoding> utf-8 </project.build.sourcencoding> <projeto.reporting.outputEncoding> utf-8 </project.reporting.outputoding> <Java.version> 1.8 </project.reporting.outputoding> <Depencency> <PuerpId> org.springframework.boot </frugid> <stifactId> primavera-boot-starter-data-elásticaarch </stutifactId> </dependency> <pendência> <purpyid> org.springframework.boot </grupo> <Tifactid> <purget-brot Stern <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> <flugins> <lugin> <voundid> org.springframework.boot </frugiD> <stifactId> spring-boot-maven-plugin </stutifactId> </plugin> </flugins> </fruct> </project>
Crie uma nova pessoa de classe modelo
pacote com.tianyalei.elticsearch.model; importar org.springframework.data.annotation.id; importar org.springframework.data.ellasticsearch.annotações.document; importar org.springframework.data.ellasticsearch.annotações.geopointfield; importar java.io.serializable; /** nome de string privado; telefone de corda privada; / ** * Localização geográfica Latitude e longitude * Latitude, Lon Longitude "40.715, -74.011" * Se você usar uma matriz, o oposto é verdadeiro [-73.983, 40.719] */ @geopointfield private String endereço; public int getId () {return id; } public void setId (int id) {this.id = id; } public string getName () {return name; } public void setName (nome da string) {this.name = name; } public string getphone () {return telefone; } public void setPhone (string telefone) {this.phone = telefone; } public string getAddress () {retornar endereço; } public void setAddress (endereço da string) {this.address = endereço; }} Eu uso o campo de endereço para representar a posição de latitude e longitude. Observe que o uso de String [] e String são diferentes ao denotar latitude e longitude, consulte os comentários.
importação com.tianyalei.elticsearch.model.person; importar org.springframework.data.elasticsearch.repository.elasticsearchRepository; interface pública PersonRepository estende ElasticsearchRepository <Pessoa, Integer> {} Dê uma olhada na classe de serviço e conclua a função de inserir dados de teste. Eu coloquei a função de consulta no controlador. Por uma questão de conveniência, deve ser colocado no serviço normalmente.
pacote com.tianyalei.elticsearch.service; importação com.tianyalei.elticsearch.model.person; importar com.tianyalei.elticsearch.repository.personRepository; importar org.springframework.beans.factory.annotation.autowired; importar org.springframework.data.ellasticsearch.core.elticsearchTemplate; importar org.springframework.data.ellasticsearch.core.query.indexQuery; importar org.springframework.tereotype.service; importar java.util.arraylist; importar java.util.list; @Service Public Class PersonService {@AUTOWIRED PERSONREPOSIENTY PERSONRepository; @Autowired ElasticsearchTemplate ElasticsearchTemplate; String final estática privada Person_index_name = "ELASTIC_SEARCH_PROJECT"; String final estática privada Person_index_type = "Person"; public pessoa add (pessoa pessoa) {return PersonRepository.Save (pessoa); } public void bulkindex (list <Soper> PERSONLIST) {int contat = 0; tente {if (! ElasticsearchTemplate.indexists (Person_index_Name)) {ElasticsearchTemplate.CreateIndex (Person_index_type); } List <indexQuery> consultas = new ArrayList <> (); para (pessoa da pessoa: PersonList) {indexQuery IndexQuery = new IndexQuery (); indexQuery.setId (PERSON.GETID () + ""); indexQuery.setObject (Person); indexQuery.setIndexName (PERSON_INDEX_NAME); indexQuery.setType (PERSON_INDEX_TYPE); // As etapas acima também podem ser usadas para construir usando indexQueryBuilder // indexQuery Index = new IndexQueryBuilder (). Withid (PERSON.GETID () + "") .WithObject (Person) .build (); Queries.add (indexQuery); if (contador % 500 == 0) {ElasticsearchTemplate.bulkindex (consultas); Queries.clear (); System.out.println ("contador de bulkindex:" + contador); } contador ++; } if (Queries.size ()> 0) {ElasticsearchTemplate.bulkindex (consultas); } System.out.println ("Bulkindex concluído."); } catch (Exceção e) {System.out.println ("IndexerService.bulkindex e;" + e.getMessage ()); jogar e; }}}Preste atenção ao método Bulkindex, usado para inserir dados em lote. A massa também é o método de inserção de dados em lote recomendados oficialmente pelo ES. Aqui, o volume é inserido a cada 500 múltiplos inteiros.
pacote com.tianyalei.elticsearch.controller; importação com.tianyalei.elticsearch.model.person; importação com.tianyalei.elticsearch.service.personservice; importação org.elticsearch.common.unit.distanceUnit; importar org.elticsarch.index.query.geodistanceQueryBuilder; importar org.elticsearch.index.Query.QueryBuilders; importar org.elticsearch.search.sort.geodistancesortbuilder; importar org.elticsearch.search.sort.sortbuilders; importar org.elticsearch.search.sort.sortorder; importar org.springframework.beans.factory.annotation.autowired; importar org.springframework.data.domain.pagerequest; importar org.springframework.data.domain.pageable; importar org.springframework.data.ellasticsearch.core.elticsearchTemplate; importar org.springframework.data.elticsearch.core.query.nativeearchQueryBuilder; importar org.springframework.data.ellasticsearch.core.query.searchQuery; importar org.springframework.web.bind.annotation.getMapping; importar org.springframework.web.bind.annotation.restcontroller; importar java.text.decimalformat; importar java.util.arraylist; importar java.util.list; importar java.util.random; @RestController Public Class PessoController {@AUTOWIRED PERSONSERVICE PERSONSERVICE; @Autowired ElasticsearchTemplate ElasticsearchTemplate; @GetMapping ("/add") public Object add () {Double Lat = 39.929986; Lon duplo = 116.395645; List <Pesso> PersonList = new ArrayList <> (900000); for (int i = 100000; i <1000000; i ++) {duplo max = 0,00001; duplo min = 0,000001; Aleatório aleatório = novo aleatório (); duplo 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); Duplo dlon = duplo.valueof (lons); Duplo dlat = duplo.valueof (lats); Pessoa pessoa = nova pessoa (); pessoa.setId (i); pessoa.SetName ("nome" + i); pessoa.Setphone ("Tel" + I); pessoa.setAddress (dlat + "," + dlon); PERSOLLIST.ADD (Pessoa); } PersOnservice.bulkindex (PersonList); // SearchQuery SearchQuery = new NativearchQueryBuilder (). WithQuery (QueryBuilders.QueryStringQuery ("Boot ou livro de primavera"). Build (); // List <Artigo> Artigos = ELAS, TicSearchTemplate.QueryForList (SE, Archquery, Article.class); // para (Artigo: Artigos) {// System.out.println (artigo.tostring ()); //} retornar "Adicionar dados"; } /*** geo_distance: Encontre o local dentro de um determinado intervalo de um determinado ponto central geo_bounding_box: encontre o local dentro de uma área de retângulo Geo_Distance_Range: encontre o local entre Min e Max Geo_polygon: encontre o local dentro de um polígono. A classificação pode ser usada para classificar */ @getMapping ("/ Query") public Object Query () {Double Lat = 39.929986; Lon duplo = 116.395645; Long nowtime = System.currenttimemillis (); // Consulta dentro de uma certa latitude e longitude dentro de 100 metros. GeodistanceQueryBuilder Builder = QueryBuilders.geodistanceQuery ("endereço"). Point (Lat, Lon) .Distance (100, DistanceUnit.Meters); Geodistancesortbuilder Sortbuilder = Sortbuilders.geodistancesort ("endereço") .point (Lat, LON) .Unit (a DistaNUnit.Meters) .Order (Sortorder.asc); Pagável pagável = new PageRequest (0, 50); NativearchQueryBuilder Builder1 = New NativearchQueryBuilder (). WithFilter (Builder) .WithSort (Sortbuilder) .WithPageable (pagável); SearchQuery SearchQuery = Builder1.Build (); // queryforlist é paginado por padrão e o queryforpage é usado. O padrão é 10 list <Sople> PERSONLIST = ElasticsearchTemplate.QueryForList (SearchQuery, Person.class); System.out.println ("TimecOnsuming:" + (System.currenttimemillis () - NowTime)); devolver personlist; }} Olhando para a classe do controlador, no método Add, inserimos 900.000 dados de teste e geramos aleatoriamente endereços de latitude e longitude.
No método de consulta, construímos uma condição de consulta a 100 metros da consulta, classificada de acordo com a distância e paga 50 itens por página. Se o pagável não for especificado, o consultor do estemplate é 10 por padrão, o que pode ser visto através do código -fonte.
Inicie o projeto, execute adicione primeiro e aguarde que milhões de dados sejam inseridos, por cerca de algumas dezenas de segundos.
Em seguida, execute a consulta e veja os resultados.
A primeira consulta levou mais de 300ms e o tempo caiu significativamente após a consulta novamente, para cerca de 30ms, porque o ES foi automaticamente armazenado em cache na memória.
Pode -se observar que o ES completa a consulta da localização geográfica muito rapidamente. Adequado para perguntas como pessoas próximas e consulta de escopo.
PostScript: Em uso posterior, na versão 2.3 Elasticsearch, o geótipo não pode ser indexado de acordo com o método de escrita acima. A entrada ES é de corda em vez da marcada geofilada. Aqui está um registro da solução, modifique o tipo de string no geopoint e está embalado em org.springframework.data.elticticsearch.core.geo.geopoint. Então você precisa chamar explicitamente o método de mapeamento ao criar o índice para mapear corretamente o Geofield.
do seguinte modo
if (! ElasticsearchTemplate.indexists ("ABC")) {ElasticsearchTemplate.CreateIndex ("ABC"); ElasticsearchTemplate.putMapping (Person.class); }O exposto acima é todo o conteúdo deste artigo. Espero que seja útil para o aprendizado de todos e espero que todos apoiem mais o wulin.com.