Elasticsearch 的 easyjson 示例

Posted thepoy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Elasticsearch 的 easyjson 示例相关的知识,希望对你有一定的参考价值。

mailru/easyjson库的特点就是我们只需要提供结构体,然后用这些结构体生成编码解码的代码。

示例的项目名为elasticsearch/encoding/json

一、创建 models

在项目中新建 model 目录,目录中新建两个文件model.goresponse.go,在这两个文件头都添加一行代码生成注释:

//go:generate easyjson -all -snake_case $GOFILE
  • //后不能有空格

models.go:

//go:generate easyjson -all -snake_case $GOFILE

package model

import (
    "time"
)

type Article struct {
    ID        uint
    Title     string
    Body      string
    Published time.Time
    Author    *Author
}

type Author struct {
    FirstName string
    LastName  string
}

response.go:

//go:generate easyjson -all -snake_case $GOFILE

package model

type ErrorResponse struct {
    Info *ErrorInfo `json:"error,omitempty"`
}

type ErrorInfo struct {
    RootCause []*ErrorInfo
    Type      string
    Reason    string
    Phase     string
}

type IndexResponse struct {
    Index   string `json:"_index"`
    ID      string `json:"_id"`
    Version int    `json:"_version"`
    Result  string
}

type SearchResponse struct {
    Took int64
    Hits struct {
        Total struct {
            Value int64
        }
        Hits []*SearchHit
    }
}

type SearchHit struct {
    Score   float64 `json:"_score"`
    Index   string  `json:"_index"`
    Type    string  `json:"_type"`
    Version int64   `json:"_version,omitempty"`

    Source Article `json:"_source"`
}

二、完善主逻辑代码

main.go:

package main

import (
    "bytes"
    "elasticsearch/encoding/json/model"
    "fmt"
    "math/rand"
    "os"
    "strconv"
    "strings"
    "time"

    "github.com/elastic/go-elasticsearch/v8"
    "github.com/elastic/go-elasticsearch/v8/esapi"
    "github.com/fatih/color"
    "github.com/mailru/easyjson"
)

var (
    out       = color.New(color.Reset)
    faint     = color.New(color.Faint)
    bold      = color.New(color.Bold)
    red       = color.New(color.FgRed)
    boldGreen = color.New(color.Bold, color.FgGreen)
    boldRed   = color.New(color.Bold, color.FgRed)

    articles []model.Article
    fnames   []string
)

func init() {
    rand.Seed(time.Now().UnixNano())
}

func main() {
    es, err := elasticsearch.NewDefaultClient()
    if err != nil {
        fmt.Printf("Error creating the client: %s\\n", err)
        os.Exit(2)
    }

    fnames = []string{"Alice", "John", "Mary"}

    for i, title := range []string{"One", "Two", "Three", "Four", "Five"} {
        articles = append(articles,
            model.Article{
                ID:        uint(i + 1),
                Title:     "Test" + title,
                Body:      "Lorem ipsum dolor sit amet, consectetur adipisicing elit",
                Published: time.Now().AddDate(i, 0, 0),
                Author: &model.Author{
                    FirstName: fnames[rand.Intn(len(fnames))],
                    LastName:  "Smith",
                },
            })
    }

    faint.Println("Indexing articles...")
    faint.Println(strings.Repeat("━", 80))

    var b bytes.Buffer
    for _, a := range articles {
        b.Reset()

        // 将 article 结构体序列化为 json,json 保存到 buffer 中
        if _, err := easyjson.MarshalToWriter(a, &b); err != nil {
            red.Println("Error decoding response", err)
            continue
        }

        res, err := es.Index(
            "articles",
            bytes.NewReader(b.Bytes()),
            es.Index.WithDocumentID(strconv.Itoa(int(a.ID))),
            // es.Index.WithVersion(-1), // <-- 取消此注释来触发异常
        )
        if err != nil {
            red.Printf("Error indexing article: %s\\n", err)
            continue
        }
        defer res.Body.Close()

        if res.IsError() {
            printErrorResponse(res)
            os.Exit(2)
        }

        var ir model.IndexResponse
        if err := easyjson.UnmarshalFromReader(res.Body, &ir); err != nil {
            red.Println("Error decoding response", err)
            continue
        }

        boldGreen.Printf("[%s] ", res.Status())
        fmt.Println(
            faint.Sprint("result=")+out.Sprint(ir.Result),
            faint.Sprint("index=")+out.Sprint(ir.Index),
            faint.Sprint("ID=")+out.Sprint(ir.ID),
            faint.Sprint("version=")+out.Sprint(ir.Version),
        )

    }

    es.Indices.Refresh(es.Indices.Refresh.WithIndex("articles"))

    faint.Println("\\nSearching articles...")
    faint.Println(strings.Repeat("━", 80))

    res, err := es.Search(
        es.Search.WithIndex("articles"),
        es.Search.WithQuery("one OR two"),
        // es.Search.WithQuery("{{{one OR two"), // <-- 取消此注释来触发异常
    )
    if err != nil {
        red.Printf("Error searching articles: %s\\n", err)
        os.Exit(2)
    }
    defer res.Body.Close()

    if res.IsError() {
        printErrorResponse(res)
        os.Exit(2)
    }

    var sr model.SearchResponse
    if err := easyjson.UnmarshalFromReader(res.Body, &sr); err != nil {
        red.Println("Error decoding response", err)
        os.Exit(2)
    }

    faint.Printf("[%s] took=%d total=%d\\n", res.Status(), sr.Took, sr.Hits.Total.Value)
    faint.Println(strings.Repeat("─", 80))

    for _, h := range sr.Hits.Hits {
        fmt.Println(
            out.Sprintf("%s,", strings.Join([]string{h.Source.Author.FirstName, h.Source.Author.LastName}, " ")),
            bold.Sprintf("%s", h.Source.Title),
            out.Sprintf("(%d)", h.Source.Published.Year()),
        )
        faint.Println(strings.Repeat("─", 80))
    }
}

// printErrorResponse 解码 es 响应,格式化后打印到终端
func printErrorResponse(res *esapi.Response) {
    bold.Printf("[%s] ", res.Status())

    var e model.ErrorResponse
    if err := easyjson.UnmarshalFromReader(res.Body, &e); err != nil {
        red.Println("Error decoding response:", err)
        return
    }
    boldRed.Print(e.Info.RootCause[0].Type)
    faint.Print(" > ")
    fmt.Println(e.Info.RootCause[0].Reason)
}

三、生成代码

拉取项目中需要的库:

go mod tidy

生成代码:

go generate ./model

之后,model 目录中会多出两个文件:model_easyjson.goresponse_easyjson.go

这两个文件中的代码为 model 中的结构体完成了mailru/easyjson规定的一些接口。

四、运行项目

go run main.go
Indexing articles...
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[200 OK] result=updated index=articles ID=1 version=36
[200 OK] result=updated index=articles ID=2 version=34
[200 OK] result=updated index=articles ID=3 version=34
[200 OK] result=updated index=articles ID=4 version=34
[200 OK] result=updated index=articles ID=5 version=34

Searching articles...
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[200 OK] took=2 total=0
────────────────────────────────────────────────────────────────────────────────

以上是关于Elasticsearch 的 easyjson 示例的主要内容,如果未能解决你的问题,请参考以下文章

EasyJson 发布

Golang ---json解析

golang 构建工具之 Makefile

ajax传对象或者数组到后端

Go 标准库 encoding/json 真的慢吗?

「必备技能」Elasticsearch索引全生命周期管理(附代码)