ElasticSearch
เว็บไซต์ทางการ: Elasticsearch: เครื่องมือค้นหาและวิเคราะห์แบบกระจาย | Elastic
Elasticsearch เป็นเครื่องมือค้นหาและวิเคราะห์ข้อมูลแบบกระจาย RESTful ที่สามารถจัดการกับกรณีการใช้งานต่างๆ ที่เกิดขึ้นอย่างต่อเนื่อง ในฐานะหัวใจหลักของ Elastic Stack, Elasticsearch จะจัดเก็บข้อมูลของคุณไว้ที่ส่วนกลาง ทำให้คุณสามารถค้นหาได้รวดเร็ว ปรับแต่งความเกี่ยวข้อง วิเคราะห์อย่างทรงพลัง และปรับขนาดได้อย่างง่ายดาย บทความนี้จะอธิบายวิธีการดำเนินการพื้นฐานบางอย่างกับ Elasticsearch ด้วย Go เช่น การเพิ่ม ลบ แก้ไข และค้นหา หากคุณไม่คุ้นเคยกับ Elasticsearch โปรดศึกษาด้วยตนเองก่อน
การติดตั้ง
ดาวน์โหลดไลบรารีทางการ
$ github.com/elastic/go-elasticsearch/v7หากคุณใช้ ES8 ให้เปลี่ยนเวอร์ชัน
$ github.com/elastic/go-elasticsearch/v8TIP
บทความนี้ใช้ ES8 เพื่อสาธิต
การเชื่อมต่อ
ใช้ฟังก์ชัน elasticsearch.NewClient เพื่อสร้างการเชื่อมต่อใหม่
func NewClient(cfg Config) (*Client, error)ES8+ ใช้การเชื่อมต่อ HTTPS เป็นค่าเริ่มต้น เมื่อสร้างการเชื่อมต่อ HTTPS คุณสามารถใช้ใบรับรอง CA หรือลายนิ้วมือ CA ซึ่งทั้งสองอย่างสร้างขึ้นบนเซิร์ฟเวอร์ Elasticsearch ตัวอย่างดังนี้
client, err := elasticsearch.NewClient(elasticsearch.Config{
Addresses: []string{"https://192.168.153.132:9200"},
Username: "elastic",
Password: "TETJ8IY+ifbt8SLc+RRQ",
CertificateFingerprint: "C0E9867C7D446BFF72FE46E7E9FE3455E970A8ADB0D3DF0E1472D55DB2612CD5",
})Go API ที่ elasticsearch จัดเตรียมไว้ล้วนเป็นฟังก์ชันแบบออปชัน เช่น การทดสอบว่าบริการใช้งานได้หรือไม่ผ่าน ping API
pingResp, err := client.Ping(client.Ping.WithPretty(), client.Ping.WithHuman())
if err != nil {
panic(err)
}
fmt.Println(pingResp)ผลลัพธ์
[200 OK]หรือตรวจสอบสถานะบริการผ่าน Info API
infoResp, err := client.Info(client.Info.WithHuman())
if err != nil {
panic(err)
}
fmt.Println(infoResp)ผลลัพธ์
[200 OK] {
"name" : "db-debian12",
"cluster_name" : "docker-cluster",
"cluster_uuid" : "OMbDIsNwTFiuyjNF9Xnpbw",
"version" : {
"number" : "8.15.0",
"build_flavor" : "default",
"build_type" : "docker",
"build_hash" : "1a77947f34deddb41af25e6f0ddb8e830159c179",
"build_date" : "2024-08-05T10:05:34.233336849Z",
"build_snapshot" : false,
"lucene_version" : "9.11.1",
"minimum_wire_compatibility_version" : "7.17.0",
"minimum_index_compatibility_version" : "7.0.0"
},
"tagline" : "You Know, for Search"
}TIP
สำหรับคำถามใดๆ เกี่ยวกับ ES API โปรดดูเอกสารทางการ ES Restful API
ดัชนี
ดำเนินการดัชนีผ่าน go api API ทั้งหมดเกี่ยวกับการดำเนินการดัชนีอยู่ในโครงสร้าง esapi.Indices
// Indices contains the Indices APIs
type Indices struct {
AddBlock IndicesAddBlock
Analyze IndicesAnalyze
ClearCache IndicesClearCache
Clone IndicesClone
Close IndicesClose
...
...
ValidateQuery IndicesValidateQuery
}การสร้าง
สร้างดัชนี ดังนี้
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 2
},
"mappings": {
"properties": {
"name": {
"type": "text"
},
"age": {
"type": "long"
},
"salary": {
"type": "double"
}
}
}
}การดำเนินการจริง คล้ายกับการส่งคำขอ HTTP
func main() {
client, err := newClient()
if err != nil {
panic(err)
}
dsl := bytes.NewBufferString(`{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 2
},
"mappings": {
"properties": {
"name": {
"type": "text"
},
"age": {
"type": "long"
},
"salary": {
"type": "double"
}
}
}
}`)
createIndices := client.Indices.Create
resp, err := createIndices("user", createIndices.WithBody(dsl))
if err != nil {
panic(err)
}
fmt.Println(resp)
}ผลลัพธ์
[200 OK] {"acknowledged":true,"shards_acknowledged":true,"index":"user"}การดึง
ดึงข้อมูลดัชนีหลายดัชนี
func main() {
client, err := newClient()
if err != nil {
panic(err)
}
get := client.Indices.Get
response, err := get([]string{"user"}, get.WithPretty(), get.WithHuman())
if err != nil {
panic(err)
}
fmt.Println(response)
}ผลลัพธ์
[200 OK] {
"user" : {
"aliases" : { },
"mappings" : {
"properties" : {
"age" : {
"type" : "long"
},
"name" : {
"type" : "text"
},
"salary" : {
"type" : "double"
}
}
},
"settings" : {
"index" : {
"creation_date_string" : "2024-09-23T04:35:04.528Z",
"routing" : {
"allocation" : {
"include" : {
"_tier_preference" : "data_content"
}
}
},
"number_of_shards" : "3",
"provided_name" : "user",
"creation_date" : "1727066104528",
"number_of_replicas" : "2",
"uuid" : "AvhhuqV2ShGkRP9z7XbdDA",
"version" : {
"created_string" : "8.14.4-snapshot[8512000]",
"created" : "8512000"
}
}
}
}
}การวิเคราะห์
วิเคราะห์สตริงข้อความสำหรับดัชนีที่ระบุ และส่งคืนผลลัพธ์ ข้อความดังนี้
{
"analyzer": "standard",
"text": ["this is a test", "the second text"]
}โค้ด
func main() {
client, err := newClient()
if err != nil {
panic(err)
}
analyze := client.Indices.Analyze
dsl := bytes.NewBufferString(`{
"analyzer" : "standard",
"text" : ["this is a test", "the second text"]
}`)
response, err := analyze(analyze.WithIndex("user"), analyze.WithBody(dsl), analyze.WithPretty(), analyze.WithHuman())
if err != nil {
panic(err)
}
fmt.Println(response)
}ผลลัพธ์
[200 OK] {
"tokens" : [
{
"token" : "this",
"start_offset" : 0,
"end_offset" : 4,
"type" : "<ALPHANUM>",
"position" : 0
},
{
"token" : "is",
"start_offset" : 5,
"end_offset" : 7,
"type" : "<ALPHANUM>",
"position" : 1
},
{
"token" : "a",
"start_offset" : 8,
"end_offset" : 9,
"type" : "<ALPHANUM>",
"position" : 2
},
{
"token" : "test",
"start_offset" : 10,
"end_offset" : 14,
"type" : "<ALPHANUM>",
"position" : 3
},
{
"token" : "the",
"start_offset" : 15,
"end_offset" : 18,
"type" : "<ALPHANUM>",
"position" : 104
},
{
"token" : "second",
"start_offset" : 19,
"end_offset" : 25,
"type" : "<ALPHANUM>",
"position" : 105
},
{
"token" : "text",
"start_offset" : 26,
"end_offset" : 30,
"type" : "<ALPHANUM>",
"position" : 106
}
]
}การลบ
ลบดัชนีที่ระบุหลายดัชนี
func main() {
client, err := newClient()
if err != nil {
panic(err)
}
indicesDelete := client.Indices.Delete
response, err := indicesDelete([]string{"user"})
if err != nil {
panic(err)
}
fmt.Println(response)
}ผลลัพธ์
[200 OK] {"acknowledged":true}ใน API เหล่านี้ คุณจะเห็นว่าร่างกายของคำขอต้องถูกทำให้เป็นอนุกรมด้วยตนเอง ทางการไม่ได้แมปเป็นโครงสร้าง Go และร่างกายการตอบสนองก็ต้องถูกจัดการด้วยตนเองเช่นกัน เหล่านี้เป็น API ที่ใช้บ่อยที่สุด API อื่นๆ ใช้งานไม่แตกต่างกันมาก
เอกสาร
การสร้าง
สร้างเอกสารดังนี้
{
"name": "jack",
"age": 12,
"salary": 5701.1
}โค้ด
func main() {
client, err := newClient()
if err != nil {
panic(err)
}
doc := bytes.NewBufferString(`{
"name": "jack",
"age": 12,
"salary": 5701.1
}`)
create := client.Create
response, err := create("user", "1", doc, create.WithPretty())
if err != nil {
panic(err)
}
fmt.Println(response)
}ผลลัพธ์
[201 Created] {
"_index" : "user",
"_id" : "1",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 3,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1
}การดึง
ดึงเอกสารที่มี ID ที่ระบุ
func main() {
client, err := newClient()
if err != nil {
panic(err)
}
get := client.Get
response, err := get("user", "1", get.WithPretty())
if err != nil {
panic(err)
}
fmt.Println(response)
}ผลลัพธ์
[200 OK] {
"_index" : "user",
"_id" : "1",
"_version" : 1,
"_seq_no" : 0,
"_primary_term" : 1,
"found" : true,
"_source" : {
"name" : "jack",
"age" : 12,
"salary" : 5701.1
}
}การอัปเดต
อัปเดตเนื้อหาเอกสาร
{
"doc": {
"name": "jack",
"age": 35,
"salary": 5701.1
}
}โค้ด
func main() {
client, err := newClient()
if err != nil {
panic(err)
}
doc := bytes.NewBufferString(`{
"doc": { "name": "jack",
"age": 35,
"salary": 5701.1
}}`)
update := client.Update
response, err := update("user", "1", doc, update.WithPretty())
if err != nil {
panic(err)
}
fmt.Println(response)
}ผลลัพธ์
[200 OK] {
"_index" : "user",
"_id" : "1",
"_version" : 2,
"result" : "updated",
"_shards" : {
"total" : 3,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 1,
"_primary_term" : 1
}Update API ยังรองรับการดำเนินการเช่น upsert ด้วย script ไปที่ Update API เพื่อเรียนรู้เพิ่มเติม
การลบ
ลบเอกสารที่ระบุด้วย ID
func main() {
client, err := newClient()
if err != nil {
panic(err)
}
deleteDoc := client.Delete
response, err := deleteDoc("user", "1", deleteDoc.WithPretty())
if err != nil {
panic(err)
}
fmt.Println(response)
}ผลลัพธ์
[200 OK] {
"_index" : "user",
"_id" : "1",
"_version" : 3,
"result" : "deleted",
"_shards" : {
"total" : 3,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 2,
"_primary_term" : 1
}การค้นหา
API ที่ใช้บ่อยที่สุดของ ES คือ search API ด้านล่างนี้จะสาธิตการใช้งานอย่างง่าย เตรียมข้อมูลก่อน
func main() {
client, err := newClient()
if err != nil {
panic(err)
}
for i := range 10 {
doc := bytes.NewBufferString(fmt.Sprintf(`{
"name": "%s",
"age": %d,
"salary": %f
}`, randomName(), rand.Intn(18)+18, rand.Float64()))
create := client.Create
response, err := create("user", string('0'+i), doc, create.WithPretty())
if err != nil {
panic(err)
}
fmt.Println(response)
}
}
func randomName() string {
var b []byte
for range 10 {
b = append(b, byte(rand.Intn(26)+'a'))
}
return string(b)
}Search API ใช้งานเหมือนกับ HTTP API ทั่วไป
ค้นหาเอกสารทั้งหมด
func main() {
client, err := newClient()
if err != nil {
panic(err)
}
dsl := bytes.NewBufferString(`{"query": {"match_all":{}}, "size": 1}`)
search := client.Search
response, err := search(search.WithBody(dsl), search.WithPretty())
if err != nil {
panic(err)
}
fmt.Println(response)
}จับคู่ฟิลด์ใดฟิลด์หนึ่ง
func main() {
client, err := newClient()
if err != nil {
panic(err)
}
dsl := bytes.NewBufferString(`{"query": {"term":{ "age": 22 } }, "size": 1}`)
search := client.Search
response, err := search(search.WithBody(dsl), search.WithPretty())
if err != nil {
panic(err)
}
fmt.Println(response)
}สรุป
การดำเนินการพื้นฐานมีเพียงเท่านี้ ใช้งานเหมือนกับ HTTP API เมื่อคุณเรียนรู้ ES แล้ว การจัดการ Go API จะไม่มีปัญหา เช่น การดำเนินการขั้นสูงเช่น cluster, data stream และ API อื่นๆ โปรดสำรวจด้วยตนเอง
