บทความนี้ไม่เกี่ยวข้องกับหลักการเฉพาะของ Elasticsearch แต่จะบันทึกเฉพาะวิธีการนำเข้าข้อมูลใน MySQL อย่างรวดเร็วสำหรับการค้นหาข้อความแบบเต็ม
ในที่ทำงานคุณต้องใช้ฟังก์ชั่นการค้นหาและนำเข้าข้อมูลฐานข้อมูลที่มีอยู่ หัวหน้าทีมแนะนำให้ใช้ Elasticsearch เพื่อนำไปใช้ คุณสามารถค้นหาผ่านบทเรียนออนไลน์ซึ่งเป็นบทความที่ค่อนข้างเก่า ฉันไม่มีทางเลือกนอกจากสำรวจด้วยตัวเอง อ้างถึงเอกสาร ES และสร้างบริการในที่สุด ฉันจะบันทึกมัน ฉันหวังว่าเพื่อนที่มีความต้องการเดียวกันสามารถหลีกเลี่ยงการออกนอกเส้นทางและสามารถสร้างบริการ Elasticsearch ที่มีอยู่ได้อย่างรวดเร็วตามบทช่วยสอนนี้
การก่อสร้าง ES
ES Builds สามารถดาวน์โหลดไฟล์ ZIP และคอนเทนเนอร์ Docker ได้โดยตรง นักเทียบท่าค่อนข้างเหมาะสำหรับเราในการให้บริการ ES เป็นไปได้ที่จะสร้างคลัสเตอร์หรือสร้างสภาพแวดล้อมการทดสอบได้อย่างง่ายดาย วิธีการคอนเทนเนอร์ยังใช้ที่นี่ ก่อนอื่นเราต้องมี dockerfile:
จาก docker.elastic.co/elasticsearch/elasticsearch-oss:6.0.0# ส่งการกำหนดค่ารวมถึง eLASTICSEARCH.YML และ KEYSTORE.JKS ใหม่ COPY-CHOWN = ELASTICSEARCH: ELASTICSEARH CONF//USR/Share/ElasticSearch/CONFIG/# https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.0.0/elasticsearch-analysis-Ik-6.0.0.zip# ติดตั้ง readonlyrestrun ./bin/elasticsearch-plugin ติดตั้ง https://github.com/hyy-yu/beziercurvedemo/raw/master/readonlyrest-16.14_es6.0.0.zipuser elasticsearchcmd ./bin/elasticsearch
นี่คือคำอธิบายของการดำเนินการข้างต้น:
elictic การกำหนดค่า elasticsearch.yml
Cluster.Name: "Docker-Cluster" Network.host: 0.0.0.0# minimum_master_nodes จำเป็นต้องตั้งค่าไว้อย่างชัดเจนเมื่อถูกผูกไว้บน IP สาธารณะ# ตั้งค่าเป็น 1 เพื่อให้กลุ่มโหนดเดียว# รายละเอียด: https://github.com/elastic/elasticsearch บน es bootstrap.memory_lock: จริง http.type: ssl_netty4readonlyrest: เปิดใช้งาน: true ssl: เปิดใช้งาน: true keystore_file: "server.jks" keystore_pass: server key_pass: server access_control_rules: "ชื่อ" ["ผู้ใช้"] ดัชนี: ["กระดาษ*"] การกระทำ: ["ดัชนี: ข้อมูล/อ่าน/*"] ผู้ใช้: - ชื่อผู้ใช้: root auth_key_sha256: CB7C98BAE153065DB931980A13BD45EE3A77CB8F27A7DFEE Xiaoming Auth_key: Xiaoming: Xiaoming Groups: ["ผู้ใช้"]
ที่นี่ bootstrap.memory_lock: จริงเป็นหลุมห้ามการแลกเปลี่ยนหน่วยความจำ เอกสารได้อธิบายไว้แล้วว่าระบบปฏิบัติการบางแห่งจะเปลี่ยนหน่วยความจำที่ไม่ได้ใช้ชั่วคราวไปยังพื้นที่ของฮาร์ดดิสก์ในช่วงรันไทม์ อย่างไรก็ตามพฤติกรรมนี้จะเพิ่มขึ้นอัตราการใช้ทรัพยากรของ ES และทำให้ระบบไม่สามารถตอบสนองได้
เป็นที่ชัดเจนแล้วในไฟล์การกำหนดค่าที่ผู้ใช้รูทเป็นของกลุ่มผู้ดูแลระบบและผู้ดูแลระบบมีสิทธิ์ทั้งหมด เนื่องจาก Xiaoming อยู่ในกลุ่มผู้ใช้เขาสามารถเข้าถึงดัชนีกระดาษเท่านั้นและสามารถอ่านได้เท่านั้น แต่ไม่สามารถทำงานได้ สำหรับการกำหนดค่าโดยละเอียดเพิ่มเติมโปรดดู: เอกสารอ่านเอกสาร
ณ จุดนี้การเตรียมการสำหรับ ES เสร็จสมบูรณ์ Docker build -t esimage: แท็ก Docker Run -P 9200: 9200 esimage: แท็กรัน
ถ้า https://127.0.0.1:9200/ ส่งคืน
{"NAME": "VAKWRIR", "Cluster_name": "Docker-Cluster", "Cluster_UUID": "YSyDowKVRH2SWZ907S2M_W", "เวอร์ชัน": {"หมายเลข": "6.0.0", "build_hash": "8f0685b" "2017-11-10T18: 41: 22.859Z", "build_snapshot": false, "lucene_version": "7.0.1", "minimum_wire_compatibility_version": "5.6.0"ตัวเอกของการสอนของเราปรากฏขึ้น ฉันจะแบ่งปัน API ที่ใช้กันทั่วไปหลายประการเพื่อหยอกล้อและดีบัก ES:
{{url}} ถูกแทนที่ด้วยที่อยู่ ES ในพื้นที่ของคุณ
นำเข้าข้อมูล MySQL
ฉันใช้ข้อมูล MySQL ที่นี่ แต่ที่จริงแล้วฐานข้อมูลอื่น ๆ ก็เหมือนกัน กุญแจสำคัญคือวิธีการนำเข้า การสอนออนไลน์จะแนะนำปลั๊กอิน MySQL สำหรับ LogStash, Beat และ ES สำหรับการนำเข้า ฉันได้ลองด้วย การกำหนดค่านั้นยุ่งยากและเอกสารนั้นกระจัดกระจาย หากโครงสร้างฐานข้อมูลมีความซับซ้อนเล็กน้อยการนำเข้าเป็นงานที่ลำบากดังนั้นจึงไม่แนะนำ ในความเป็นจริง ES มีไลบรารี API ที่สอดคล้องกันในแต่ละภาษา คุณสามารถรวบรวมข้อมูลลงใน JSON ในระดับภาษาและส่งไปยัง ES ผ่านห้องสมุด API กระบวนการมีดังนี้:
ฉันใช้ ES Library Elastic ของ Golang คุณสามารถค้นหา GitHub สำหรับภาษาอื่น ๆ และวิธีการทำงานเหมือนกัน
ถัดไปใช้ฐานข้อมูลอย่างง่ายเพื่อแนะนำ:
โต๊ะกระดาษ
| รหัสประจำตัว | ชื่อ |
|---|---|
| 1 | ปักกิ่งหมายเลข 1 การจำลองโรงเรียนประถมศึกษา |
| 2 | คำถามการสอบเข้าวิทยาลัยทั่วไปของ Jiangxi Beijing General College |
ตารางจังหวัด
| รหัสประจำตัว | ชื่อ |
|---|---|
| 1 | ปักกิ่ง |
| 2 | เจียงซี |
Paper_province Table
| Paper_id | จังหวัด _id |
|---|---|
| 1 | 1 |
| 2 | 1 |
| 2 | 2 |
ดังที่ได้กล่าวไว้ข้างต้นกระดาษและจังหวัดมีความสัมพันธ์หลายต่อหลายคน ตอนนี้ข้อมูลกระดาษถูกป้อนลงใน ES คุณสามารถค้นหาชื่อกระดาษหรือกรองผ่านจังหวัด รูปแบบข้อมูล JSON มีดังนี้:
{"id": 1, "ชื่อ": "ปักกิ่งหมายเลข 1 ปริมาณการจำลองโรงเรียนประถมศึกษา", "จังหวัด": [{"id": 1, "ชื่อ": "Beijing"}]} ก่อนเตรียมไฟล์ mapping.json ซึ่งเป็นคำจำกัดความโครงสร้างการจัดเก็บข้อมูลของข้อมูลใน ES
{"การแม็พ": {"เอกสาร": {"รวม _in_all": false, "คุณสมบัติ": {"id": {"type": "long"}, "name": {"type": "text", "analyzer": "ik_max_word" // "id": {"type": "integer"}, "name": {"type": "text", "index": "false" // ไม่ได้ทำดัชนี}}}}}}}}}}}}}, "การตั้งค่า": "number_of_shards"ควรสังเกตว่าฟิลด์ _all ถูกยกเลิก ค่าเริ่มต้น _all นี้จะรวบรวมฟิลด์หน่วยเก็บข้อมูลทั้งหมดเพื่อให้ได้การค้นหาที่ จำกัด อย่างไม่มีเงื่อนไข ข้อเสียคือพื้นที่มีพื้นที่มาก
ฉันตั้งค่าหมายเลข Shard เป็น 1 และไม่มีการตั้งค่าแบบจำลอง ท้ายที่สุดนี่ไม่ใช่คลัสเตอร์และข้อมูลที่ประมวลผลไม่มากนัก หากมีข้อมูลจำนวนมากที่ต้องประมวลผลคุณสามารถตั้งค่าจำนวนเศษและแบบจำลองด้วยตัวเอง
ขั้นแรกให้สร้างการเชื่อมต่อกับ ES, CA.CRT เกี่ยวข้องกับการลงชื่อด้วยตนเองของ JKS แน่นอนที่นี่ฉันใช้ Unsecureskipverify เพื่อเพิกเฉยต่อการตรวจสอบไฟล์ใบรับรอง
func initelasticsearch () {pool: = x509.newcertpool () crt, err0: = ioutil.readfile ("conf/ca.crt") ถ้า err0! = nil {ไม่สามารถ openes (err0, "อ่านไฟล์ crt err") return} pool.appendcertsfrompem & tls.config {rootcas: พูล, ไม่ปลอดภัย kipverify: true},} httpClient: = & http.client {การขนส่ง: tr} // พื้นหลังสร้างความยืดหยุ่น Elastic.setGzip (จริง), Elastic.SethttpClient (httpClient), Elastic.setsniff (เท็จ), // sniff คลัสเตอร์, อย่าลืมปิดโหนดเดียว "search_client_error") return} // การก่อสร้างความยืดหยุ่นเสร็จสมบูรณ์ // คำถามว่ามีดัชนีกระดาษอยู่หรือไม่ err: = elasticClient.indexexists (myConfig.elasticIndexname) .do (backgroundground ()) หากไม่ได้รับการตรวจสอบ ถ้ามีอยู่ {ถ้า! isIndexIntegrity (ElasticClient) {// ลบดัชนีปัจจุบันและเตรียมที่จะสร้าง deleteresponse, err: = eLasticClient.deleteIndex (myConfig.elasticIndexName) .do (context.background ()) ! deleteresponse.ackNowledged {ไม่สามารถเปิด (เอ่อ, "delete_index_error") return}} else {return}} // ฐานข้อมูลการสืบค้นพื้นหลังและส่งข้อมูลไปยัง elasticsearch Go FetchDbgetAllPaperandSendToes ()}}}}}} พิมพ์ papersearch struct {paperid int64 `gorm:" primary_key; คอลัมน์: f_paper_id; ประเภท: bigint (20) "json:" id "` สตริงชื่อ `gorm:" คอลัมน์: f_name; ขนาด: 80 "json:" ชื่อ " JSON: "จังหวัด" `// จังหวัดที่กระดาษทดสอบใช้งานได้} func fetchdbgetallpaperandsendtoes () {// fetch paper var allpaper [] papersearch getdb () ตาราง (" t_papers ") ค้นหา (& Allpaper) // getdb (). ตาราง ("t_provinces"). เข้าร่วม ("เข้าร่วม` t_paper_province` บน `t_paper_province`. 'province_f_province_id` =' t_provinces ' AllPaper [i] .PaperID) .find (& AllPro) AllPaper [i] .provinces = AllPro} ถ้า LEN (AllPaper)> 0 {// ส่งไปยัง ES - สร้าง INDEX CREATESERVICE: = getElAsticSearch (). createIndex createservice.body (index_default_setting) createresult, err: = createservice.do (context.background ()) ถ้า err! = nil {ไม่สามารถ openes (err, "create_paper_index") {createresult.acknowledged ||! // - ส่งกระดาษ bulkrequest ทั้งหมด: = getElasticSearch (). bulk () สำหรับ i: = ช่วง AllPaper {indexreq: = Elastic.newbulkindexRequest (). optype ("Create"). index (myConfig.elasticIndexName). Doc (AllPaper [i]) bulkrequest.add (indexreq)} // ส่งคำขอจำนวนมากไปยัง ElasticSearch BulkResponse, err: = bulkrequest.do (บริบท. background ()) ถ้า err! ! = len (allpaper) {ไม่สามารถเปิด (เอ่อ, "insert_docs_nums_error") return} // ส่งความสำเร็จ}} หลังจากเรียกใช้รหัสด้านบนให้ใช้ {{url}}/_ cat/ดัชนี? v เพื่อดูว่าดัชนีที่สร้างขึ้นใหม่จะปรากฏใน ES หรือไม่และใช้ {{url}}/papers/_search เพื่อดูว่ามีเอกสารจำนวนเท่าใด หากจำนวนเอกสารเท่ากับจำนวนข้อมูลที่คุณส่งในอดีตบริการค้นหาจะถูกพิจารณาว่ากำลังทำงานอยู่
ค้นหา
ตอนนี้คุณสามารถค้นหาเอกสารทดสอบโดย ProvinceID และ Q และค่าเริ่มต้นจะถูกเรียงลำดับตามคะแนนความเกี่ยวข้อง
// q การค้นหาสตริง ProvinceID จำกัด มณฑล จำกัด พารามิเตอร์การแบ่งหน้าพารามิเตอร์ func searchpaper (q string, provinceid uint, จำกัด int, หน้า int) (รายการ [] เอกสารการค้นหา, totalPage int, currentPage int, pageisend int, returneRerr) {// หากเงื่อนไขไม่ตรงไปตรงมา SearchPaperLocal (Q, CourseID, เกรด, ProvinceId, PaperTypeId, ขีด จำกัด , หน้า)} list = make ([] PaperImple, 0) TotalPage = 0 CurrentPage = Page PageAnd = 0 returnerr = nil ไคลเอ็นต์: = getelasticsearch () หากไคลเอนต์ == nil ปัญหาเกี่ยวกับ ElasticSearch ใช้ฐานข้อมูลเพื่อค้นหาว่า! isIndexIntegrity (ไคลเอนต์) {ส่งคืน searchPaperLocal (q, courseid, เกรด, provinceid, papertypeid, ขีด จำกัด , หน้า)} ถ้า! client.isrunning () {client.start () Elastic.newBoolQuery () // Paper.name MatchQuery: = Elastic.newMatchQuery ("ชื่อ", Q) // จังหวัดถ้า ProvinceId> 0 && ProvinceId! = default_province_all {probool: = Elastic.newBoolQuery () Elastic.newnestedQuery ("จังหวัด", probool.must (tpro)) boolQuery.must (pronest)} boolQuery.must (matchQuery) สำหรับ _, e: = range termQuerys {boolQuery.must (e)} ไฮไลต์ highlight.pretags (Elastic_search_search_field_tag_start) Highlight.postTags (Elastic_search_search_field_tag_end) SearchResult, err2: = client.search (myconfig.elasticIndexName) ไฮไลต์ (Highligt) แบบสอบถาม (บูลคิวรี่) จาก ((หน้า - 1) * ขีด จำกัด ) ขนาด (ขีด จำกัด ) ทำ (context.background ()) ถ้า err2! = nil {// จัดการข้อผิดพลาด getLogger (). logerr ("เกิดข้อผิดพลาดในขณะที่ค้นหา"+err2.error (), "search_error") // จัดการข้อผิดพลาด returnerr = errors.new ("เกิดข้อผิดพลาดในระหว่างการค้นหา") searchResult.hits.hits {var p papersearch err: = json.unmarshal (*hit.source, & p) ถ้า err! = nil {// deserialization ล้มเหลว getLogger (). logerr ("เกิดข้อผิดพลาดระหว่างการค้นหา" len (hit.highlight [eLastic_Search_Search_field_name])> 0 {p.name = hit.highlight [eLastic_Search_Search_field_name] [0]} รายการ = ภาคผนวก (รายการ, p)} นับ: = searchResult.totalhits () float64 (ขีด จำกัด )))} ถ้า currentPage> = totalPage {pageIsend = 1}} else {// no hit}} return}}}ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่ามันจะเป็นประโยชน์ต่อการเรียนรู้ของทุกคนและฉันหวังว่าทุกคนจะสนับสนุน wulin.com มากขึ้น