ElasticSearch是通过暴露HTTP接口来达到操作数据的目的。
字段类型
- Text:用于全文检索,例如博客内容、新闻内容、产品描述等。字段内容会被分析,并且在生成倒排索引之前,字符串会被分词器分成一个个词项。Text 类型的字段不用于排序,并且很少用于聚合。这种字段也被称为 analyzed 字段。
- Keyword:适用于结构化的字段,例如标签、电子邮件地址、手机号码等。这种类型的字段可以用作过滤、排序、聚合等。这种字段也称之为 not-analyzed 字段。
- Binary:用于存储编码为 Base64 的字符串或二进制值。
- Boolean:用于存储 true 或 false。
- Numbers:表示数字类型,可以是整数或浮点数,如 long、integer、short、byte、double、float、half_float、scaled_float
- Date:表示日期类型,可以存储日期和时间信息。
- Object:表示 JSON 对象,可以用于存储复杂的嵌套数据结构。
- Nested:嵌套类型,用于表示对象数组,其中的对象可以具有自己的字段和嵌套对象。
- Array:数组类型,可以包含 0 个或多个值,数组中的数据类型必须相同。
- Range:范围类型,用于表示数字或日期的范围,如integer_range、float_range、long_range、double_range、date_range。
- Token Count:单词计数类型,统计字符串中的单词数量
- IP:IP 地址类型,用于存储和查询 IP 地址,为IPV4的地址
- Geo Point 和 Geo Shape:地理位置类型,用于存储和查询地理位置和空间位置信息。其中geo_point表示经纬点,是地理点的数据类型;goe_shape是多边形的复杂地理形状。
重点:keyword和text的区别!!!
keyword | text | |
---|---|---|
适用场景 | 精确匹配场景,比如搜索用户名/唯一id | 全文搜索场景,比如搜索用户个人签名 |
操作 | 可以进行聚合操作,比如对特定的字段分组、计数 | 支持模糊匹配,支持通配符和正则表达式 |
分词 | 不会分词 | 可以分词,支持定义分析器 |
注:如果字段存储量较大的话,两者都会影响到查询性能
创建索引
索引在es的定义相当于数据库的表,所以创建索引相当于创建表。
使用PUT方法来创建索引,下面的HTTP请求创建了一个名为user_idx的索引,其中mappings里存放的是字段,设置了每个字段的名称和类型,比如email字段是text类型,phone字段是keyword类型,birthday字段是date类型。
curl --location --request PUT 'http://localhost:9200/user_idx' \
--header 'Content-Type: application/json' \
--data '{
"mappings":{
"properties":{
"email":{
"type":"text"
},
"phone":{
"type":"keyword"
},
"birthday":{
"type":"date"
}
}
}
}'
也可以通过settings设置基本设置,如分片数、副本数等,settings里的字段都有默认值。
添加了settings的请求如下:
curl --location --request PUT 'http://localhost:9200/user_1' \
--header 'Content-Type: application/json' \
--data '{
"settings":{
"number_of_shards":3,
"number_of_replicas":2
},
"mappings":{
"properties":{
"email":{
"type":"text"
},
"phone":{
"type":"keyword"
},
"birthday":{
"type":"date"
}
}
}
}'
查询索引
使用GET方法来查询现有索引的定义
curl --location 'http://localhost:9200/user_idx'
返回的是索引的完整定义,创建索引的时候如果有未定义的字段,会赋默认值
创建文档
通过POST方法创建文档,注意URL后面要加上_doc
,表示这是对文档的操作
curl --location 'http://localhost:9200/user_idx/_doc' \
--header 'Content-Type: application/json' \
--data-raw '{
"email":"test222@example.com",
"phone":"1111112222",
"birthday":"2000-01-02"
}'
查询文档
查询类型
- Term Query :精确查询,用于匹配字段中精确的值。
- Match Query:匹配查询,用于全文检索,匹配字段中包含指定文本的内容。
- Range Query:范围查询,用于匹配字段中值在某个指定范围内的文档。
- Bool Query:布尔查询,用于组合多个查询条件,支持AND、OR、NOT等逻辑关系。
- Match Phrase Query:短语匹配查询,根据字段中连续的短语进行查询,适用于需要保持短语顺序的查询
- Wildcard Query:通配符查询,用于匹配字段中包含模糊值的文档。
- Fuzzy Query:模糊查询,用于匹配字段中近似匹配的文本。
- Prefix Query:前缀查询,用于匹配字段中以指定前缀开头的文本。
- Phrase Query:短语匹配查询,用于匹配字段中包含特定短语的文档。
- Multi Match Query:多字段匹配查询,可以在多个字段中匹配指定的文本。
- Nested Query:嵌套查询,用于在嵌套文档中进行查询。
- Script Query:脚本查询,使用脚本来定义查询条件。
获取文档
使用GET方法和文档的id可以获取文档的详细信息
curl --location 'http://localhost:9200/user_idx/_doc/dTYHA44BgsSXhIjgILnZ'
匹配查询
查询email里有test字段的数据
curl --location --request GET 'http://localhost:9200/user_idx/_search' \
--header 'Content-Type: application/json' \
--data '{
"query":{
"match":{
"email":"test"
}
}
}'
精确匹配
term表示精确匹配,下面的HTTP请求表示查询phone字段为1112222的数据
curl --location --request GET 'http://localhost:9200/user_idx/_search' \
--header 'Content-Type: application/json' \
--data '{
"query":{
"term":{
"phone":"1112222"
}
}
}'
范围查询
range表示返回查询,下面的请求表示查询birthday大于等于1900-01-11的数据。
范围查询里的字段:
gt
:大于(Greater-than)gte
:大于或等于(Greater-than or equal to)lt
:小于(Less-than)lte
:小于或等于(Less-than or equal to)
curl --location --request GET 'http://localhost:9200/user_idx/_search' \
--header 'Content-Type: application/json' \
--data '{
"query":{
"range":{
"birthday":{
"gte":"1900-01-11"
}
}
}
}'
Go 使用ElasticSearch
官方库是 github.com/elastic/go-elasticsearch/v8
一般用的库是 github.com/olivere/elastic/v7
更推荐后者,更好用一些,很多公司都是用的这个库
import (
elastic "github.com/elastic/go-elasticsearch/v8"
olivere "github.com/olivere/elastic/v7"
)
初始化客户端
都是调用NewClient方法,传入地址即可,两者区别不大
es, err := elastic.NewClient(elastic.Config{
Addresses: []string{
"http://localhost:9200"},
})
ol, err := olivere.NewClient(olivere.SetURL("http://localhost:9200"))
创建索引
其中es为刚刚使用官方库创建的client,ol为刚刚使用三方库创建的client。
下面代码的def为索引配置的json格式,即
def := `
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 2
},
"mappings": {
"properties": {
"email": {
"type": "text"
},
"phone": {
"type": "keyword"
},
"birthday": {
"type": "date"
}
}
}
}
`
resp, err := es.Indices.Create("user_idx_go",es.Indices.Create.WithContext(ctx),es.Indices.Create.WithBody(strings.NewReader(def)))
_, err = ol.CreateIndex("user_idx_go_ol").Body(def).Do(ctx)
创建文档
创建文档对应的API是Index,索引对应的是Indices。注意两者的区别
官方库需要构建json字符串,如下面代码的data,而三方库则可以传入结构体,稍微简化了一下代码
data := `
{
"email": "john@example.com",
"phone": "1234567890",
"birthday": "2000-01-01"
}
`
_, err := es.Index("user_idx_go", strings.NewReader(data), es.Index.WithContext(ctx))
_, err = ol.Index().Index("user_idx_go").BodyJson(User{
Email: "john@example.com"}).Do(ctx)
查询文档
注意:如果是根据文档id查找的话使用GET这个API,如果想要根据条件查询使用Search这个API,跟直接操作es类似。
官方库需要构造query的json格式请求,返回的结果是类似http的返回体,需要自己构造解析,非常麻烦。
三方库则有对应的函数,比如NewMatchQuery。返回结果是已经定义的结构体,结果在hits里。
query := `
{
"query": {
"range": {
"birthday": {
"gte": "1990-01-01"
}
}
}
}
`
resp1, err := es.Search(es.Search.WithContext(ctx),es.Search.WithIndex("user_idx_go"),es.Search.WithBody(strings.NewReader(query)))
olQuery := olivere.NewMatchQuery("email", "john")
resp, err := s.olivere.Search("user_idx_go").Query(olQuery).Do(ctx)
for _, hit := range resp.Hits.Hits {
var u User
err = json.Unmarshal(hit.Source, &u)
}