基本操作
环境搭建
搭建Elasticsearch环境
下载docker镜像
1
|
docker pull elasticsearch:7.4.2
|
映射配置文件
1
2
3
4
5
6
7
8
9
|
# 配置映射文件夹
mkdir -p /mydata/elasticsearch/config
mkdir -p /mydata/elasticsearch/data
# 设置文件夹权限任何用户可读可写
chmod 777 /mydata/elasticsearch -R
# 配置 http.host
echo "http.host: 0.0.0.0" >> /mydata/elasticsearch/config/elasticsearch.yml
|
启动容器
1
2
3
4
5
6
7
|
docker run --name elasticsearch -p 9200:9200 -p 9300:9300 \
-e "discovery.type"="single-node" \ # 设置为单节点
-e ES_JAVA_OPTS="-Xms64m -Xmx128m" \ # 设置启动时ES的初始内存以及最大内存
-v /mydata/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \
-v /mydata/elasticsearch/data:/usr/share/elasticsearch/data \
-v /mydata/elasticsearch/plugins:/usr/share/elasticsearch/plugins \
-d elasticsearch:7.4.2
|
访问ES服务,http://82.157.127.173:9200/
得到相应体如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
{
"name" : "de85ed684243",
"cluster_name" : "elasticsearch",
"cluster_uuid" : "UeIP1PrXT2OFd7FlEEl3hQ",
"version" : {
"number" : "7.4.2",
"build_flavor" : "default",
"build_type" : "docker",
"build_hash" : "2f90bbf7b93631e52bafb59b3b049cb44ec25e96",
"build_date" : "2019-10-28T20:40:44.881551Z",
"build_snapshot" : false,
"lucene_version" : "8.2.0",
"minimum_wire_compatibility_version" : "6.8.0",
"minimum_index_compatibility_version" : "6.0.0-beta1"
},
"tagline" : "You Know, for Search"
}
|
可以通过/_cat来获取节点信息
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
|
# 访问http://82.157.127.173:9200/_cat
# 属性列表
/_cat/allocation
/_cat/shards
/_cat/shards/{index}
/_cat/master
/_cat/nodes
/_cat/tasks
/_cat/indices
/_cat/indices/{index}
/_cat/segments
/_cat/segments/{index}
/_cat/count
/_cat/count/{index}
/_cat/recovery
/_cat/recovery/{index}
/_cat/health
/_cat/pending_tasks
/_cat/aliases
/_cat/aliases/{alias}
/_cat/thread_pool
/_cat/thread_pool/{thread_pools}
/_cat/plugins
/_cat/fielddata
/_cat/fielddata/{fields}
/_cat/nodeattrs
/_cat/repositories
/_cat/snapshots/{repository}
/_cat/templates
|
搭建Kibana环境
下载docker镜像
1
|
docker pull kibana:7.4.2
|
启动容器
1
|
docker run --name kibana -e ELASTICSEARCH_HOSTS=http://192.168.0.128:9200 -p 5601:5601 -d kibana:7.4.2
|
访问Kibana服务,http://192.168.0.128:5601/
RESTful
一种软件架构风格,而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
ES的基本REST命令:
Method |
Url |
描述 |
PUT |
localhost:9200/索引名称/类型名称/文档id |
创建文档(指定文档id) |
GET |
localhost:9200/索引名称/类型名称/文档id |
通过文档id查询文档 |
POST |
localhost:9200/索引名称/类型名称 |
创建文档(随机文档id) |
POST |
localhost:9200/索引名称/类型名称/文档id/_update |
修改文档 |
POST |
localhost:9200/索引名称/类型名称/_search |
查询所有数据 |
DELETE |
localhost:9200/索引名称/类型名称/文档id |
删除文档 |
CRUD
创建索引
在创建索引时,我们可以声明字段与数据类型的映射
请求:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
PUT /test0
{
"mappings":{
"properties":{
"name":{
"type":"text"
},
"author":{
"type":"text"
}
}
}
}
|
响应:
1
2
3
4
5
|
{
"acknowledged": true,
"shards_acknowledged": true,
"index": "test0"
}
|
即使如果我们没有配置类型,ES也会根据字段的内容来自行推导。
注意⚠️:由于索引具有不变性,我们只能进行追加而不能更改已经存在的映射字段,必须创建新的索引后进行数据迁移。
1
2
3
4
5
6
7
8
9
|
POST _reindex
{
"source": {
"index": "test0"
},
"dest": {
"index": "test1"
}
}
|
插入文档
PUT和POST都可以插入文档:
- POST:如果不指定 id,自动生成 id。如果指定 id,则修改这条记录,并新增版本号。
- PUT:必须指定 id,如果没有这条记录,则新增,如果有,则更新。
示例:在 test1
索引下的books
类型中保存标识为 1
的文档。
请求:
1
2
3
4
5
|
PUT /test1/books/1
{
"name":"three days to see",
"author" : "Daniel Defoe"
}
|
响应:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
{
"_index": "test", //索引
"_type": "book", //类型
"_id": "1", //id
"_version": 1, //版本号
"result": "updated", //操作类型
"_shards": { //分片
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 1, //并发控制字段,每次更新就会+1,用来做乐观锁
"_primary_term": 1 //同上,主分片重新分配,如重启,就会变化
}
|
查询文档
示例:查询test1
索引下的books
类型中保存标识为 1
的文档的内容。
请求:
响应:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
{
"_index": "test1",
"_type": "books",
"_id": "1",
"_version": 1,
"_seq_no": 0,
"_primary_term": 1,
"found": true,
"_source": {
"name": "three days to see",
"author": "Daniel Defoe"
}
}
|
更新文档
使用POST
命令,在ID后面加_update,并把需要修改的内容放入doc属性中
示例:更新test1
索引下的books
类型中保存标识为 1
的文档的内容。
请求:
1
2
3
4
5
6
7
8
|
POST /test1/books/1/_update
{
"doc" : {
"name":"three days to see",
"author" : "Daniel Defoe",
"country" : "England"
}
}
|
响应:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
{
"_index": "test1",
"_type": "books",
"_id": "1",
"_version": 2,
"result": "updated",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 1,
"_primary_term": 1
}
|
删除文档和索引
删除使用DELETE
命令
示例:删除文档/test1/books/1
请求:
响应:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
{
"_index": "test1",
"_type": "books",
"_id": "1",
"_version": 3,
"result": "deleted",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 2,
"_primary_term": 1
}
|
示例:删除索引/test1
响应:
1
2
3
|
{
"acknowledged": true
}
|
Search
为了方便测试,可以从官网导入测试数据https://download.elastic.co/demos/kibana/gettingstarted/accounts.zip
1
2
3
4
5
6
|
POST /test_data/account/_bulk
{"index":{"_id":"1"}}
{"account_number":1,"balance":39225,"firstname":"Amber","lastname":"Duke","age":32,"gender":"M","address":"880 Holmes Lane","employer":"Pyrami","email":"amberduke@pyrami.com","city":"Brogan","state":"IL"}
{"index":{"_id":"6"}}
{"account_number":6,"balance":5686,"firstname":"Hattie","lastname":"Bond","age":36,"gender":"M","address":"671 Bristol Street","employer":"Netagy","email":"hattiebond@netagy.com","city":"Dante","state":"TN"}
....................
|
查询方式
ES支持两种查询方式,一种是直接在URL后加上参数,另一种是在URL后加上JSON格式的请求体。
示例:查找到收入最高的十条记录
URL + 参数
常用的参数如下
- q:用于指定搜索的关键词。
- from & size:类似于SQL中的
offset
和limit
。
- sort:对结果排序,默认为降序。
- _source:指定想要返回的属性。
1
|
GET /test_data/_search?q=*&sort=balance:desc&from=0&size=10
|
URL + QueryDSL
1
2
3
4
5
6
7
8
9
10
11
|
GET /test_data/_search
{
"query": {
"match_all" : {}
},
"sort" : [{
"balance" : "desc"
}],
"from" : 0,
"size" : 10
}
|
虽然URL+参数的写法非常简洁,但是随着逻辑的复杂化,其可读性也越来越差,所以通常都会使用URL + QueryDSL的格式。
match 匹配
match 匹配查询
无论你在任何字段上进行的是全文搜索还是精确查询,match
查询是你可用的标准查询。
对于not_analyzed
的字段,match
能做到精确查询,而对于analyzed
的字段,match能做到匹配查询(全文搜索)。
示例:查找所有年龄为25岁的记录(精确查询)
请求:
1
2
3
4
5
6
7
8
|
GET /test_data/_search
{
"query":{
"match" : {
"age": 25
}
}
}
|
示例:查询所有地址与976 Lawrence Street相关的记录(全文搜索)
请求:
1
2
3
4
5
6
7
8
|
GET /test_data/_search
{
"query":{
"match" : {
"address": "976 Lawrence Street"
}
}
}
|
match_all 全部匹配
match_all
用于查询所有文档。在没有指定查询方式时,它是默认。
示例:查询年龄最小的十条记录
请求:
1
2
3
4
5
6
7
8
9
10
11
|
GET /test_data/_search
{
"query": {
"match_all" : {}
},
"sort" : [{
"age" : "asc"
}],
"from" : 0,
"size" : 10
}
|
match_phase 短语匹配
match_phase
用于进行短语的匹配,它查询时并不是像term
一样不进行分词直接查询,而是借助分析器返回的查询词的相对顺序以及偏移量来做判断——满足所有查询词且顺序完全相同的记录才会被匹配上。
示例:地址包含502 Baycliff Terrace的记录
请求:
1
2
3
4
5
6
7
8
|
GET /test_data/_search
{
"query":{
"match_phase" : {
"address": "502 Baycliff Terrace"
}
}
}
|
multi_match 多字段匹配
multi_match
可以在多个字段上执行相同的 match
查询。
示例:查找city或address字段中包含Dixie或Street的记录。
请求:
1
2
3
4
5
6
7
8
9
10
11
12
|
GET /test_data/_search
{
"query":{
"multi_match":{
"query":"Dixie Street",
"fields":[
"city",
"address"
]
}
}
}
|
term 精确查询
term
即直接在倒排索引中查询,也就是精确查找,不进行分词器分析,文档中必须包含整个搜索的词汇。
term
和match
的区别:
match
是经过分析处理的,查询词先被文本分析器处理后再进行查询。所以根据不同的文本分析器,分析出
的结果也会不同。
term
是不经过分析处理的,直接去倒排索引查找精确的值。
由于text字段会被文本分析器处理,所以通常全文检索字段用match,其他非text字段(not_analyzed)匹配用term。
1
2
3
4
5
6
7
8
9
10
|
GET /test_data/_search
{
"query": {
"term": {
"address": "Street"
}
}
}
// 虽然文档中存在”702 Quentin Street“,但是由于文本分析器默认会转为小写,无法搜到任何数据
|
布尔查询(复合查询)
借助布尔查询可以实现如SQL中(and、or、!=)等逻辑条件的判断,并且可以合并任何其他查询语句,包括复合语句。复合语句之间可以相互嵌套,可以表达复杂的逻辑。
-
must(and):文档必须匹配这些条件才能被包含进来。(影响相关性得分)
-
must_not(not):文档必须不匹配这些条件才能被包含进来。(不影响相关性得分)
-
should(or):如果满足这些语句中的任意语句,将增加得分 。(用于修正相关性得分)
示例:查找年龄不等于18的地址包含Street的男性,且优先展示居住在30岁以上的的记录
请求:
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
|
GET /test_data/_search
{
"query":{
"bool":{
"must":[
{
"match":{
"address":"Street"
}
},
{
"match":{
"gender":"M"
}
}
],
"must_not":[
{
"match":{
"age":"18"
}
}
],
"should":[
{
"range":{
"age":{
"gt":30
}
}
}
]
}
}
}
|
Filter 过滤器
Filter
通常搭配布尔查询一起使用,用于过滤出所有满足Filter
的记录,不影响相关性得分。
示例:查找年龄在30~60之间的记录
请求:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
GET /test_data/_search
{
"query":{
"bool":{
"filter":[
{
"range":{
"age":{
"gte":30,
"lte":60
}
}
}
]
}
}
}
|
Aggregations 聚合
要掌握聚合,你只需要明白两个主要的概念:
- 桶(Buckets):满足特定条件的文档的集合
- 指标(Metrics):对桶内的文档进行统计计算
翻译成SQL的形式来理解的话:
1
2
3
4
5
|
SELECT
COUNT(1),
MAX(balance)
FROM table
GROUP BY gender;
|
桶在概念上类似于 SQL 的分组(GROUP BY
,如上面的GROUP BY gender
),而指标则类似于 COUNT()
、 SUM()
、 MAX()
等统计方法,如MAX(balance)
。
聚合的语法如下:
1
2
3
4
5
6
7
8
9
10
|
"aggregations" : {
"<聚合名称 1>" : {
"<聚合类型>" : {
<聚合体内容>
}
[,"元数据" : { [<meta_data_body>] }]?
[,"aggregations" : { [<sub_aggregation>]+ }]?
}
["聚合名称 2>" : { ... }]*
}
|
示例:按照性别进行分组,计算平均年龄和最高收入
请求:
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
|
GET /test_data/_search
{
"query":{
"match_all": {}
},
"aggs":{
"group_gender":{
"terms":{
"field":"gender"
},
"aggs":{
"avg_age":{
"avg":{
"field":"age"
}
},
"max_balance":{
"max":{
"field":"balance"
}
}
}
}
},
"size":0
}
|