ElasticSearch
Elasticsearch(ES)是一個基於
Lucene構建的開源、分佈式、
RESTful接口的全文搜索引擎。
Elasticsearch還是一個分佈式文檔數據庫,其中每個字段均可被索引,而且每個字段的數據均可被搜索,
ES能夠橫向擴展至數以百計的服務器存儲以及處理**PB**級的數據。可以在極短的時間內存儲、搜索和分析大量的數據。通常作爲具有複雜搜索場景情況下的核心發動機。根據
DB-Engines的排名顯示,
Elasticsearch`是最受歡迎的企業搜索引擎。
go-ealsticsearch
隨着官方客戶端的發佈和逐漸成熟,原來社區維護的客戶端
Typed API
Typed API從簡單開始,到逐步擴展覆蓋更多領域,提升類型安全性和易用性。成爲該客戶端庫的一大特色。
Typed API早在2.19年的V7版本中就出現了,不過一直處於alpha狀態,直到8.7版本,才基本可用。我用的是最新的8.90版,看到TypedApi的介紹,就選擇入坑選擇了。沒想到,還真的坑啊,基本的增刪改還好,稍微複雜的用法只能去找examples和tests代碼,加上自己試驗,連文檔都沒有:(。所以在這裏記錄一下我用到的TypedAPI。
連接EL
var err error
esCfg:=es.Config{
Addresses: []string{"http://192.168.0.134:9200"},
Username: "Username",
Password: "Password",
}
typedClient, err := es.NewTypedClient(esCfg)
if err != nil {
log.Fatal("創建TypedClient失敗",err)
}
//
ctx:=context.TODO()
ok,err:=typedClient.Ping().IsSuccess(ctx)
if err != nil {
log.Fatal("TypedClient ping失敗",err)
}
if !ok{
log.Fatal("connect to EL server fail!")
}else{
log.Println("------- connected success")
}
log.Printf( "EL info: %#v",typedClient.Info)
EL中的實體類
type ElKnowledge struct {
ID int `json:"id"`
KnowledgeID string `json:"knowledge_id"`
Title string `json:"title"`
Author string `json:"author"`
Category string `json:"category"`
Keywords string `json:"keywords"`
Content string `json:"content"`
Images string `json:"images"`
Files string `json:"files"`
DAddAt time.Time `json:"d_add_at"`
AddAt string `json:"add_at"`
Comments string `json:"comments"`
Scores string `json:"scores"`
}
func (me *ElKnowledge) SID() string {
return me.KnowledgeID
}
func (me *ElKnowledge) ToJsonRawMessage() json.RawMessage {
bf, err := json.Marshal(me)
if err != nil {
log.Fatalln("[ElKnowledge.ToJson] fail", err)
}
return bf
}
func (me *ElKnowledge) ToJson() string {
return string(me.ToJsonRawMessage())
}
創建索引
indexName:="myIndex"
var ElKnowledgeTypedMapping *types.TypeMapping = &types.TypeMapping{
Properties: map[string]types.Property{
"id": types.NewIntegerNumberProperty(),
"knowledge_id": types.NewKeywordProperty(),
"title": types.NewTextProperty(),
"category": types.NewTextProperty(),
"author": types.NewTextProperty(),
"keywords": types.NewTextProperty(),
"content": types.NewTextProperty(),
"add_at": types.NewKeywordProperty(),
"images": types.NewTextProperty(),
"files": types.NewTextProperty(),
"d_add_at": types.NewDateProperty(),
"comments": types.NewTextProperty(),
"scores": types.NewTextProperty(),
},
}
//檢查索引是否存在
exists,err := typedClient.Indices.Exists(indexName).IsSuccess(ctx)
if err != nil {
log.Fatalln ("check index exist failed", err.Error())
}
//索引不存在則創建索引
//索引不存在時查詢會報錯,但索引不存在的時候可以直接插入
if !exists {
log.Printf("index %s is not exist, to create", indexName)
cr, err :=typedClient.Indices.Create(indexName).Request(&create.Request{
Mappings: ElKnowledgeTypedMapping,
}).Do(ctx)
if err != nil {
log.Fatal("create index failed", err.Error())
}
log.Println("index creat",cr.Index)
}
新增
func insertKnowledge(doc *ElKnowledge){
sid:=doc.SID()
rr,err:=typedClient.Create(indexName,sid).Request(&doc).Do(context.TODO())
if err!=nil{
log.Fatal(" Insert new doc fail,",err)
}
log.Println(" Insert new doc, result=>",rr.Result.String())
}
按ID查詢
func GetKnowledge(sid string)(doc *ElKnowledge,ok bool){
rr,err:=typedClient.Get(indexName,sid).Do(context.TODO())
if err!=nil{
log.Println("[GetKnowledge] fail",err)
return
}
if !rr.Found {return }
doc,err= ElKnowledgeFromJsonRaw(rr.Source_)
if err!=nil{
return
}
return doc, true
}
修改
func upsertKnowledge(doc *ElKnowledge){
useUpsert:=true
sid:=doc.SID()
js:=doc.ToJson()
rr,err:=typedClient.Update(indexName,sid).Request(&update.Request{
Doc: json.RawMessage(js),
DocAsUpsert: &useUpsert,
}).Do(context.TODO())
if err!=nil{
log.Println("upsert doc fail,",err)
panic(err)
}
log.Println("upserted success, by way=>",rr.Result.String())
}
刪除
func deleteKnowledge(doc *ElKnowledge){
sid:=doc.SID()
rr,err:=typedClient.Delete(indexName,sid).Do(context.TODO())
if err!=nil{
log.Fatal("Delete doc fail",err)
}
log.Println("Deleted, ",rr.Result.String())
}
查詢
func Search(c *gin.Context) {
words:=c.Query("words")
sfrom:=c.Query("from")
ssize:=c.Query("size")
from,_:=strconv.Atoi(sfrom)
size,_:=strconv.Atoi(ssize)
res,err:=typedClient.Search().Index("yhkb").Request(&search.Request{
Query: &types.Query{
Match: map[string]types.MatchQuery{
"all_content": { Query: words, Operator: &operator.And},
},
},
Sort: []types.SortCombinations{
types.SortOptions{
SortOptions: map[string]types.FieldSort{
"add_at":{Order: &sortorder.Desc,},
},
},
},
From: &from,
Size: &size,
}).Do(context.Background())
if err != nil {
msg:=""
if err,ok:=err.(types.ElasticsearchError);ok{
b,_:=json.Marshal(err)
msg=string(b)
}
err=utils.WrapErrorWith(err,"查詢失敗"+msg)
slog.