@@ -12,6 +12,7 @@ import (
1212 elasticV6 "github.com/olivere/elastic"
1313 elasticV3 "gopkg.in/olivere/elastic.v3"
1414 elasticV5 "gopkg.in/olivere/elastic.v5"
15+ elasticV7 "gopkg.in/olivere/elastic.v7"
1516
1617 "github.com/qiniu/log"
1718 "github.com/qiniu/pandora-go-sdk/base/reqerr"
@@ -31,11 +32,13 @@ type Sender struct {
3132 host []string
3233 retention int
3334 indexName string
35+ idField string
3436 eType string
3537 eVersion string
3638 elasticV3Client * elasticV3.Client
3739 elasticV5Client * elasticV5.Client
3840 elasticV6Client * elasticV6.Client
41+ elasticV7Client * elasticV7.Client
3942
4043 aliasFields map [string ]string
4144
@@ -73,6 +76,7 @@ func NewSender(conf conf.MapConf) (elasticSender sender.Sender, err error) {
7376 return
7477 }
7578 logkitSendTime , _ := conf .GetBoolOr (KeyLogkitSendTime , true )
79+ idField , _ := conf .GetStringOr (KeyElasticIDField , "" )
7680 eType , _ := conf .GetStringOr (KeyElasticType , defaultType )
7781 name , _ := conf .GetStringOr (KeyName , fmt .Sprintf ("elasticSender:(elasticUrl:%s,index:%s,type:%s)" , host , index , eType ))
7882 fields , _ := conf .GetAliasMapOr (KeyElasticAlias , make (map [string ]string ))
@@ -93,7 +97,24 @@ func NewSender(conf conf.MapConf) (elasticSender sender.Sender, err error) {
9397 var elasticV3Client * elasticV3.Client
9498 var elasticV5Client * elasticV5.Client
9599 var elasticV6Client * elasticV6.Client
100+ var elasticV7Client * elasticV7.Client
96101 switch eVersion {
102+ case ElasticVersion7 :
103+ optFns := []elasticV7.ClientOptionFunc {
104+ elasticV7 .SetSniff (false ),
105+ elasticV7 .SetHealthcheck (false ),
106+ elasticV7 .SetURL (host ... ),
107+ elasticV7 .SetGzip (enableGzip ),
108+ }
109+
110+ if len (authUsername ) > 0 && len (authPassword ) > 0 {
111+ optFns = append (optFns , elasticV7 .SetBasicAuth (authUsername , authPassword ))
112+ }
113+
114+ elasticV7Client , err = elasticV7 .NewClient (optFns ... )
115+ if err != nil {
116+ return nil , err
117+ }
97118 case ElasticVersion6 :
98119 optFns := []elasticV6.ClientOptionFunc {
99120 elasticV6 .SetSniff (false ),
@@ -152,10 +173,12 @@ func NewSender(conf conf.MapConf) (elasticSender sender.Sender, err error) {
152173 name : name ,
153174 host : host ,
154175 indexName : index ,
176+ idField : idField ,
155177 eVersion : eVersion ,
156178 elasticV3Client : elasticV3Client ,
157179 elasticV5Client : elasticV5Client ,
158180 elasticV6Client : elasticV6Client ,
181+ elasticV7Client : elasticV7Client ,
159182 eType : eType ,
160183 aliasFields : fields ,
161184 intervalIndex : i ,
@@ -184,6 +207,78 @@ func (s *Sender) Name() string {
184207// Send ElasticSearchSender
185208func (s * Sender ) Send (datas []Data ) error {
186209 switch s .eVersion {
210+ case ElasticVersion7 :
211+ bulkService := s .elasticV7Client .Bulk ()
212+
213+ makeDoc := true
214+ if len (s .aliasFields ) == 0 {
215+ makeDoc = false
216+ }
217+ var indexName string
218+ for _ , doc := range datas {
219+ //计算索引
220+ indexName = buildIndexName (s .indexName , s .timeZone , s .intervalIndex )
221+ //字段名称替换
222+ if makeDoc {
223+ doc = s .wrapDoc (doc )
224+ }
225+ //添加发送时间
226+ if s .logkitSendTime {
227+ doc [KeySendTime ] = time .Now ().In (s .timeZone ).UnixNano () / 1000000
228+ }
229+ doc2 := doc
230+
231+ request := elasticV7 .NewBulkIndexRequest ().UseEasyJSON (true ).Index (indexName ).Type (s .eType ).Doc (& doc2 )
232+ id , ok := doc [s .idField ].(string )
233+ if ok && id != "" {
234+ request .Id (id )
235+ }
236+ bulkService .Add (request )
237+ }
238+
239+ resp , err := bulkService .Do (context .Background ())
240+ if err != nil {
241+ return err
242+ }
243+
244+ var (
245+ // 查找出失败的操作并回溯对应的数据返回给上层
246+ lastFailedResult * elasticV7.BulkResponseItem
247+ failedDatas = make ([]map [string ]interface {}, len (datas ))
248+ failedDatasIdx = 0
249+ )
250+ for i , item := range resp .Items {
251+ for _ , result := range item {
252+ if ! (result .Status >= 200 && result .Status <= 299 ) {
253+ failedDatas [failedDatasIdx ] = datas [i ]
254+ failedDatasIdx ++
255+ lastFailedResult = result
256+ break // 任一情况的失败都算该条数据整体操作失败,没有必要重复检查
257+ }
258+ }
259+ }
260+ failedDatas = failedDatas [:failedDatasIdx ]
261+ if len (failedDatas ) == 0 {
262+ return nil
263+ }
264+ lastError , err := jsoniter .MarshalToString (lastFailedResult )
265+ if err != nil {
266+ lastError = fmt .Sprintf ("marshal to string failed: %v" , lastFailedResult )
267+ }
268+
269+ return & StatsError {
270+ StatsInfo : StatsInfo {
271+ Success : int64 (len (datas ) - len (failedDatas )),
272+ Errors : int64 (len (failedDatas )),
273+ LastError : lastError ,
274+ },
275+ SendError : reqerr .NewSendError (
276+ fmt .Sprintf ("bulk failed with last error: %s" , lastError ),
277+ failedDatas ,
278+ reqerr .TypeBinaryUnpack ,
279+ ),
280+ }
281+
187282 case ElasticVersion6 :
188283 bulkService := s .elasticV6Client .Bulk ()
189284
@@ -204,7 +299,13 @@ func (s *Sender) Send(datas []Data) error {
204299 doc [KeySendTime ] = time .Now ().In (s .timeZone ).UnixNano () / 1000000
205300 }
206301 doc2 := doc
207- bulkService .Add (elasticV6 .NewBulkIndexRequest ().UseEasyJSON (true ).Index (indexName ).Type (s .eType ).Doc (& doc2 ))
302+
303+ request := elasticV6 .NewBulkIndexRequest ().UseEasyJSON (true ).Index (indexName ).Type (s .eType ).Doc (& doc2 )
304+ id , ok := doc [s .idField ].(string )
305+ if ok && id != "" {
306+ request .Id (id )
307+ }
308+ bulkService .Add (request )
208309 }
209310
210311 resp , err := bulkService .Do (context .Background ())
@@ -270,7 +371,12 @@ func (s *Sender) Send(datas []Data) error {
270371 doc [KeySendTime ] = curTime
271372 }
272373 doc2 := doc
273- bulkService .Add (elasticV5 .NewBulkIndexRequest ().Index (indexName ).Type (s .eType ).Doc (& doc2 ))
374+ request := elasticV5 .NewBulkIndexRequest ().Index (indexName ).Type (s .eType ).Doc (& doc2 )
375+ id , ok := doc [s .idField ].(string )
376+ if ok && id != "" {
377+ request .Id (id )
378+ }
379+ bulkService .Add (request )
274380 }
275381
276382 resp , err := bulkService .Do (context .Background ())
@@ -335,7 +441,12 @@ func (s *Sender) Send(datas []Data) error {
335441 doc [KeySendTime ] = time .Now ().In (s .timeZone ).UnixNano () / 1000000
336442 }
337443 doc2 := doc
338- bulkService .Add (elasticV3 .NewBulkIndexRequest ().Index (indexName ).Type (s .eType ).Doc (& doc2 ))
444+ request := elasticV3 .NewBulkIndexRequest ().Index (indexName ).Type (s .eType ).Doc (& doc2 )
445+ id , ok := doc [s .idField ].(string )
446+ if ok && id != "" {
447+ request .Id (id )
448+ }
449+ bulkService .Add (request )
339450 }
340451
341452 resp , err := bulkService .Do ()
@@ -409,6 +520,9 @@ func (s *Sender) Close() error {
409520 if s .elasticV6Client != nil {
410521 s .elasticV6Client .Stop ()
411522 }
523+ if s .elasticV7Client != nil {
524+ s .elasticV7Client .Stop ()
525+ }
412526 return nil
413527}
414528
0 commit comments