ElasticSearch学习
一、概述
ElaticSearch,简称为es,es是一个开源的高扩展的份布式全文检索引擎,它可以近乎实时的存储、检索数据;本身扩展性很好,可以扩展到上百台服务器,处理PB级别(大数据时代)的数据。es也使用ava开发井使用Lucene作为其核心来实现所有索引和搜索的功能,但是它的目的是通过简单的 RESTfuL AP来隐 Lucene的复杂性,从而让全文搜索变得简单
谁在使用
- 维基百科
- github
- 电商网站,检索商品
- 日志数据分析, logstash采集日志,ES进行复杂的数据分析,ELK技术, elasticsearch+ logstash+ kibana
- 商品价格监控网站,用户设定某商品的价格值,当低于该阈值的时候,发送通知消息给用户,比如说订阅牙膏的监控,如果高露洁牙膏的家庭套装低于50块钱,就通知我,我就去买
elasticsearch和solr比较
- 当单纯的对已有数据进行搜索时,Solr更快
- solr搭建需要zookeeper来帮忙管理,es本身就支持集群搭建,不需要三方介入
- 当实时建立索引时,solr会产生io阻塞,查询性能较差,Elasticsearch具有明显的优势
- 随着数据量的增加,Solr的搜索效率会变得更低,而Elasticsearch却没有明显的变化
- 转变我们的搜索基础设施后从 Solr elasticsearch我们看见一个即时50×提高搜索性能!
对比总结
- es基本是开箱即用(解压就可以用!),非常简单。Solr安装略微复杂一丢丢!
- Solr利用 Zookeeper进行分布式管理,而 Elasticsearch自身带有分布式协调管理功能。
- Solr支持更多格式的数据,比如json、XML、CSV,而 Elasticsearch仅支持json文件格式。
- solr官方提供的功能更多,而 Elasticsearch本身更注重于核心功能,高级功能多有第三方插件提供,例如图形化界面需要kiana友好支撑
- Solr査询快,但更新索引时慢(即插入删除慢),用于电商等查询多的应用;
- ES建立索引快(即查询慢),即实时性查询快,用于facebook新浪等搜索。
- Solr是传统搜索应用的有力解决方案,但 Elasticsearch更适用于新兴的实时搜索应用
- solr比较成熟,有一个更大,更成熟的用户、开发和贡献者社区,而 Elasticsearch相对开发维护者较少,更新太快,学习使用成本高
二、安装
docker安装
Kibana是一个针对 Elasticsearch的开源分析及可视化平台,用来搜索、查看交互存储在 Elasticsearch索引中的数据。使用 Kibana可以通过各种图表进行高级数据分析及展示。 Kibana让海量数据更容易理解。它操作简单,基于浏览器的用户界面可以快速创建仪表板( dashboard)实时显示 Elasticsearch查询动态。设置 Kibana非常简单。无需编码或者额外的基础架构,几分钟内就可以完成Kibana安装并启动 Elasticsearch索引监测
docker-compose.yml文件如下:
镜像获取地址:https://hub.daocloud.io/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
version: "3.0"
services:
elasticsearch:
image: daocloud.io/library/elasticsearch:7.6.2
restart: always
container_name: elasticsearch
ports:
- 9200:9200
kibana:
image: daocloud.io/library/kibana:7.6.2
restart: always
container_name: kibana
ports:
- 5601:5601
environment:
- elasticsearch_url=http://192.168.1.6:9200
depends_on:
- elasticsearch
|
注意:
:与-后面要有空格
- 使用空格代替tab键
1
2
|
# 安装,docker-compose目录下执行
docker-compose up -d
|
安装可视化界面es head的插件
1
2
3
4
|
#1、拉取镜像
docker pull mobz/elasticsearch-head:5
#2、创建,启动镜像
docker run --restart=always --name es-head -di -p 9100:9100 docker.io/mobz/elasticsearch-head:5
|
安装ec-ik分词器
1
2
3
4
5
6
7
8
|
# 进入ec容器
docker exec -it elasticsearch /bin/bash
# 进入bin目录
cd bin
# 安装插件
./elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.5.4/elasticsearch-analysis-ik-6.5.4.zip
-> Downloading https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.5.4/elasticsearch-analysis-ik-6.5.4.zip
# 重启ec
|
三、ES核心概念
elasticsearch是面向文档,关系型数据库和elasticsearch客观的对比!一切都是json!
| Relational DB |
Elasticsearch |
| 数据库(database) |
索引(index) |
| 表(tables) |
types(慢慢会被弃用,5.x一个index中可以创建多个,6.x中一个index中包含1个,7中废弃) |
| 行(rows) |
documents |
| 字段(columns) |
fields(倒排索引) |
elasticsearch(集群)中可以包含多个索引(数据库),每个索引中可以包含多个类型(表),每个类型下又包含多个文档(行),每个文档中又包含多个字段(列)。
物理设计:
elasticsearch在后台把每个索引划分成多个分片。每个分片可以在集群中的不同服务器间迁移
一个人就是一个集群!默认的集群名称就是elaticsearch

逻辑设计:
一个索引类型中,包含多个文档,当我们索引一篇文档时,可以通过这样的一个顺序找到它:索引-》类型-》文档id,通过这个组合我们就能索引到某个具体的文档。注意:ID不必是整数,实际上它是一个字符串。
最初1个集群里放了1亿条数据,这时候使用分片,在ec服务1中分片1中含有5k万,从分片2中包含5kw条数据(服务2中分片1中5kw备份),ec服务2中分片中含有5kw,从分片2中包含5kw条数据(服务1中的分片1中备份)
文档
就是我们的一条条的记录
之前说elasticsearch是面向文档的,那么就意味着索弓和搜索数据的最小单位是文档, elasticsearch中,文档有几个重要属性:
- 自我包含, - -篇文档同时包含字段和对应的值,也就是同时包含key:value !
- 可以是层次型的,-一个文档中包含自文档,复杂的逻辑实体就是这么来的! {就是一 个json对象! fastjson进行自动转换!}
- 灵活的结构,文档不依赖预先定义的模式,我们知道关系型数据库中,要提前定义字段才能使用,在elasticsearch中,对于字段是非常灵活的,有时候,我们可以忽略该字段,或者动态的添加一个新的字段。
尽管我们可以随意的新增或者忽略某个字段,但是,每个字段的类型非常重要,比如一一个年龄字段类型,可以是字符串也可以是整形。因为elasticsearch会保存字段和类型之间的映射及其他的设置。这种映射具体到每个映射的每种类型,这也是为什么在elasticsearch中,类型有时候也称为映射类型。
类型
类型是文档的逻辑容器,就像关系型数据库一样,表格是行的容器。类型中对于字段的定 义称为映射,比如name映射为字符串类型。我们说文档是无模式的 ,它们不需要拥有映射中所定义的所有字段,比如新增一个字段,那么elasticsearch是怎么做的呢?elasticsearch会自动的将新字段加入映射,但是这个字段的不确定它是什么类型, elasticsearch就开始猜,如果这个值是18 ,那么elasticsearch会认为它是整形。但是elasticsearch也可能猜不对 ,所以最安全的方式就是提前定义好所需要的映射,这点跟关系型数据库殊途同归了,先定义好字段,然后再使用,别整什么幺蛾子。
索引
就是数据库!
索引是映射类型的容器, elasticsearch中的索引是一个非常大的文档集合。索|存储了映射类型的字段和其他设置。然后它们被存储到了各个分片上了。我们来研究下分片是如何工作的。
物理设计:节点和分片如何工作
一个集群至少有一 个节点,而一个节点就是一-个elasricsearch进程 ,节点可以有多个索引默认的,如果你创建索引,那么索引将会有个5个分片( primary shard ,又称主分片)构成的,每一个主分片会有-一个副本( replica shard ,又称复制分片)
https://snailsir.oss-cn-beijing.aliyuncs.com/typora/20200828224136138.png
上图是一个有3个节点的集群,可以看到主分片和对应的复制分片都不会在同-个节点内,这样有利于某个节点挂掉了,数据也不至于丢失。实际上, 一个分片是- -个Lucene索引, -一个包含倒排索引的文件目录,倒排索引的结构使得elasticsearch在不扫描全部文档的情况下,就能告诉你哪些文档包含特定的关键字。不过,等等,倒排索引是什么鬼?
倒排索引
elasticsearch使用的是一种称为倒排索引的结构,采用Lucene倒排索作为底层。这种结构适用于快速的全文搜索,一个索引由文档中所有不重复的列表构成,对于每一个词,都有一个包含它的文档列表。 例如,现在有两个文档,每个文档包含如下内容:
1
2
|
Study every day, good good up to forever # 文 档1包含的内容
To forever, study every day,good good up # 文档2包含的内容
|
为了创建倒排索引,我们首先要将每个文档拆分成独立的词(或称为词条或者tokens) ,然后创建一一个包含所有不重 复的词条的排序列表,然后列出每个词条出现在哪个文档:
| term |
doc_1 |
doc_2 |
| Study |
√ |
x |
| To |
x |
x |
| every |
√ |
√ |
| forever |
√ |
√ |
| day |
√ |
√ |
| study |
x |
√ |
| good |
√ |
√ |
| every |
√ |
√ |
| to |
√ |
x |
| up |
√ |
√ |
现在,我们试图搜索 to forever,只需要查看包含每个词条的文档
| term |
doc_1 |
doc_2 |
| to |
√ |
x |
| forever |
√ |
√ |
| total |
2 |
1 |
两个文档都匹配,但是第一个文档比第二个匹配程度更高。如果没有别的条件,现在,这两个包含关键字的文档都将返回。
再来看一个示例,比如我们通过博客标签来搜索博客文章。那么倒排索引列表就是这样的一个结构:
| 博客文章(原始数据) |
博客文章(原始数据) |
索引列表(倒排索引) |
索引列表(倒排索引) |
| 博客文章ID |
标签 |
标签 |
博客文章ID |
| 1 |
python |
python |
1,2,3 |
| 2 |
python |
linux |
3,4 |
| 3 |
linux,python |
|
|
| 4 |
linux |
|
|
如果要搜索含有python标签的文章,那相对于查找所有原始数据而言,查找倒排索引后的数据将会快的多。只需要查看标签这一栏,然后获取相关的文章ID即可。完全过滤掉无关的所有数据,提高效率!
elasticsearch的索引和Lucene的索引对比
在elasticsearch中,索引(库)这个词被频繁使用,这就是术语的使用。在elasticsearch中 ,索引被分为多个分片,每份分片是-个Lucene的索引。所以一个elasticsearch索引是由多 个Lucene索引组成的。别问为什么,谁让elasticsearch使用Lucene作为底层呢!如无特指,说起索引都是指elasticsearch的索引。
接下来的一切操作都在kibana中Dev Tools下的Console里完成。基础操作!
1
2
3
4
|
1、将存放的数据,以一定的方式进行分词,并且将分词的内容存放到一个单独的分词库中
2、当用户去查询的时候,会将用户的查询关键字进行分词
3、然后去分词库中去匹配内容,最终得到数据的id标识
4、根据id标识去存放数据的位置拉取指定的数据
|
ik分词器
是什么
分词:即把一-段中文或者别的划分成一个个的关键字,我们在搜索时候会把自己的信息进行分词,会把数据库中或者索引库中的数据进行分词,然后进行一个匹配操作,默认的中文分词是将每个字看成一个词,比如“我爱狂神”会被分为"我",“爱”,“狂”,“神” ,这显然是不符合要求的,所以我们需要安装中文分词器ik来解决这个问题。
如果要使用中文,建议使用ik分词器!
IK提供了两个分词算法: ik_ smart和ik_ max_ word ,其中ik_ smart为最少切分, ik_ max_ _word为最细粒度划分!一会我们测试!
什么是IK分词器:
- 把一句话分词
- 如果使用中文:推荐IK分词器
- 两个分词算法:ik_smart(最少切分),ik_max_word(最细粒度划分)
【ik_smart】测试:

ik_max_word为最细粒度划分!穷尽词库的可能!
【ik_max_word】测试:

ik分词器增加自己的配置
1、在ec/plugins/ik/config/创建snailsir.dic自己的字典文件
2、在ec/plugins/ik/config/IKAnalyzer.cfg.xml按照如下配置:
1
2
|
<!--用户可以在这里配置自己的扩展字典 -->
<entry key="ext_dict">snailsir.dic</entry>
|
以后的话,我们需要自己配置分词就在自己定义的dc文件中进行配置即可!
四、基本使用
Rest风格说明
一种软件架构风格,而不是标准。更易于实现缓存等机制
| method |
url地址 |
描述 |
| PUT |
localhost:9200/索引名称/类型名称/文档id |
创建文档(指定文档id) |
| POST |
localhost:9200/索引名称/类型名称 |
创建文档(随机文档id) |
| POST |
localhost:9200/索引名称/类型名称/文档id/_update |
修改文档 |
| DELETE |
localhost:9200/索引名称/类型名称/文档id |
删除文档 |
| GET |
localhost:9200/索引名称/类型名称/文档id |
通过文档id查询文档 |
| POST |
localhost:9200/索引名称/类型名称/_search |
查询所有的数据 |
数据类型
-
字符串类型
text:一般用于全文索引,将当前field进行分词
keyword:当前的field不会被分词
-
数值类型
long:
integer:
short:
byte:
double:
float:
half_floa:比float精度小一半
scaled_float
-
日期类型
date:
-
布尔类型
boolean
-
二进制类型
binary:暂时支持base64 encode的字符串
-
范围类型
lang_range:赋值的时候无需指定具体内容,只需要存储一个范围即可, 指定gt,lt,elt,egt
integer_range:
double_range:
float_range:
date_range:
ip_range:
-
geo用来存储经纬度
-
ip类型
ip:可以存储ipv4或者ipv6
关于索引的基本操作
创建一个索引
创建
1
2
3
4
5
6
7
|
PUT /person
{
"settings": {
"number_of_replicas": 1,
"number_of_shards": 5
}
}
|
查看索引信息
删除索引
创建索引规则
创建
指定字段的类型novel,就比如sql创表
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
|
PUT /book
{
"settings": {
# 备份数
"number_of_replicas": 1,
# 分片数
"number_of_shards": 5
},
# 指定数据结构
"mappings": {
# 类型 type
"novel":{
# 文档存储的field
"properties":{
#field属性名
"name":{
# 类型
"type":"text",
# 指定分词器
"analyzer":"ik_max_word",
# 是否为该字段建立索引
"index":true,
# 是否在文档中存储该字段
"store": false
},
"author":{
"type":"keyword"
},
"count":{
"type":"long"
},
"sale":{
"type":"date",
# 时间类型的格式化方式
"format":"yyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
}
}
}
}
}
|
查看
获得这个规则!可以通过GET请求获得具体的信息
关于文档的基本操作
新建文档
自动生成id
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
POST /book/novel
{
"name":"回到明朝当王爷",
"author":"月关",
"count": 1000000,
"sale": "2000-01-01"
}
# 返回结果
{
"_index" : "book",
"_type" : "novel",
"_id" : "Ang7GnoBzF3XFwZP8bC2",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1
}
|
手动指定_id
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
PUT /book/novel/1
{
"name":"锦衣夜行",
"author":"月关",
"count": 1000000,
"sale": "2008-01-01"
}
# 返回结果
{
"_index" : "book",
"_type" : "novel",
"_id" : "1",
"_version" : 1,
"result" : "created", # 创建
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 1,
"_primary_term" : 1
}
|
修改文档
覆盖修改
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
PUT /book/novel/1
{
"name":"锦衣夜行",
"author":"月关",
"count": 1000000,
"sale": "2008-09-30"
}
# 返回结果
{
"_index" : "book",
"_type" : "novel",
"_id" : "1",
"_version" : 2, #version已经发生改变了,说明修改了
"result" : "updated",#更新
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 2,
"_primary_term" : 1
}
|
doc修改方式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
POST /book/novel/1/_update
{
"doc": {
"count": 1500000
}
}
# 返回结果
{
"_index" : "book",
"_type" : "novel",
"_id" : "1",
"_version" : 3,
"result" : "updated",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 3,
"_primary_term" : 1
}
|
删除文档
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
DELETE /book/novel/Ang7GnoBzF3XFwZP8bC2
# 返回结果
{
"_index" : "book",
"_type" : "novel",
"_id" : "Ang7GnoBzF3XFwZP8bC2",
"_version" : 2,
"result" : "deleted",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 4,
"_primary_term" : 1
}
|
五、查询
构建测试数据
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
|
PUT /sms-logs-index
{
"settings": {
"number_of_replicas": 1,
"number_of_shards": 3
},
"mappings": {
"sms-logs-type":{
"properties":{
"name":{
"type":"keyword"
},
"createDate":{
"type":"date"
},
"free":{
"type":"long"
},
"ipAddr":{
"type":"ip"
},
"longCode":{
"type":"keyword"
},
"mobile":{
"type":"keyword"
},
"operatorId":{
"type":"integer"
},
"province":{
"type":"keyword"
},
"replyTotal":{
"type":"integer"
},
"sendDate":{
"type":"date"
},
"smsContent":{
"type":"text",
"analyzer":"ik_max_word"
},
"state":{
"type":"integer"
}
}
}
}
}
POST /sms-logs-index/sms-logs-type/1
{
"name":"途虎养车",
"createDate": 1587137793030,
"sendDate": "2000-01-01",
"longCode": "1500632323",
"mobile": "17600696127",
"state": 0,
"operatorId": 1,
"province": "北京",
"ipAddr": "10.23.35.104",
"smsContent":"ajsda阿拉基倒垃圾手动阀爱神的箭疯狂拉时间段爱劳动纠纷",
"free": 3,
"replyTotal": 10
}
|
简单查询
1
|
GET /sms-logs-index/sms-logs-type/_search?q=name:北京
|
query_string查询
1
2
3
4
5
6
7
8
9
|
POST /sms-logs-index/sms-logs-type/_search
{
"query": {
"query_string":{
"default_field": "name",
"query": "北京 or 上海"
}
}
}
|
simple_query_string
1
2
3
4
5
6
7
8
9
|
POST /sms-logs-index/sms-logs-type/_search
{
"query": {
"simple_query_string":{
"query": "北京",
"fields": ["name","province"]
}
}
}
|
term&terms查询
term查询
完全匹配,搜索之前不会对你搜索的关键字进行分词,对你的关键字去文档分词库中去匹配内容。
1
2
3
4
5
6
7
8
9
10
11
12
|
POST /sms-logs-index/sms-logs-type/_search
{
"from": 0,
"size": 5,
"query": {
"term":{
"province":{
"value":"北京"
}
}
}
}
|
terms查询
和term查询机制一样,都不会将指定的查询关键字进行分词,直接去分词库中匹配,找到相应的文档内容。
terms是在针对一个字段包含多个值得时候使用,类似于sql中的in查询
1
2
3
4
5
6
7
8
9
10
11
12
13
|
POST /sms-logs-index/sms-logs-type/_search
{
"from": 0,
"size": 5,
"query": {
"terms": {
"province": [
"北京",
"上海"
]
}
}
}
|
注意
并不是只对keyword类型有效,text也有效,但是text类型是使用了分词器进行了分词,可能会匹配不到数据(分词器,将词拆分后的词没有要查询的词)
match查询
会根据你查询的字段类型,采用不同的查询方式
- 日期或数值,会将基于字符串查询的内容转换成日期或数值对待
- keyword(不能被分词器分词),不会对你指定的查询关键词进行分词
- text(可以被分词),match会将你指定的查询内容根据一定的方式去分词,然后去分词库中匹配指定的内容
match,实际底层就是多个term查询,将多个term查询的结果给你封装到一起
match_all查询
查询全部内容(只返回name与province字段),不指定任何查询条件
1
2
3
4
5
6
7
8
9
|
POST /sms-logs-index/sms-logs-type/_search
{
"from": 0,
"size": 5,
"query": {
"match_all": {}
},
"_source": ["name","province"] # 或者 "_source": {"includes": ["name","province"]}
}
|
指定一个field作为筛选条件,返回的字段不包含name与province
1
2
3
4
5
6
7
8
9
10
11
|
POST /sms-logs-index/sms-logs-type/_search
{
"from": 0,
"size": 5,
"query": {
"match": {
"smsContent": "疯狂"
}
},
"_source": {"excludes": ["name","province"]}
}
|
布尔match查询
既包含中国又包含健康的
1
2
3
4
5
6
7
8
9
10
11
12
13
|
POST /sms-logs-index/sms-logs-type/_search
{
"from": 0,
"size": 5,
"query": {
"match": {
"smsContent": {
"query": "中国 健康",
"operator": "and"
}
}
}
}
|
包含中国或健康的
1
2
3
4
5
6
7
8
9
10
11
12
13
|
POST /sms-logs-index/sms-logs-type/_search
{
"from": 0,
"size": 5,
"query": {
"match": {
"smsContent": {
"query": "中国 健康",
"operator": "or"
}
}
}
}
|
multi_match查询
针对多个field进行检索(多个field对应一个搜索文本)
1
2
3
4
5
6
7
8
9
10
11
|
POST /sms-logs-index/sms-logs-type/_search
{
"from": 0,
"size": 5,
"query": {
"multi_match": {
"query": "北京",
"fields": ["province","smsContent"]
}
}
}
|
其他查询
id查询
1
|
GET /sms-logs-index/sms-logs-type/1
|
ids查询
1
2
3
4
5
6
7
8
|
POST /sms-logs-index/sms-logs-type/_search
{
"query": {
"ids": {
"values": [1,2,3]
}
}
}
|
prefix查询
前缀查询,可以通过一个关键字去指定一个field的前缀,从而查询到指定的文档。
类似于百度搜索,我们输入一个词,百度给出关联
1
2
3
4
5
6
7
8
9
10
|
POST /sms-logs-index/sms-logs-type/_search
{
"query": {
"prefix": {
"name": {
"value": "途虎"
}
}
}
}
|
fuzzy查询(模糊查询)
我们输入字符的大概,es就可以根据输入的内容大概去匹配结果
有错别字也会匹配结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
POST /sms-logs-index/sms-logs-type/_search
{
"query": {
"fuzzy": {
"name": {
"value": "途虎养成"
}
}
}
}
POST /sms-logs-index/sms-logs-type/_search
{
"query": {
"fuzzy": {
"name": {
"value": "途虎样车",
"prefix_length": 3 # 前3个字符不能错误
}
}
}
}
|
wildcard查询(通配查询)
和mysql中的like一样,可以在查询时,在字符串中指定通配符*和占位符?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
POST /sms-logs-index/sms-logs-type/_search
{
"query": {
"wildcard": {
"name": {
"value": "途虎*"
}
}
}
}
POST /sms-logs-index/sms-logs-type/_search
{
"query": {
"wildcard": {
"name": {
"value": "途虎??"
}
}
}
}
|
range查询(范围查询)
只针对数值类型,对某一个field进行大于或小的范围查询
1
2
3
4
5
6
7
8
9
10
11
|
POST /sms-logs-index/sms-logs-type/_search
{
"query": {
"range": {
"free": {
"gte": 10,
"lte": 20
}
}
}
}
|
regexp查询(正则查询)
1
2
3
4
5
6
7
8
|
POST /sms-logs-index/sms-logs-type/_search
{
"query": {
"regexp": {
"mobile": "175[0-9]{8}"
}
}
}
|
分页查询
from+size在es查询数据过程:
- 将用户指定的关键词进行分词
- 将词汇去分词库中进行检索,得到多个文档的id
- 去各个分片中去拉取指定的数据(耗时较长)
- 将数据根据score进行排序(耗时较长)
- 根据from的值,将查询到的数据舍弃一部分
- 返回结果
scroll查询过程:
-
将用户指定的关键词进行分词
-
将词汇去分词库中进行检索,得到多个文档的id
-
将文档的id存放在一个es的上下文中
-
根据你指定的size的个数去es中检索指定个数的数据,拿完数据的文档id,会从上下文移除
-
如果需要下一页的数据,直接去es的上下文中找后续内容
-
循环第4步与第5步
scroll查询方式,不适合做实时的查询
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
|
# 返回第一页数据,并将文档id信息存放在es上下文中,并且指定生存时间1分钟
POST /sms-logs-index/sms-logs-type/_search?scroll=1m
{
"query": {
"match_all": {}
},
"size": 2,
"sort": [
{
"free": {
"order": "desc"
}
}
]
}
#返回数据
{
"_scroll_id" : "根据第一步得到的scorll_id去指定",
"took" : 2,
"timed_out" : false,
"_shards" : {
"total" : 3,
"successful" : 3,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 1,
"max_score" : null,
"hits" : [
{
"_index" : "sms-logs-index",
"_type" : "sms-logs-type",
"_id" : "1",
"_score" : null,
"_source" : {
"name" : "途虎养车",
"createDate" : 1587137793030,
"sendDate" : "2000-01-01",
"longCode" : "1500632323",
"mobile" : "17600696127",
"state" : 0,
"operatorId" : 1,
"province" : "北京",
"ipAddr" : "10.23.35.104",
"smsContent" : "ajsda阿拉基倒垃圾手动阀爱神的箭疯狂拉时间段爱劳动纠纷",
"free" : 3,
"replyTotal" : 10
},
"sort" : [
3
]
}
]
}
}
# 下一页数据
POST /_search/scroll
{
"scroll_id":"DnF1ZXJ5VGhlbkZldGNoAwAAAAAAAGJBFm1DdTRTNEhFVFBXd2hqemJ3RkxKc0EAAAAAAABiQxZtQ3U0UzRIRVRQV3doanpid0ZMSnNBAAAAAAAAYkIWbUN1NFM0SEVUUFd3aGp6YndGTEpzQQ==",
"scroll": "1m"
}
# 返回结果
{
"_scroll_id" : "DnF1ZXJ5VGhlbkZldGNoAwAAAAAAAGMyFm1DdTRTNEhFVFBXd2hqemJ3RkxKc0EAAAAAAABjNBZtQ3U0UzRIRVRQV3doanpid0ZMSnNBAAAAAAAAYzMWbUN1NFM0SEVUUFd3aGp6YndGTEpzQQ==",
"took" : 2,
"timed_out" : false,
"_shards" : {
"total" : 3,
"successful" : 3,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 1,
"max_score" : null,
"hits" : [ ]
}
}
# 删除scroll在es上下文中的数据
DELETE /_search/scroll/根据第一步得到的scorll_id去指定
# 如果先执行删除,然后再执行上方的查询,会返回错误,因为已经把上下文给删了
|
复合查询
bool查询
复合过滤器:将你的多个查询条件,以一定的逻辑组合在一起
- must:所有的条件,用must组合在一起,表示and的意思
- must_not:将must_not中的条件,表示全部都不能匹配,表示not的意思
- should:所有的条件,用should组合在一起,表示or的意思
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
|
# 查询省份为武汉或者北京
# 运营商不是联通
# name中包含中国和平安
POST /sms-logs-index/sms-logs-type/_search
{
"query": {
"bool": {
"should": [
{
"term": {
"province": {
"value": "北京"
}
}
},
{
"term": {
"province": {
"value": "武汉"
}
}
}
],
"must_not": [
{
"term": {
"operatorId": {
"value": "2"
}
}
}
],
"must": [
{
"match": {
"name": "中国"
}
},{
"match": {
"name": "平安"
}
}
]
}
}
}
|
boostring查询
可以帮助我们去影响查询后的score
- positive:只有匹配上positive的查询内容,才会被放到返回的结果中
- negative:如果匹配上positive并且也匹配上了negative,就可以降低这样的文档score
- negative_boost:指定系数,必须小于1.0
关于查询时,分数是如何计算的:
- 搜索的关键字在文档中出现的频次越高,分数越高
- 指定的文档内容越短,分数就越高
- 我们在搜索时,指定的关键字也会被分词,这个被分词的内容,被分词库匹配的个数越多,分数越高
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
# 查询neme中含有’收货安装‘,如果同时含有’王五‘,就对该条数据降级(分数-0.5)
POST /sms-logs-index/sms-logs-type/_search
{
"query": {
"boosting": {
"positive": {
"match": {
"name": "收货安装"
}
},
"negative": {
"match": {
"name": "王五"
}
},
"negative_boost": 0.5
}
}
}
|
filter查询
query查询,会计算文档的匹配度得到一个分数,并且根据分数进行排序,不会缓存
filter:根据你的查询条件去查询文档,不去计算分数,而且filter会对经常被过滤的数据进行缓存
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
# max_score为0
POST /sms-logs-index/sms-logs-type/_search
{
"query": {
"bool": {
"filter": [
{
"term":{
"name":"途虎养车"
}
},
{
"range":{
"free":{
"lte":5
}
}
}
]
}
}
}
|
高亮查询
就是将用户输入的关键字,以一定的特殊样式展示给用户,让用户知道为什么这个结果被检索出来。
高亮展示的数据,本身就是文档中的一个field,单独将filed以highlight的形式返回给你。
es提供了一个highlight属性,和query同级别。
- fragment_size:指定高亮数据展示多个个字符出来
- pre_tags:指定前缀标签
- post_tags:指定后缀标签,
- Fields:指定哪几个field以高亮形式返回
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
POST /sms-logs-index/sms-logs-type/_search
{
"query": {
"match": {
"smsContent":"ajsda"
}
},
"highlight": {
"fields": {
"smsContent":{}
},
"pre_tags": "<font color='red>",
"post_tags": "</font>",
"fragment_size": 15
}
}
|
聚合查询
去重计数查询
先将返回的文档中的一个指定field进行去重,统计一共有多少条
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
# 统计一共有多少省份
POST /sms-logs-index/sms-logs-type/_search
{
"aggs": {
"province_num": {
"cardinality": {
"field": "province"
}
}
}
}
# 返回结果
"aggregations" : {
"province_num" : {
"value" : 1
}
}
|
范围统计
统计一定范围内出现的文档个数,比如,针对某个field的值在0-100,100-200,200-300之间文档出现的个数分别是多少
返回统计可以针对普通的数值(range),针对时间类型(date_range),针对ip类型(ip_range)都可以做相应的统计。
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
|
# 统计free(-无穷,5)有多少个,(5,10]有多少个,[10,正无穷)有多少个
# from包含,to不包含
POST /sms-logs-index/sms-logs-type/_search
{
"aggs": {
"free_num": {
"range": {
"field": "free",
"ranges": [
{
"to": 5
},
{
"from": 5,
"to": 10
},
{
"from": 10
}
]
}
}
}
}
# 返回结果
"aggregations" : {
"free_num" : {
"buckets" : [
{
"key" : "*-5.0",
"to" : 5.0,
"doc_count" : 1
},
{
"key" : "5.0-10.0",
"from" : 5.0,
"to" : 10.0,
"doc_count" : 0
},
{
"key" : "10.0-*",
"from" : 10.0,
"doc_count" : 0
}
]
}
}
|
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
|
POST /sms-logs-index/sms-logs-type/_search
{
"aggs": {
"date_num": {
"date_range": {
"field": "createDate",
"format": "yyy",
"ranges": [
{
"to": 1900
},
{
"from": 1900,
"to": 2000
},
{
"from": 2000
}
]
}
}
}
}
# 返回结果
"aggregations" : {
"date_num" : {
"buckets" : [
{
"key" : "*-1900",
"to" : -2.2089888E12,
"to_as_string" : "1900",
"doc_count" : 0
},
{
"key" : "1900-2000",
"from" : -2.2089888E12,
"from_as_string" : "1900",
"to" : 9.466848E11,
"to_as_string" : "2000",
"doc_count" : 0
},
{
"key" : "2000-*",
"from" : 9.466848E11,
"from_as_string" : "2000",
"doc_count" : 1
}
]
}
}
|
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
|
POST /sms-logs-index/sms-logs-type/_search
{
"aggs": {
"ip_num": {
"ip_range": {
"field": "ipAddr",
"ranges": [
{
"to": "10.126.2.8"
},
{
"from": "10.126.2.8"
}
]
}
}
}
}
# 返回结果
"aggregations" : {
"ip_num" : {
"buckets" : [
{
"key" : "*-10.126.2.8",
"to" : "10.126.2.8",
"doc_count" : 1
},
{
"key" : "10.126.2.8-*",
"from" : "10.126.2.8",
"doc_count" : 0
}
]
}
}
|
统计聚合查询
查找指定field的最大值,最小值,平均值…
使用extended_stats实现
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
|
POST /sms-logs-index/sms-logs-type/_search
{
"aggs": {
"calc_result":{
"extended_stats": {
"field": "free"
}
}
}
}
# 返回结果
"aggregations" : {
"calc_result" : {
"count" : 1,
"min" : 3.0,
"max" : 3.0,
"avg" : 3.0,
"sum" : 3.0,
"sum_of_squares" : 9.0,
"variance" : 0.0,
"std_deviation" : 0.0,
"std_deviation_bounds" : {
"upper" : 3.0,
"lower" : 3.0
}
}
}
|
地图经纬度搜索
geo_distance
以一个点为中心画圆,查询在该圆内的数据
1
2
3
4
5
6
7
8
9
10
11
12
13
|
POST /map/map/_search
{
"query":{
"geo_distance":{
"location":{ # 确定一个点
"lon":116.433733,
"lat":39.908404
},
"distance": 2000, # 确定半径
"distance_type": "arc" #指定形状为圆形
}
}
}
|
geo_bounding_box
以两个点确定一个矩形,获取矩形内的全部数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
POST /map/map/_search
{
"query":{
"geo_bounding_box":{
"location":{
"top_left":{
"lon":116.433733,
"lat":39.908404
},
"bottom_right":{
"lon":115.433733,
"lat":38.908404
}
}
}
}
}
|
geo_polygon
以多个点确定一个多边形,获取多边形内的全部数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
POST /map/map/_search
{
"query":{
"geo_polygon":{
"location":{
"points":[
{
"lon":116.433733,
"lat":39.908404
},
{
"lon":115.433733,
"lat":38.908404
},
{
"lon":114.433733,
"lat":37.908404
}
]
}
}
}
}
|
通过查询删除
1
2
3
4
5
6
7
8
9
10
|
POST /sms-logs-index/sms-logs-type/_delete_by_query
{
"query":{
"range":{
"free":{
"lt":4
}
}
}
}
|
https://www.processon.com/view/5dbba19fe4b0c555374987e3#map