quick start

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
package elastic

import (
"context"
"encoding/json"
"fmt"
"github.com/olivere/elastic/v7"
"reflect"
"time"
)

type User struct {
Name string `json:"name"`
Age int `json:"age"`
Married bool `json:"married"`
Sex string `json:"sex"`
Created time.Time `json:"created,omitempty"`
Tags []string `json:"tags,omitempty"`
Location string `json:"location,omitempty"`
Suggest *elastic.SuggestField `json:"suggest_field,omitempty"`
}

// 定义一些变量,mapping为定制的index字段类型
const mapping = `
{
"settings":{
"number_of_shards": 1,
"number_of_replicas": 0
},
"mappings":{
"properties":{
"name":{
"type":"text"
},
"age":{
"type":"long"
},
"married":{
"type":"boolean"
},
"created":{
"type":"date"
},
"tags":{
"type":"keyword"
},
"location":{
"type":"geo_point"
},
"suggest_field":{
"type":"completion"
}
}
}
}`

const mapping1 = `
{
"properties": {
"sex": {
"type": "text"
}
}
}
}`

var ctx = context.Background()
var esUrl string = "http://192.168.1.109:9200"

func main() {
// 连接客户端
// Sniff 参数为 true, 创建的客户端会去嗅探整个集群,此动作会使用内网 IP 通信,导致无法连接到 ES 服务器,这里设置为 false。
client, err := elastic.NewClient(elastic.SetURL(esUrl), elastic.SetSniff(false))
if err != nil {
panic(err)
}

// ping通服务端,并获得服务端的es版本,本实例的es版本为version 7.6.1
info, code, err := client.Ping(esUrl).Do(ctx)
if err != nil {
panic(err)
}
fmt.Printf("Elasticsearch returned with code>: %d and version %s\n", code, info.Version.Number)

// 获取版本号的直接API
esVersion, err := client.ElasticsearchVersion(esUrl)
if err != nil {
panic(err)
}
fmt.Printf("es的版本为%s\n", esVersion)

// 创建index
// 创建index前,先查看es引擎中是否存在自己想要创建的索引index
exists, err := client.IndexExists("user").Do(ctx)
if err != nil {
panic(err)
}
if !exists {
// 如果不存在,就创建
createIndex, err := client.CreateIndex("user").BodyString(mapping1).Do(ctx)
if err != nil {
// Handle error
panic(err)
}
if !createIndex.Acknowledged {
// Not acknowledged ,创建失败
}
}

// 为已有的索引添加字段
_, err = client.PutMapping().Index("user").BodyString(mapping1).Do(ctx)
if err != nil {
panic(err)
}

// 添加文档方法1
user1 := User{Name: "bob", Sex: "male", Married: false, Age: 23}
put1, err := client.Index().Index("user").BodyJson(user1).Id("1").Do(ctx)
if err != nil {
panic(err)
}
fmt.Printf("Indexed user %s to index %s, type %s\n", put1.Id, put1.Index, put1.Type) //Indexed user 1 to index user, type _doc

// 添加文档方法2
user2 := `{"name":"mike","sex":"male","married":true,"age":"22"}`
put2, err := client.Index().Index("user").BodyString(user2).Do(ctx) // 不指定id
if err != nil {
panic(err)
}
fmt.Printf("Indexed user %s to index %s, type %s\n", put2.Id, put2.Index, put2.Type) //Indexed user 4-K2wXIB33YuyEzPYoAi to index user, type _doc

// 查询
get1, err := client.Get().Index("user").Id("1").Do(ctx)
if err != nil {
panic(err)
}
if get1.Found {
fmt.Printf("Got document %s in version %d from index %s, type %s\n", get1.Id, get1.Version, get1.Index, get1.Type)
}

// Flush to make sure the documents got written.将文档刷入磁盘
_, err = client.Flush().Index("user").Do(ctx)
if err != nil {
panic(err)
}

// 按"term"搜索Search with a term query
termQuery := elastic.NewTermQuery("name", "mike")
searchResult, err := client.Search().
Index("user"). // 搜索的索引"user"
Query(termQuery). // specify the query
Sort("age", true). //按字段"age"排序,升序排列
From(0).Size(10). // 分页,单页显示10条
Pretty(true). // pretty print request and response JSON以json的形式返回信息
Do(ctx) // 执行
if err != nil {
panic(err)
}
fmt.Printf("Query took %d milliseconds\n", searchResult.TookInMillis) // Query took 3 milliseconds

var user User
// Each是一个简便函数,此函数忽略了错误输出
for _, item1 := range searchResult.Each(reflect.TypeOf(user)) {
if u, ok := item1.(User); ok {
fmt.Printf("Person by %s,age:%d,married:%t,Sex:%s\n", u.Name, u.Age, u.Married, u.Sex) //Person by bob,age:23,married:false,Sex:male
}
}

// 搜索文档方法2
// 使用hits,获得更详细的输出结果
if searchResult.Hits.TotalHits.Value > 0 {
fmt.Printf("找到的数据总数是 %d \n", searchResult.Hits.TotalHits.Value)
for _, hits := range searchResult.Hits.Hits {
u := User{}
err := json.Unmarshal([]byte(hits.Source), &u)
if err != nil {
fmt.Println("反序列化失败", err)
}
fmt.Printf("User by %s,age:%d,married:%t,Sex:%s\n", u.Name, u.Age, u.Married, u.Sex)
}
} else {
fmt.Println("没有搜到用户")
}

// 更新文档 update
update, err := client.Update().Index("user").Id("1").
Script(elastic.NewScriptInline("ctx._source.age += params.num").Lang("painless").Param("num", 1)).
Upsert(map[string]interface{}{"created": "2020-06-17"}). // 插入未初始化的字段value
Do(ctx)
if err != nil {
panic(err)
}
fmt.Printf("New version of user %q is now %d\n", update.Id, update.Version)

// 删除文档
termQuery = elastic.NewTermQuery("name", "mike")
_, err = client.DeleteByQuery().Index("user"). // search in index "user"
Query(termQuery). // specify the query
Do(ctx)
if err != nil {
panic(err)
}
}

quick start2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
package elastic

import (
"context"
"fmt"
"github.com/olivere/elastic/v7"
"log"
"os"
"reflect"
)

var client *elastic.Client
var host = "http://127.0.0.1:9200/"

type Employee struct {
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Age int `json:"age"`
About string `json:"about"`
Interests []string `json:"interests"`
}

//初始化
func init() {
errorlog := log.New(os.Stdout, "APP", log.LstdFlags)
var err error
client, err = elastic.NewClient(elastic.SetErrorLog(errorlog), elastic.SetURL(host))
if err != nil {
panic(err)
}
info, code, err := client.Ping(host).Do(context.Background())
if err != nil {
panic(err)
}
fmt.Printf("Elasticsearch returned with code %d and version %s\n", code, info.Version.Number)

esversion, err := client.ElasticsearchVersion(host)
if err != nil {
panic(err)
}
fmt.Printf("Elasticsearch version %s\n", esversion)

}

/*下面是简单的CURD*/

//创建
func create() {
//使用结构体
e1 := Employee{"Jane", "Smith", 32, "I like to collect rock albums", []string{"music"}}
put1, err := client.Index().
Index("megacorp").
Type("employee").
Id("1").
BodyJson(e1).
Do(context.Background())
if err != nil {
panic(err)
}
fmt.Printf("Indexed tweet %s to index s%s, type %s\n", put1.Id, put1.Index, put1.Type)

//使用字符串
e2 := `{"first_name":"John","last_name":"Smith","age":25,"about":"I love to go rock climbing","interests":["sports","music"]}`
put2, err := client.Index().
Index("megacorp").
Type("employee").
Id("2").
BodyJson(e2).
Do(context.Background())
if err != nil {
panic(err)
}
fmt.Printf("Indexed tweet %s to index s%s, type %s\n", put2.Id, put2.Index, put2.Type)

e3 := `{"first_name":"Douglas","last_name":"Fir","age":35,"about":"I like to build cabinets","interests":["forestry"]}`
put3, err := client.Index().
Index("megacorp").
Type("employee").
Id("3").
BodyJson(e3).
Do(context.Background())
if err != nil {
panic(err)
}
fmt.Printf("Indexed tweet %s to index s%s, type %s\n", put3.Id, put3.Index, put3.Type)

}

//删除
func delete() {
res, err := client.Delete().Index("megacorp").
Type("employee").
Id("1").
Do(context.Background())
if err != nil {
println(err.Error())
return
}
fmt.Printf("delete result %s\n", res.Result)
}

//修改
func update() {
res, err := client.Update().
Index("megacorp").
Type("employee").
Id("2").
Doc(map[string]interface{}{"age": 88}).
Do(context.Background())
if err != nil {
println(err.Error())
}
fmt.Printf("update age %s\n", res.Result)

}

//查找
func gets() {
//通过id查找
get1, err := client.Get().Index("megacorp").Type("employee").Id("2").Do(context.Background())
if err != nil {
panic(err)
}
if get1.Found {
fmt.Printf("Got document %s in version %d from index %s, type %s\n", get1.Id, get1.Version, get1.Index, get1.Type)
}
}

//搜索
func query() {
var res *elastic.SearchResult
var err error
//取所有
res, err = client.Search("megacorp").Type("employee").Do(context.Background())
printEmployee(res, err)

//字段相等
q := elastic.NewQueryStringQuery("last_name:Smith")
res, err = client.Search("megacorp").Type("employee").Query(q).Do(context.Background())
if err != nil {
println(err.Error())
}
printEmployee(res, err)

//条件查询
//年龄大于30岁的
boolQ := elastic.NewBoolQuery()
boolQ.Must(elastic.NewMatchQuery("last_name", "smith"))
boolQ.Filter(elastic.NewRangeQuery("age").Gt(30))
res, err = client.Search("megacorp").Type("employee").Query(q).Do(context.Background())
printEmployee(res, err)

//短语搜索 搜索about字段中有 rock climbing
matchPhraseQuery := elastic.NewMatchPhraseQuery("about", "rock climbing")
res, err = client.Search("megacorp").Type("employee").Query(matchPhraseQuery).Do(context.Background())
printEmployee(res, err)

//分析 interests
aggs := elastic.NewTermsAggregation().Field("interests")
res, err = client.Search("megacorp").Type("employee").Aggregation("all_interests", aggs).Do(context.Background())
printEmployee(res, err)

}

//简单分页
func list(size, page int) {
if size < 0 || page < 1 {
fmt.Printf("param error")
return
}
res, err := client.Search("megacorp").
Type("employee").
Size(size).
From((page - 1) * size).
Do(context.Background())
printEmployee(res, err)

}

//打印查询到的Employee
func printEmployee(res *elastic.SearchResult, err error) {
if err != nil {
print(err.Error())
return
}
var typ Employee
for _, item := range res.Each(reflect.TypeOf(typ)) { //从搜索结果中取数据的方法
t := item.(Employee)
fmt.Printf("%#v\n", t)
}
}

func main() {
create()
delete()
update()
gets()
query()
list(1, 3)
}

查询

精确查询

1
2
3
4
5
// 单值查询
elasticv7.NewTermQuery("key","value")

// 多值查询
elasticv7.NewTermsQuery("key", []string{"value1","value2"}...)

精确查询要注意字符串类型的匹配,若为 text 字段,将匹配失败。可以尝试对 {字段}.keyword 来进行 Term 查询

通配符查询

1
elasticv7.NewWildcardQuery(key, word)

通配符查询通常用于模糊查询,例如 *xxxx*, 等价于 mysql 中的 like % xxxx%

与查询

1
2
query := elasticv7.NewBoolQuery()
query.Must(queries ...)

与查询使用 BoolQuery 的 Must 函数来完成,其参数是类型为 query 的不定参数。当所有 query 均为真时此条件为真,可嵌套。

或查询

1
2
elasticv7.NewWildcardQuery("", "")
query.Should(queries ...)

与 Must 相似。

创建查询服务

1
search := cli.Search().Index(index_name).Query(query)

index_name 是 ES 中的索引,类比 Mysql 相当于表 Table 的概念。query 为查询对象,以上各种查询可相互嵌套形成最终的查询对象。

分页

1
2
search = search.From(10)
search = search.Size(10)

这里 search 中的函数都是链式的,可分行写亦可整行写。

排序

1
search = search.Sort(key,true)

排序的第一参数为排序字段,第二参数为是否正序。

跳过评分计算

1
constantQuery := elasticv7.NewConstantScoreQuery(query)

评分会降低查询的效率,当不需要时可以跳过。