บทความก่อนหน้านี้แนะนำว่า Elasticsearch ใช้ที่เก็บและ ElasticsearchTemplate เพื่อสร้างเงื่อนไขการสืบค้นที่ซับซ้อนและแนะนำฟังก์ชั่นของ Elasticsearch เพื่อใช้ที่ตั้งทางภูมิศาสตร์
ในบทความนี้มาดูฟังก์ชั่นการใช้ Elasticsearch เพื่อกรอกข้อมูลการสืบค้นข้อมูลขนาดใหญ่ใกล้เคียงและค้นหาข้อมูลภายในช่วง N-Meter
เตรียมสภาพแวดล้อม
การทดสอบแบบดั้งเดิมใช้ Elasticsearch รุ่นล่าสุด 5.5.1, Springboot1.5.4 และ Spring-Data-Elasticsearch2.1.4
สร้างโครงการ Springboot ใหม่ตรวจสอบ Elasticsearch และ Web
ไฟล์ POM มีดังนี้
<? xml version = "1.0" การเข้ารหัส = "utf-8"?> <project xmlns = "http://maven.apache.org/pom/4.0.0" xmlns: xsi = "http://www.w3.org/2001/ XSI: schemalocation = "http://maven.apache.org/pom/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" <ArtIfactId> Elasticsearch </artifactId> <persion> 0.0.1-Snapshot </เวอร์ชัน> <packaging> jar </packaging> <name> elasticsearch </name> <scription> โครงการสาธิตสำหรับการบูตฤดูใบไม้ผลิ </คำอธิบาย> <carent> <Sersion> 1.5.4.Release </เวอร์ชัน> <inelypath/> <!-การค้นหาผู้ปกครองจากที่เก็บ-> </parent> <properties> <project.build.sourceencoding> utf-8 </project.build.sourceencoding> <java.version> 1.8 </java.version> </premerties> <การพึ่งพา> <การพึ่งพา> <roupId> org.springframework.boot </groupid> <ratifactid> Spring-Boot-Starter-Data-ElasticSearch </artifactid> <ArtIfactId> Spring-Boot-Starter-WEB </artifactId> </serdency> <การพึ่งพา> <roupId> org.springframework.boot </groupid> <ratifactid> การทดสอบสปริง <ArtIfactId> JNA </artifactId> <sersion> 3.0.9 </Sident> </การพึ่งพาอาศัย> </perctencies> <uffer> <build> <plugins> <plugin> <splugin> <roupid> org.springframework.boot </groupid> <atifactid> สปริง
สร้างบุคคลรุ่นใหม่
แพ็คเกจ com.tianyalei.elasticsearch.model; นำเข้า org.springframework.data.annotation.id; นำเข้า org.springframework.data.elasticsearch.annotations.document; นำเข้า org.springframework.data.elasticsearch.annotations.geopointfield; นำเข้า java.io.serializable; / *** คลาสรุ่น*/ @Document (indexname = "eLastic_Search_project", type = "person", indexstoretype = "fs", shards = 5, reflicas = 1, RefreshInterval = "-1") บุคคลชั้นเรียน ชื่อสตริงส่วนตัว; โทรศัพท์สตริงส่วนตัว / ** * ละติจูดที่ตั้งทางภูมิศาสตร์และลองจิจูด * ละติจูด Lon Longitude "40.715, -74.011" * ถ้าคุณใช้อาร์เรย์ตรงข้ามคือจริง [-73.983, 40.719] */ @geopointfield ที่อยู่สตริงส่วนตัว; สาธารณะ int getId () {return id; } โมฆะสาธารณะ setId (int id) {this.id = id; } สตริงสาธารณะ getName () {ชื่อคืน; } โมฆะสาธารณะ setName (ชื่อสตริง) {this.name = name; } สตริงสาธารณะ getphone () {ส่งคืนโทรศัพท์; } โมฆะสาธารณะ setphone (โทรศัพท์สตริง) {this.phone = โทรศัพท์; } สตริงสาธารณะ getAddress () {return address; } โมฆะสาธารณะ setAddress (ที่อยู่สตริง) {this.address = ที่อยู่; - ฉันใช้ฟิลด์ที่อยู่เพื่อแสดงตำแหน่งละติจูดและลองจิจูด โปรดทราบว่าการใช้สตริง [] และสตริงนั้นแตกต่างกันเมื่อแสดงถึงละติจูดและลองจิจูดให้ดูความคิดเห็น
นำเข้า com.tianyalei.elasticsearch.model.person; นำเข้า org.springframework.data.elasticsearch.repository.elasticsearchrepository; ส่วนต่อประสานสาธารณะ personrepository ขยาย eLASTICSEARCHEPOSITIORY <person, Integer> {} ลองดูที่คลาสบริการและทำหน้าที่ของการแทรกข้อมูลการทดสอบ ฉันใส่ฟังก์ชั่นการสืบค้นในคอนโทรลเลอร์ เพื่อความสะดวกควรวางไว้ในบริการตามปกติ
แพ็คเกจ com.tianyale.elasticsearch.service; นำเข้า com.tianyalei.elasticsearch.model.person; นำเข้า com.tianyale.elasticsearch.repository.personrepository; นำเข้า org.springframework.beans.factory.annotation.autowired; นำเข้า org.springframework.data.elasticsearch.core.elasticsearchtemplate; นำเข้า org.springframework.data.elasticsearch.core.query.indexQuery; นำเข้า org.springframework.stereotype.service; นำเข้า java.util.arraylist; นำเข้า java.util.list; @Service Public Class Personservice {@autowired personrepository personrepository; @autowired ElasticSearchTemplate ElasticsearchTemplate; สตริงสุดท้ายคงที่ส่วนตัว person_index_name = "Elastic_search_project"; สตริงสุดท้ายคงที่ส่วนตัว person_index_type = "บุคคล"; บุคคลสาธารณะเพิ่ม (บุคคลบุคคล) {return personrepository.save (บุคคล); } โมฆะสาธารณะ BULKINDEX (รายการ <Person> PersonList) {int counter = 0; ลอง {ถ้า (! elasticsearchTemplate.indexExists (person_index_name)) {elasticsearchTemplate.createIndex (person_index_type); } list <ploenquery> แบบสอบถาม = new ArrayList <> (); สำหรับ (บุคคลบุคคล: PersonList) {IndexQuery IndexQuery = new IndexQuery (); indexQuery.setId (person.getId () + ""); indexQuery.setObject (บุคคล); indexQuery.setIndexName (person_index_name); indexQuery.setType (person_index_type); // ขั้นตอนข้างต้นยังสามารถใช้ในการสร้างโดยใช้ indexQueryBuilder // indexQuery index = new IndexQueryBuilder (). withId (person.getId () + "") Queries.add (IndexQuery); if (counter % 500 == 0) {elasticsearchTemplate.bulkindex (แบบสอบถาม); Queries.Clear (); System.out.println ("ตัวนับ bulkindex:" + ตัวนับ); } เคาน์เตอร์ ++; } if (Queries.Size ()> 0) {ElasticSearchTemplate.bulkindex (แบบสอบถาม); } system.out.println ("Bulkindex เสร็จสมบูรณ์"); } catch (exception e) {system.out.println ("indexerservice.bulkindex e;" + e.getMessage ()); โยน e; -ให้ความสนใจกับวิธี BULKINDEX ซึ่งใช้ในการใส่ข้อมูลแบทช์ BULK ยังเป็นวิธีการของแบทช์แทรกข้อมูลที่แนะนำอย่างเป็นทางการโดย ES ที่นี่จำนวนมากจะถูกแทรกทุก 500 จำนวนเต็มทวีคูณ
แพ็คเกจ com.tianyale.elasticsearch.controller; นำเข้า com.tianyalei.elasticsearch.model.person; นำเข้า com.tianyale.elasticsearch.service.personservice; นำเข้า org.elasticsearch.common.unit.distanceunit; นำเข้า org.elasticsearch.index.query.geodistanceQueryBuilder; นำเข้า org.elasticsearch.index.query.queryBuilders; นำเข้า org.elasticsearch.search.sort.geodistancesortbuilder; นำเข้า org.elasticsearch.search.sort.sortbuilders; นำเข้า org.elasticsearch.search.sort.sortorder; นำเข้า org.springframework.beans.factory.annotation.autowired; นำเข้า org.springframework.data.domain.pageRequest; นำเข้า org.springframework.data.domain.pageable; นำเข้า org.springframework.data.elasticsearch.core.elasticsearchtemplate; นำเข้า org.springframework.data.elasticsearch.core.query.nativesearchQueryBuilder; นำเข้า org.springframework.data.elasticsearch.core.query.searchQuery; นำเข้า org.springframework.web.bind.annotation.getMapping; นำเข้า org.springframework.web.bind.annotation.restcontroller; นำเข้า java.text.decimalformat; นำเข้า java.util.arraylist; นำเข้า java.util.list; นำเข้า java.util.random; @RestController ชั้นเรียนสาธารณะ PersonController {@autowired Personservice Personservice; @autowired ElasticSearchTemplate ElasticsearchTemplate; @getMapping ("/เพิ่ม") วัตถุสาธารณะเพิ่ม () {double lat = 39.929986; double lon = 116.395645; รายการ <person> personlist = new ArrayList <> (900000); สำหรับ (int i = 100000; i <1000000; i ++) {double max = 0.00001; สองนาที = 0.000001; สุ่มสุ่ม = ใหม่สุ่ม (); double s = random.nextdouble () % (สูงสุด - min + 1) + สูงสุด; DecimalFormat df = decimalformat ใหม่ ("###### 0.000000"); // system.out.println (s); สตริง lons = df.format (s + lon); สตริง lats = df.format (s + lat); double dlon = double.valueof (lons); double dlat = double.valueof (lats); บุคคล = บุคคลใหม่ (); person.setid (i); person.setName ("ชื่อ" + i); person.setphone ("tel" + i); person.setAddress (dlat + "," + dlon); personlist.add (บุคคล); } personservice.bulkindex (รายการบุคคล); // SearchQuery SearchQuery = ใหม่ NativeSearchQueryBuilder (). WithQuery (QueryBuilders.QueryStringQuery ("Spring Boot หรือ Book")). build (); // รายการ <sarticle> บทความ = elas, ticsearchtemplate.queryforlist (se, archquery, article.class); // สำหรับ (บทความบทความ: บทความ) {// system.out.println (บทความ. toString ()); //} ส่งคืน "เพิ่มข้อมูล"; } /*** geo_distance: ค้นหาตำแหน่งภายในช่วงหนึ่งของจุดศูนย์กลางบางจุด GEO_Bounding_Box: ค้นหาตำแหน่งภายในพื้นที่สี่เหลี่ยมผืนผ้า GEO_Distance_Range: ค้นหาตำแหน่งระหว่างขั้นต่ำและ Max Geo_Polygon: ค้นหาตำแหน่งภายในรูปหลายเหลี่ยม การเรียงลำดับสามารถใช้ในการเรียงลำดับ */ @getMapping ("/ query") การสืบค้นวัตถุสาธารณะ () {double lat = 39.929986; double lon = 116.395645; นานแล้ว = System.currentTimeMillis (); // แบบสอบถามภายในละติจูดและลองจิจูดที่แน่นอนภายใน 100 เมตร GeodistanceQueryBuilder Builder = QueryBuilders.GeodistanceQuery ("ที่อยู่") จุด (LAT, LON). DISTANCE (100, MAILEUNIT.METERS); geodistancesortBuilder sortBuilder = sortBuilders.Geodistancesort ("ที่อยู่") .Point (lat, lon) .unit (distanceUnit.meters). order (sortorder.asc); PAGABLE PAGABLE = NEW PAGEREQUEST (0, 50); NativeSearchQueryBuilder Builder1 = ใหม่ NativeSearchQueryBuilder (). with filter (builder). withSort (sortBuilder). withPageable (pageable); SearchQuery SearchQuery = builder1.build (); // queryforlist ถูก paginated โดยค่าเริ่มต้นและใช้ queryforpage ค่าเริ่มต้นคือ 10 รายการ <person> personlist = elasticsearchTemplate.QueryForList (SearchQuery, person.class); System.out.println ("timeconsuming:" + (system.currenttimeMillis () - ตอนนี้)); รายการบุคคลกลับ; - เมื่อดูที่คลาสคอนโทรลเลอร์ในวิธีการเพิ่มเราแทรกข้อมูลทดสอบ 900,000 และสร้างที่อยู่ละติจูดและลองจิจูดที่แตกต่างกันแบบสุ่ม
ในวิธีการสืบค้นเราสร้างเงื่อนไขการสืบค้นที่อยู่ภายในระยะ 100 เมตรของแบบสอบถามเรียงลำดับตามระยะทางและเพจ 50 รายการต่อหน้า หากไม่ได้ระบุ pageable queryforlist ของ Estemplate คือ 10 โดยค่าเริ่มต้นซึ่งสามารถมองเห็นได้ผ่านซอร์สโค้ด
เริ่มโครงการดำเนินการเพิ่มก่อนและรอข้อมูลนับล้านที่จะแทรกประมาณไม่กี่โหลวินาที
จากนั้นดำเนินการค้นหาและดูผลลัพธ์
แบบสอบถามแรกใช้เวลามากกว่า 300ms และเวลาลดลงอย่างมีนัยสำคัญหลังจากการสืบค้นอีกครั้งถึงประมาณ 30ms เนื่องจาก ES ถูกแคชไปที่หน่วยความจำโดยอัตโนมัติ
จะเห็นได้ว่า ES เสร็จสิ้นการสืบค้นที่ตั้งทางภูมิศาสตร์อย่างรวดเร็ว เหมาะสำหรับการสอบถามเช่นคนใกล้เคียงและการสืบค้นขอบเขต
Postscript: ในการใช้งานในภายหลังใน ElasticSearch เวอร์ชัน 2.3 ธรณีโพตเปิ้ลไม่สามารถจัดทำดัชนีตามวิธีการเขียนข้างต้น รายการ ES เป็นสตริงแทน geofiled ที่ทำเครื่องหมายไว้ นี่คือบันทึกของโซลูชันแก้ไขประเภทสตริงเป็น geopoint และมันถูกบรรจุภายใต้ org.springframework.data.elasticsearch.core.geo.geopoint จากนั้นคุณต้องเรียกใช้วิธีการแมปอย่างชัดเจนเมื่อสร้างดัชนีเพื่อแมปอย่างถูกต้องไปยัง Geofield
ดังนี้
if (! ElasticSearchTemplate.indexExists ("ABC")) {ElasticsearchTemplate.CreateIndex ("ABC"); ElasticSearchTemplate.putMapping (person.class); -ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่ามันจะเป็นประโยชน์ต่อการเรียนรู้ของทุกคนและฉันหวังว่าทุกคนจะสนับสนุน wulin.com มากขึ้น