El artículo anterior presentó que Elasticsearch utiliza el repositorio y elasticsearchtemplate para crear condiciones de consulta complejas, y presenta brevemente la función de ElasticSearch para usar la ubicación geográfica.
En este artículo, echemos un vistazo a la función de usar Elasticsearch para completar la gran consulta de datos cercanas y buscar datos dentro del rango de N-Meter.
Preparar el medio ambiente
La prueba nativa utiliza la última versión de Elasticsearch 5.5.1, SpringBoot1.5.4 y Spring-Data-Elasticsearch2.1.4.
Cree un nuevo proyecto SpringBoot, consulte Elasticsearch y Web.
El archivo POM es el siguiente
<? xml versión = "1.0" encoding = "utf-8"?> <Project xmlns = "http://maven.apache.org/pom/4.0.0" xmlns: xsi = "http://www.w3.org/2001/xmlschemainstance" 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> <grupo> com.tianyalei </groupid> <artifactid> <versión> 0.0.1-snapshot </versewer> <packaging> jar </packaging> <name> elasticsearch </name> <scuidt> Proyecto de demostración para el arranque de primavera </scription> <-parent> <proupid> org.springframework.boot </groupid> <artifactID> spring-boot-sharter-parent </artifactid> <verSersion> < <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> <MoupRoD> org.springframework.boot </groupid> <artifactid> spring-boot-starter-test </artifactid> <cope> test </scope> </pendency> <epardency> <proupid> com.sun.jna </groupid> <artifactid> jna </artifactid> <versión> 3.0.9 <//versión> </versión> </Versión> </dependientes <glugins> <glugin> <uproupid> org.springframework.boot </groupid> <artifactid> spring-boot-maven-plugin </arfactid> </glugin> </glugins> </build> </jection>
Crear una nueva persona de clase modelo
paquete com.tianyalei.elasticsearch.model; importar org.springframework.data.annotation.id; importar org.springframework.data.elasticsearch.annotations.document; importar org.springframework.data.elasticsearch.annotations.geOpointfield; import java.io.serializable; / *** clase de modelo*/ @Document (indexname = "elastic_search_project", type = "persona", indexStoreType = "fs", fragmentos = 5, replicas = 1, refreshinterval = "-1") PUBLIC CLASS PERPELES nombre de cadena privada; Teléfono de cadena privada; / ** * Latitud y longitud de ubicación geográfica * Latitud, Lon Longitud "40.715, -74.011" * Si usa una matriz, lo contrario es verdadero [-73.983, 40.719] */ @GeOpointfield Dirección de cadena privada; public int getId () {return id; } public void setid (int id) {this.id = id; } public String getName () {nombre de retorno; } public void setName (nombre de cadena) {this.name = name; } public String getPhone () {return Phone; } public void setPhone (teléfono de cadena) {this.phone = phone; } public String getAddress () {Dirección de retorno; } public void setAddress (dirección de cadena) {this.address = dirección; }} Utilizo el campo de dirección para representar la posición de latitud y longitud. Tenga en cuenta que usar cadena [] y cadena son diferentes cuando denotan latitud y longitud, vea los comentarios.
import com.tianyalei.elasticsearch.model.person; importar org.springframework.data.elasticsearch.repository.elasticsearchRepository; interfaz pública PersonRepository extiende ElasticSearchRepository <Person, Integer> {} Eche un vistazo a la clase de servicio y complete la función de insertar datos de prueba. Puse la función de consulta en el controlador. En aras de la conveniencia, se debe colocar en el servicio normalmente.
paquete com.tianyalei.elasticsearch.service; import com.tianyalei.elasticsearch.model.person; import com.tianyalei.elasticsearch.repository.personRepository; importar org.springframework.beans.factory.annotation.aUtowired; importar org.springframework.data.elasticsearch.core.elasticsearchtemplate; importar org.springframework.data.elasticsearch.core.query.Indexquery; importar org.springframework.stereotype.service; import java.util.arrayList; import java.util.list; @Service Public Class Personservice {@aUtowired PersonRepository PersonRepository; @AUTOWIREDEDIRDEDECHTemplate ElasticsearchTemplate; static final static private Person_index_name = "elastic_search_project"; Private static final cadena persona_index_type = "persona"; Persona pública add (persona persona) {return PersonRepository.save (persona); } public void bulkindex (List <Oll> Personlist) {int contador = 0; Pruebe {if (! ElasticSearchTemplate.IndexExists (Person_index_Name)) {ElasticsearchTemplate.CreateIndex (Person_index_Type); } List <DaxQuery> Queries = new ArrayList <> (); para (persona persona: persona list) {indexQuery indexQuery = new IndexQuery (); indexQuery.setId (persona.getid () + ""); indexQuery.setObject (persona); indexQuery.setIndexName (persona_index_name); indexQuery.settype (persona_index_type); // Los pasos anteriores también se pueden usar para construir usando indexQueryBuilder // indexQuery index = new IndexQueryBuilder (). Withid (Person.getID () + "") .WithObject (persona) .Build (); QUERIES.Add (indexQuery); if (contador % 500 == 0) {elasticsearchtemplate.bulkindex (consultas); QUERIES.CLEAR (); System.out.println ("contador bulkindex:" + contador); } contador ++; } if (Queries.size ()> 0) {elasticsearchtemplate.bulkindex (consulta); } System.out.println ("bulkindex completado"); } catch (Exception e) {System.out.println ("indexerservice.bulkindex e;" + e.getMessage ()); tirar E; }}}Preste atención al método Bulkindex, que se utiliza para insertar datos por lotes. La masa también es el método de los datos de inserción por lotes recomendados oficialmente por ES. Aquí, el volumen se inserta cada 500 múltiplos enteros.
paquete com.tianyalei.elasticsearch.controller; import com.tianyalei.elasticsearch.model.person; import com.tianyalei.elasticsearch.service.personservice; importar org.elasticsearch.common.unit.distanceUnit; importar org.elasticsearch.index.Query.GeodistancequeryBuilder; importar org.elasticsearch.index.query.QueryBuilders; importar org.elasticsearch.search.sort.geodistancesortBuilder; importar org.elasticsearch.search.sort.sortbuilders; importar org.elasticsearch.search.sort.sortorder; importar org.springframework.beans.factory.annotation.aUtowired; importar org.springframework.data.domain.pagerequest; importar org.springframework.data.domain.pagable; importar org.springframework.data.elasticsearch.core.elasticsearchtemplate; importar org.springframework.data.elasticsearch.core.query.natesearchqueryBuilder; importar org.springframework.data.elasticsearch.core.query.searchQuery; importar org.springframework.web.bind.annotation.getMapping; importar 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; @AUTOWIREDEDIRDEDECHTemplate ElasticsearchTemplate; @GetMapping ("/add") Public Object add () {Double Lat = 39.929986; doble lon = 116.395645; Lista <Oll> PersonList = New ArrayList <> (900000); para (int i = 100000; i <1000000; i ++) {double max = 0.00001; doble min = 0.000001; Aleatorio aleatorio = new Random (); doble s = random.nextDouble () % (max - min + 1) + max; Decimalformat df = new DecimalFormat ("###### 0.000000"); // System.out.println (s); String Lons = Df.Format (S + Lon); Cadena lats = df.format (s + lat); Doble dlon = double.ValueOf (Lons); Doble dlat = double.valueOf (lats); Persona persona = nueva persona (); persona.setid (i); persona.setName ("nombre" + i); Person.setPhone ("Tel" + I); persona.setaddress (dlat + "," + dlon); Personlist.Add (persona); } Personservice.BulkIndex (Personlist); // SearchQuery SearchQuery = New NatesearchQueryBuilder (). WithQuery (QueryBuilders.QueryStringQuery ("Boot o libro de primavera")). Build (); // List <Artículo> Artículos = elas, ticSearchTemplate.QueryForlist (SE, Archquery, Artículo.class); // para (artículo Artículo: Artículos) {// System.out.println (artículo.ToString ()); //} return "Agregar datos"; } /*** Geo_Distance: encuentre la ubicación dentro de un cierto rango de cierto punto central Geo_Bounding_Box: Encuentre la ubicación dentro de un área rectangular geo_distance_range: Encuentre la ubicación entre min y max geo_polygon: encuentre la ubicación dentro de un polígono. La ordenación se puede usar para ordenar */ @getmapping ("/ QUERY") Public Object Query () {Double Lat = 39.929986; doble lon = 116.395645; Long ahora = System.CurrentTimemillis (); // Consulta dentro de una cierta latitud y longitud dentro de los 100 metros. GeodistanceQueryBuilder Builder = QueryBuilders.GeodistanceQuery ("Dirección"). Point (Lat, Lon) .Distance (100, DistanceUnit.Meters); GeodistancesortBuilder sortBuilder = sortBuilders.Geodistancesort ("dirección") .Point (Lat, Lon) .unit (DistanceUnit.Meters) .order (sortOrder.asc); Concordante pagable = nuevo pagequest (0, 50); NatesearchQueryBuilder Builder1 = New NatesearchQueryBuilder (). WithFilter (Builder) .WithSort (SortBuilder) .WithPagable (pagible); SearchQuery SearchQuery = Builder1.Build (); // QueryForlist se pagina de forma predeterminada y se utiliza la consulta. El valor predeterminado es 10 List <Oll> PersonList = ElasticSearchTemplate.QueryForList (SearchQuery, Person.Class); System.out.println ("TimeConsuming:" + (System.CurrentTimemillis () - NowTime)); devolver la lista de personas; }} Mirando la clase del controlador, en el método Agregar, insertamos 900,000 datos de prueba y generamos aleatoriamente diferentes direcciones de latitud y longitud.
En el método de consulta, construimos una condición de consulta que está a menos de 100 metros de la consulta, ordenada según la distancia y pagando 50 elementos por página. Si no se especifica que se puede especificar, la consulta de la propiedad es 10 de forma predeterminada, lo que se puede ver a través del código fuente.
Inicie el proyecto, ejecute Agregar primero y espere a que se inserten millones de datos, durante unas pocas docenas de segundos.
Luego ejecute la consulta y vea los resultados.
La primera consulta tomó más de 300 ms, y el tiempo cayó significativamente después de la consulta nuevamente, a unos 30 ms, porque ES se ha almacenado en caché automáticamente a la memoria.
Se puede ver que ES completa la consulta de la ubicación geográfica muy rápidamente. Adecuado para consultas como personas cercanas y consulta de alcance.
PostScript: en uso posterior, en la versión 2.3 de Elasticsearch, el geotipo no se puede indexar de acuerdo con el método de escritura anterior. La entrada ES es una cadena en lugar del Geofiled marcado. Aquí hay un registro de la solución, modifique el tipo de cadena a GeoPoint y está empaquetado en org.springframework.data.elasticsearch.core.geo.geopoint. Luego, debe llamar explícitamente el método de mapeo al crear el índice para asignar correctamente a GeoField.
como sigue
if (! ElasticsearchTemplate.IndexExists ("ABC")) {ElasticSearchTemplate.CreateIndex ("ABC"); ElasticsearchTemplate.putMapping (Person.Class); }Lo anterior es todo el contenido de este artículo. Espero que sea útil para el aprendizaje de todos y espero que todos apoyen más a Wulin.com.