Skip to content

ElasticSearch

เว็บไซต์ทางการ: Elasticsearch: เครื่องมือค้นหาและวิเคราะห์แบบกระจาย | Elastic

Elasticsearch เป็นเครื่องมือค้นหาและวิเคราะห์ข้อมูลแบบกระจาย RESTful ที่สามารถจัดการกับกรณีการใช้งานต่างๆ ที่เกิดขึ้นอย่างต่อเนื่อง ในฐานะหัวใจหลักของ Elastic Stack, Elasticsearch จะจัดเก็บข้อมูลของคุณไว้ที่ส่วนกลาง ทำให้คุณสามารถค้นหาได้รวดเร็ว ปรับแต่งความเกี่ยวข้อง วิเคราะห์อย่างทรงพลัง และปรับขนาดได้อย่างง่ายดาย บทความนี้จะอธิบายวิธีการดำเนินการพื้นฐานบางอย่างกับ Elasticsearch ด้วย Go เช่น การเพิ่ม ลบ แก้ไข และค้นหา หากคุณไม่คุ้นเคยกับ Elasticsearch โปรดศึกษาด้วยตนเองก่อน

การติดตั้ง

ดาวน์โหลดไลบรารีทางการ

bash
$ github.com/elastic/go-elasticsearch/v7

หากคุณใช้ ES8 ให้เปลี่ยนเวอร์ชัน

bash
$ github.com/elastic/go-elasticsearch/v8

TIP

บทความนี้ใช้ ES8 เพื่อสาธิต

การเชื่อมต่อ

ใช้ฟังก์ชัน elasticsearch.NewClient เพื่อสร้างการเชื่อมต่อใหม่

go
func NewClient(cfg Config) (*Client, error)

ES8+ ใช้การเชื่อมต่อ HTTPS เป็นค่าเริ่มต้น เมื่อสร้างการเชื่อมต่อ HTTPS คุณสามารถใช้ใบรับรอง CA หรือลายนิ้วมือ CA ซึ่งทั้งสองอย่างสร้างขึ้นบนเซิร์ฟเวอร์ Elasticsearch ตัวอย่างดังนี้

go
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

go
pingResp, err := client.Ping(client.Ping.WithPretty(), client.Ping.WithHuman())
if err != nil {
    panic(err)
}
fmt.Println(pingResp)

ผลลัพธ์

[200 OK]

หรือตรวจสอบสถานะบริการผ่าน Info API

go
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

go
// Indices contains the Indices APIs
type Indices struct {
    AddBlock              IndicesAddBlock
    Analyze               IndicesAnalyze
    ClearCache            IndicesClearCache
    Clone                 IndicesClone
    Close                 IndicesClose
    ...
    ...
  ValidateQuery         IndicesValidateQuery
}

การสร้าง

สร้างดัชนี ดังนี้

json
{
  "settings": {
    "number_of_shards": 3,
    "number_of_replicas": 2
  },
  "mappings": {
    "properties": {
      "name": {
        "type": "text"
      },
      "age": {
        "type": "long"
      },
      "salary": {
        "type": "double"
      }
    }
  }
}

การดำเนินการจริง คล้ายกับการส่งคำขอ HTTP

go
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)
}

ผลลัพธ์

json
[200 OK] {"acknowledged":true,"shards_acknowledged":true,"index":"user"}

การดึง

ดึงข้อมูลดัชนีหลายดัชนี

go
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)
}

ผลลัพธ์

json
[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"
        }
      }
    }
  }
}

การวิเคราะห์

วิเคราะห์สตริงข้อความสำหรับดัชนีที่ระบุ และส่งคืนผลลัพธ์ ข้อความดังนี้

json
{
  "analyzer": "standard",
  "text": ["this is a test", "the second text"]
}

โค้ด

go
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)
}

ผลลัพธ์

json
[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
    }
  ]
}

การลบ

ลบดัชนีที่ระบุหลายดัชนี

go
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)
}

ผลลัพธ์

json
[200 OK] {"acknowledged":true}

ใน API เหล่านี้ คุณจะเห็นว่าร่างกายของคำขอต้องถูกทำให้เป็นอนุกรมด้วยตนเอง ทางการไม่ได้แมปเป็นโครงสร้าง Go และร่างกายการตอบสนองก็ต้องถูกจัดการด้วยตนเองเช่นกัน เหล่านี้เป็น API ที่ใช้บ่อยที่สุด API อื่นๆ ใช้งานไม่แตกต่างกันมาก

เอกสาร

การสร้าง

สร้างเอกสารดังนี้

json
{
  "name": "jack",
  "age": 12,
  "salary": 5701.1
}

โค้ด

go
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)
}

ผลลัพธ์

json
[201 Created] {
  "_index" : "user",
  "_id" : "1",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 3,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 0,
  "_primary_term" : 1
}

การดึง

ดึงเอกสารที่มี ID ที่ระบุ

go
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)
}

ผลลัพธ์

json
[200 OK] {
  "_index" : "user",
  "_id" : "1",
  "_version" : 1,
  "_seq_no" : 0,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "name" : "jack",
    "age" : 12,
    "salary" : 5701.1
  }
}

การอัปเดต

อัปเดตเนื้อหาเอกสาร

json
{
  "doc": {
    "name": "jack",
    "age": 35,
    "salary": 5701.1
  }
}

โค้ด

go
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)
}

ผลลัพธ์

json
[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

go
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)
}

ผลลัพธ์

json
[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 ด้านล่างนี้จะสาธิตการใช้งานอย่างง่าย เตรียมข้อมูลก่อน

go
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 ทั่วไป

ค้นหาเอกสารทั้งหมด

go
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)
}

จับคู่ฟิลด์ใดฟิลด์หนึ่ง

go
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 อื่นๆ โปรดสำรวจด้วยตนเอง

Golang by www.golangdev.cn edit