ElasticSearch
Trang web chính thức: Elasticsearch: Công cụ tìm kiếm và phân tích phân tán chính thức | Elastic
Elasticsearch là một công cụ tìm kiếm và phân tích dữ liệu phân tán theo phong cách RESTful, có khả năng giải quyết nhiều trường hợp sử dụng khác nhau. Là trung tâm của Elastic Stack, Elasticsearch lưu trữ tập trung dữ liệu của bạn, cho phép bạn tìm kiếm nhanh chóng, tinh chỉnh mức độ liên quan, thực hiện phân tích mạnh mẽ và dễ dàng mở rộng quy mô. Bài viết này sẽ giải thích cách thực hiện một số thao tác cơ bản với Elasticsearch bằng Go, chẳng hạn như thêm, xóa, sửa, truy vấn, v.v. Nếu bạn không quen thuộc với Elasticsearch, vui lòng tự học trước.
Phụ thuộc
Tải xuống thư viện chính thức
$ github.com/elastic/go-elasticsearch/v7Nếu bạn sử dụng ES8, hãy thay đổi phiên bản
$ github.com/elastic/go-elasticsearch/v8TIP
Bài viết này sử dụng ES8 để minh họa
Kết nối
Sử dụng hàm elasticsearch.NewClient để thiết lập kết nối mới
func NewClient(cfg Config) (*Client, error)ES8+ mặc định sử dụng kết nối HTTPS. Khi thiết lập kết nối HTTPS, bạn có thể sử dụng chứng chỉ CA hoặc dấu vân tay CA, cả hai đều được tạo từ phía máy chủ Elasticsearch. Ví dụ như sau
client, err := elasticsearch.NewClient(elasticsearch.Config{
Addresses: []string{"https://192.168.153.132:9200"},
Username: "elastic",
Password: "TETJ8IY+ifbt8SLc+RRQ",
CertificateFingerprint: "C0E9867C7D446BFF72FE46E7E9FE3455E970A8ADB0D3DF0E1472D55DB2612CD5",
})Go API do elasticsearch cung cấp về cơ bản đều là các hàm tùy chọn, ví dụ kiểm tra dịch vụ có khả dụng hay không thông qua ping API
pingResp, err := client.Ping(client.Ping.WithPretty(), client.Ping.WithHuman())
if err != nil {
panic(err)
}
fmt.Println(pingResp)Đầu ra
[200 OK]Ví dụ khác, kiểm tra trạng thái dịch vụ thông qua Info API
infoResp, err := client.Info(client.Info.WithHuman())
if err != nil {
panic(err)
}
fmt.Println(infoResp)Đầu ra
[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
Về bất kỳ câu hỏi nào liên quan đến ES API, vui lòng tham khảo tài liệu chính thức ES Restful API.
Chỉ mục
Thao tác chỉ mục thông qua go api, tất cả API thao tác chỉ mục đều nằm trong cấu trúc esapi.Indices
// Indices contains the Indices APIs
type Indices struct {
AddBlock IndicesAddBlock
Analyze IndicesAnalyze
ClearCache IndicesClearCache
Clone IndicesClone
Close IndicesClose
...
...
ValidateQuery IndicesValidateQuery
}Tạo
Tạo một chỉ mục như sau
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 2
},
"mappings": {
"properties": {
"name": {
"type": "text"
},
"age": {
"type": "long"
},
"salary": {
"type": "double"
}
}
}
}Thao tác thực tế giống như gửi yêu cầu 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)
}Đầu ra
[200 OK] {"acknowledged":true,"shards_acknowledged":true,"index":"user"}Lấy
Lấy thông tin của một số chỉ mục
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)
}Đầu ra
[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"
}
}
}
}
}Phân tích
Phân tích chuỗi văn bản đối với chỉ mục được chỉ định và trả về kết quả, văn bản như sau
{
"analyzer": "standard",
"text": ["this is a test", "the second text"]
}Mã nguồn
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)
}Đầu ra
[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
}
]
}Xóa
Xóa một số chỉ mục được chỉ định
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)
}Đầu ra
[200 OK] {"acknowledged":true}Trong các API trên, có thể thấy rằng phần thân yêu cầu cần được tuần tự hóa thủ công,官方 không ánh xạ thành cấu trúc Go và phần thân phản hồi cũng cần được xử lý thủ công. Đây là những API thường dùng, các API khác đều tương tự, không có sự khác biệt quá lớn.
Tài liệu
Tạo
Tạo một tài liệu như sau
{
"name": "jack",
"age": 12,
"salary": 5701.1
}Mã nguồn
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)
}Đầu ra
[201 Created] {
"_index" : "user",
"_id" : "1",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 3,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1
}Lấy
Lấy một tài liệu với ID được chỉ định
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)
}Đầu ra
[200 OK] {
"_index" : "user",
"_id" : "1",
"_version" : 1,
"_seq_no" : 0,
"_primary_term" : 1,
"found" : true,
"_source" : {
"name" : "jack",
"age" : 12,
"salary" : 5701.1
}
}Cập nhật
Cập nhật nội dung tài liệu
{
"doc": {
"name": "jack",
"age": 35,
"salary": 5701.1
}
}Mã nguồn
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)
}Đầu ra
[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 còn hỗ trợ các thao tác như upsert thông qua script, truy cập Update API để biết thêm thông tin.
Xóa
Xóa một tài liệu được chỉ định theo 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)
}Đầu ra
[200 OK] {
"_index" : "user",
"_id" : "1",
"_version" : 3,
"result" : "deleted",
"_shards" : {
"total" : 3,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 2,
"_primary_term" : 1
}Tìm kiếm
API được sử dụng phổ biến nhất trong ES API là search API. Dưới đây sẽ trình diễn cách sử dụng đơn giản, trước tiên cần chuẩn bị dữ liệu.
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 hoạt động hoàn toàn giống như HTTP API thông thường.
Truy vấn tất cả tài liệu
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)
}Khớp một trường
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)
}Tổng kết
Các thao tác cơ bản gần như là những nội dung trên, cách sử dụng hoàn toàn giống với HTTP API. Khi đã thành thạo ES, việc thao tác với Go API hoàn toàn không có vấn đề gì. Đối với một số thao tác nâng cao như cluster, data stream và các API khác, vui lòng tự khám phá.
