Elasticsearch upsert

413 阅读1分钟

Elasticsearch 数据处理:upsert

Elasticsearch 插入数据,中间由于网络等问题,有可能会使数据重复上报,就需要执行upsert(存在就更新,不存在就插入)的操作。

type AppFlow struct {
    OpTime  int64  `json:"opTime"`  // 操作时间
    UserId  string `json:"userId"`  // 用户id
    App     string `json:"app"`     // app
    Flow    int64  `json:"flow"`    // 流量
    Channel string `json:"channel"` // 渠道
}

eg:在上面结构中需要实现upsert就需要设置一个类似于mysql 的唯一索引,检查重复。Elasticsearch 中又没有设置唯一索引的操作。所以在往Elasticsearch 插入数据的时候,需要加一个_id字段做唯一索引

func (e *AppFlow) GetId() string {
   return fmt.Sprintf("%d_%s_%s_%s", e.OpTime, e.UserId, e.App, e.Channel)
}

在插入数据的时候指定id,Elasticsearch 就会根据id执行upsert操作

func (e *AppFlow) EsAddBulk(ctx context.Context, data []*AppFlow) error {
    idx := "index_name"
    bulkRequest := getESClient().Bulk()
    for _, v := range data {
        tmp := v
        req := elastic.NewBulkIndexRequest().Index(idx).Id(v.GetId()).Doc(tmp)
        bulkRequest = bulkRequest.Add(req)
    }
    bulkResponse, err := bulkRequest.Do(ctx)
    if err != nil {
        log.print("Error app flow bulk insert: %s", err)
        return err
    }
    // 检查批量响应的错误
    if bulkResponse.Errors {
        for _, item := range bulkResponse.Items {
            for action, result := range item {
                if result.Error != nil {
                    log.print("Failed to %s document: %s", action, result.Error.Reason)
                }
            }
        }
    }
    return err
}