ElasticSearch的学习

简介

ElasticSearch是一个分布式的开源搜索和分析引擎,MySQL专攻于数据的持久化存储与管理(即CRUD),在真正要处理海量数据的检索与分析时,ElasticSearch是更胜一筹的,可以秒级地从海量数据中检索出需要需要的数据,而MySQL如果单表达到百万以上的数据再进行检索是非常慢的。

ElasticSearch功能有很多,包括各种检索功能(应用程序搜索、网站搜索、企业搜索)、对检索来的数据做处理分析(特别是日志处理和分析)、应用指标的监控、数据的分析和可视化等。

ElasticSearchm是目前全文搜索引擎的首选,可以快速地存储、搜索和分析海量数据。数据默认放在内存中

其底层是用以前Apache的开源库Lucene,对Lucene做了再一次的简化封装,直接提供REST API的操作接口,比如直接给ElasticSearch发请求就可以使用其复杂的检索功能。

官方文档

一、基本概念

1、Index(索引)

动词,相当于MySQL中的insert,在MySQL中插入一条数据 = 在ElasticSearch中索引一条数据;

名词,相当于MySQL中的Database,MySQL中的库 = ElasticSearch的索引

2、Type(类型)【根据当前ES版本最新文档,“Before 7.0.0, the mapping definition included a type name. Elasticsearch 7.0.0 and later no longer accept a default mapping. See Removal of mapping types.”,类型已被移除。具体原因及解决见 Mapping 知识块】

在Index(索引)中,可以定义一个或多个类型;

类似于MySQL中的Table;每一种类型的数据放在一起

3、Document

保存在某个索引(Index)下,某种类型(Type)的一个数据(Document),文档是JSON格式的,Document就像是MySQL中的某个Table里面的内容(一条条的记录)

4、ElasticSearch概念 — 倒排索引机制

分词:将整句分拆为单词;

将拆分出来的单词和该单词出现的记录存放在ElasticSearch额外维护的倒排索引表中

检索:拆分检索的数据为单词,在倒排索引表中查询这些单词分别在哪些记录中

相关性得分,将相关性得分高的记录数据查出来

二、docker安装ElasticSearch

修改 Linux 网络设置
[root@localhost ~]# cd /etc/sysconfig/network-scripts/
[root@localhost network-scripts]# ls
ifcfg-eth0  ifdown-bnep  ifdown-isdn    ifdown-sit       ifup          ifup-ippp  ifup-plusb   ifup-sit       ifup-wireless
ifcfg-eth1  ifdown-eth   ifdown-post    ifdown-Team      ifup-aliases  ifup-ipv6  ifup-post    ifup-Team      init.ipv6-global
ifcfg-lo    ifdown-ippp  ifdown-ppp     ifdown-TeamPort  ifup-bnep     ifup-isdn  ifup-ppp     ifup-TeamPort  network-functions
ifdown      ifdown-ipv6  ifdown-routes  ifdown-tunnel    ifup-eth      ifup-plip  ifup-routes  ifup-tunnel    network-functions-ipv6
[root@localhost network-scripts]# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00inet 127.0.0.1/8 scope host lovalid_lft forever preferred_lft foreverinet6 ::1/128 scope host valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000link/ether 52:54:00:4d:77:d3 brd ff:ff:ff:ff:ff:ffinet 10.0.2.15/24 brd 10.0.2.255 scope global noprefixroute dynamic eth0valid_lft 83062sec preferred_lft 83062secinet6 fe80::5054:ff:fe4d:77d3/64 scope link valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000link/ether 08:00:27:87:53:b1 brd ff:ff:ff:ff:ff:ffinet 192.168.56.10/24 brd 192.168.56.255 scope global noprefixroute eth1valid_lft forever preferred_lft foreverinet6 fe80::a00:27ff:fe87:53b1/64 scope link valid_lft forever preferred_lft forever
4: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:da:49:0e:5c brd ff:ff:ff:ff:ff:ffinet 172.17.0.1/16 brd 172.17.255.255 scope global docker0valid_lft forever preferred_lft foreverinet6 fe80::42:daff:fe49:e5c/64 scope link valid_lft forever preferred_lft forever
6: veth9f2577f@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default link/ether 4a:e1:fa:70:da:a3 brd ff:ff:ff:ff:ff:ff link-netnsid 1inet6 fe80::48e1:faff:fe70:daa3/64 scope link valid_lft forever preferred_lft forever
8: veth938fc84@if7: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default link/ether 2a:e1:8c:3b:bc:66 brd ff:ff:ff:ff:ff:ff link-netnsid 0inet6 fe80::28e1:8cff:fe3b:bc66/64 scope link valid_lft forever preferred_lft forever
12: vethb2c64c0@if11: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default link/ether 0e:fa:e2:77:1a:62 brd ff:ff:ff:ff:ff:ff link-netnsid 3inet6 fe80::cfa:e2ff:fe77:1a62/64 scope link valid_lft forever preferred_lft forever
18: veth9f373db@if17: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default link/ether 1e:42:ad:3e:88:f2 brd ff:ff:ff:ff:ff:ff link-netnsid 2inet6 fe80::1c42:adff:fe3e:88f2/64 scope link valid_lft forever preferred_lft forever
[root@localhost network-scripts]# vi ifcfg-eth1#VAGRANT-BEGIN
# The contents below are automatically generated by Vagrant. Do not modify.
NM_CONTROLLED=yes
BOOTPROTO=none
ONBOOT=yes
IPADDR=192.168.56.10
NETMASK=255.255.255.0
GATEWAY=192.168.56.1       # 设置网关
DNS1=114.114.114.114       # 公共DNS,用于解析域名
DNS2=8.8.8.8
DEVICE=eth1
PEERDNS=no
#VAGRANT-END[root@localhost network-scripts]# service network restart
修改 Linux 的 yum 源
  1. 备份原 yum 源
  2. 使用新 yum 源
  3. 生成缓存
[root@localhost network-scripts]# mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup
[root@localhost network-scripts]# curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.163.com/.help/CentOS7-Base-163.repo% Total    % Received % Xferd  Average Speed   Time    Time     Time  CurrentDload  Upload   Total   Spent    Left  Speed
100  1572  100  1572    0     0   3849      0 --:--:-- --:--:-- --:--:--  3852
[root@localhost network-scripts]# yum makecache
Loaded plugins: fastestmirror
Determining fastest mirrors
base                                                                            | 3.6 kB  00:00:00
docker-ce-stable                                                                | 3.5 kB  00:00:00
extras                                                                          | 2.9 kB  00:00:00
updates                                                                         | 2.9 kB  00:00:00
(1/11): base/7/x86_64/other_db                                                  | 2.6 MB  00:00:01
(2/11): base/7/x86_64/filelists_db                                              | 7.2 MB  00:00:01
(3/11): docker-ce-stable/7/x86_64/filelists_db                                  |  24 kB  00:00:05
(4/11): extras/7/x86_64/filelists_db                                            | 226 kB  00:00:00
(5/11): extras/7/x86_64/other_db                                                | 134 kB  00:00:00
(6/11): extras/7/x86_64/primary_db                                              | 225 kB  00:00:00
(7/11): updates/7/x86_64/primary_db                                             | 5.6 MB  00:00:00
(8/11): updates/7/x86_64/other_db                                               | 454 kB  00:00:00
(9/11): updates/7/x86_64/filelists_db                                           | 3.4 MB  00:00:00
(10/11): docker-ce-stable/7/x86_64/other_db                                     | 117 kB  00:00:01
(11/11): docker-ce-stable/7/x86_64/primary_db                                   |  56 kB  00:00:09
Metadata Cache Created

1、下载镜像文件

docker pull elasticsearch:7.10.1     #存储和检索数据,相当于MySQL服务
docker pull kibana:7.10.1               #可视化检索数据,相当于SQLyog

两个镜像版本需统一

2、创建实例

1)、Elasticsearch
mkdir -p /mydata/elasticsearch/config
#将在docker容器中的ElasticSearch所有的配置文件信息都挂载在外面虚拟机中的/mydata/elasticsearch/config文件夹下,通过修改虚拟机/mydata/elasticsearch/config中配置文件的配置信息,就能修改docker容器中ElasticSearch的配置mkdir -p /mydata/elasticsearch/data
#同样将ElasticSearch中的一些数据文件挂载在外面虚拟机中的/mydata/elasticsearch/data文件夹下。echo "http.host: 0.0.0.0" >> /mydata/elasticsearch/config/elasticsearch.yml
#将http.host: 0.0.0.0写入elasticsearch.yml配置文件中,以便ElasticSearch可以让远程的任何机器进行访问
#如果在之后一部步启动elasticsearch容器报错,并无法通过浏览器访问elasticsearch的9200端口访问到信息,可以查看日志排查,如是文件权限问题,进行以下修改。也可以事先进行文件权限修改
docker logs elasticsearch               #查看elasticsearch启动的日志
ll /mydata/elasticsearch/               #查看/mydata/elasticsearch/目录下的文件的权限,包括config、data、plugins
#发现三个文件都为drwxr-xr-x权限,文件所有人(这里是root用户)可读可写可执行rwx,文件所有组和其他人只有可读和可执行的权限r-x。
#解读drwxr-xr-x:
#第1位    d       代表文件类型,-:普通文件,d:目录文件,l:链接文件,b:设备文件,c:字符设备文件,p:管道文件
#第2-4位  rwx     代表文件所有者(属主)有可读可写可执行的权限
#第5-7位  r-x     代表文件所有组(属组,与属主同一组的用户)有可读可执行的权限
#第8-10位 r-x     代表其他人有可读可执行的权限
#r:可读,数字表示为4;w:可写,数字表示为2;x:可执行,数字表示为1。
chmod -R 777 /mydata/elasticsearch/     #chmod是修改权限的命令;-R是可选项,表示递归;777表示将任何用户任何组的权限改为可读可写可执行,对应了三个角色;改的是/mydata/elasticsearch/目录下的所有文件
#-R是命令可选项,参考如下说明:
#-c : 若该文件权限确实已经更改,才显示其更改动作
#-f : 若该文件权限无法被更改也不要显示错误讯息
#-v : 显示权限变更的详细资料
#-R : 对目前目录下的所有文件与子目录进行相同的权限变更(即以递回的方式逐个变更)
#--help : 显示辅助说明
#--version : 显示版本
docker run --name elasticsearch -p 9200:9200 -p 9300:9300 \
-e "discovery.type=single-node" \
-e ES_JAVA_OPTS="-Xms64m -Xmx512m" \
-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.10.1
#--name elasticsearch                   表示为ElasticSearch镜像起个名字为elasticsearch;
#-p 9200:9200 -p 9300:9300              暴露了两个端口,一个为9200,一个为9300。9200是后来由REST API向ElasticSearch的9200端口发送http请求,9300是ElasticSearch在分布式集群状态下节点之间的通信端口
#-e "discovery.type=single-node"     ElasticSearch以单节点模式运行
#-e ES_JAVA_OPTS="-Xms64m -Xmx512m"      很重要!如果不指定该条,ElasticSearch一启动会将内存全部占用,会导致整个虚拟机卡死,因此在此指定Xms64m初始内存为64兆,最大占用内存为512兆(测试期间够用,但真正服务上线后,公司的检索服务器内存一般都是32G左右,因此可以给ElasticSearch多分配)
#-v /mydata/elasticsearch/config/elasticsearch.yml:/user/share/elasticsearch/config/elasticsearch.yml                                               -v是进行挂载,相当于将容器中ElasticSearch中的所有配置,跟外部虚拟机创建的配置文件进行一一关联,以后修改外部的就相当于修改容器内的。包括挂载data数据目录、plugins插件目录
#-d elasticsearch:7.10.1                最后-d用elasticsearch:7.10.1镜像启动ElasticSearch
2)、Kibana
docker run --name kibana -e ELASTICSEARCH_HOSTS=http://192.168.56.10:9200 -p 5601:5601 \
-d kibana:7.10.1
#-e修改参数ELASTICSEARCH_HOSTS,修改ES主机地址修改为自己虚拟机的地址
#-p映射到端口5601,通过访问5601端口访问到kibana的可视化界面
#然后从可视化界面,kibana把请求发送给ES的http://192.168.56.10:9200

三、初步检索

*:http://192.168.56.10:9200

1、_cat

GET */cat/nodes                          # 查看所有节点
GET */_cat/health                        # 查看ES健康状况
GET */_cat/master                        # 查看主节点
GET */_cat/indices                       # 查看所有索引    show databases;

2、索引一个文档(保存记录)

保存一个数据,保存在哪个索引的哪个记录下,指定用哪个唯一标识

PUT customer/external/1;在customer索引下的external类型下保存1号数据为:

PUT */customer/external/1                # postman发送请求:{"name":"Cyril_P"}                     # 并带上数据:

PUT请求和POST请求都可以保存数据,但是PUT请求必须带上id,POST请求可以不带id。

如果POST请求不指定id,会自动生成id;如果指定id,并且该id之前没数据就会新增,继续指定该id,就会修改这个数据,并新增版本号

PUT可以新增可以修改,但PUT必须指定id;由于PUT需要指定id,我们一般都用来做修改操作,PUT不指定id会报错

3、查询文档

GET */customer/external/1
{                                // 带下划线'_'表示元数据"_index": "customer",      // 在哪个索引"_type": "external",        // 在哪个类型"_id": "1",                 // 记录id"_version": 1,             // 版本号"_seq_no": 0,               // 并发控制字段,每次更新就会+1,用来做乐观锁"_primary_term": 1,           // 同上,主分片重新分配,如重启,就会变化,用来做乐观锁"found": true,               // 为true,代表找到数据"_source": {                // 查询到的真正内容"name": "Cyril_P"}
}

乐观锁处理多个修改请求,更新文档uri需携带 ?if_seq_no=0&if_primary_trem=1

4、更新文档

POST */customer/external/1/_update{"doc": {"name": "PrPrPr"}}
会对比原来数据,与原来一样就什么都不做,version、seq_no都不变;

POST */customer/external/1/{"doc": {"name": "PrPrPr"}}
直接更新数据,version和seq_no会改变;

PUT */customer/external/1/{"doc": {"name": "PrPrPr"}}
直接更新数据,version和seq_no会改变。
更新同时增加属性,以上三个都可以:

{“doc”: {“name”: “PrPrPr”,“age”:21}}

5、删除文档&索引

DELETE */customer/external/1/
DELETE */customer

6、bulk批量API 【在这之后的请求体无法在postman中测试,均移步至Kibana上测试】

POST /customer/external/_bulk{"index":{"_id":"1"}}     # index表示插入动作
{"name":"Cyril_P"}
{"index":{"_id":"2"}}
{"name":"PrPrPrPr"}

语法格式:

{action:{metadata}}

{requestbody}

{action:{metadata}}

{requestbody}

复杂实例:(metadata前带有"_",此处markdown没有显示,index、type和id前都有)

POST /_bulk{"delete":{"_index":"website","_type":"blog","_id":"123"}}                          # delete表示删除动作
{"create":{"_index":"website","_type":"blog","_id":"123"}}                            # create表示创建动作
{"title":"My First Blog POST"}                                                      # 真正的内容
{"index":{"_index":"website","_type":"blog"}}                                     # index表示插入动作
{"title":"My Second Blog POST"}                                                     # 真正的内容
{"update":{"_index":"website","_type":"blog","_id":"123","retry_on_conflict":3}}    # update表示更新动作
{"doc":{"title":"My Updated Blog POST"}}                                          # 真正的内容

四、进阶检索

1、SearchAPI

ES支持两种基本方式检索:

一个是通过使用 REST request URI 发送搜索参数(uri + 检索参数);

另一个是通过使用 REST request body 来发送它们(uri + 请求体)。

1)、检索信息
  • 一切检索从 _search 开始
GET /bank/_search                                        # 检索bank下所有信息,包括type和docs
GET /bank/_search?q=*&sort=account_number:asc          # 请求参数方式检索

响应结果解释:

took —— ElasticSearch执行搜索的时间(毫秒)

time_out —— 表示搜索是否超时

_shards —— 表示多少个分片被搜索了,以及统计了成功/失败的搜索分片

hits —— 搜索结果

hits.total —— 搜索结果

hits.hits —— 实际的搜索结果数组(默认为前10的文档)

sort —— 结果的排序key(键)(没有则按score排序)

score 和 max_score —— 相关性得分和最高得分(全文检索用)

  • uri + 请求体进行检索
GET  /bank/_search
{"query": {"match_all": {}},"sort": [{"account_number": "asc"}]
}

HTTP 客户端工具(postman),GET 请求不能携带请求体,我们变为 POST 也是一样的,我们 POST 一个 JSON 格式的查询请求体到_search API。

需要了解,一旦搜索的结果被返回,ElasticSearch 就完成了这次请求,并且不会维护任何服务端的资源或者结果的 cursor(游标)。

2、Query DSL

1)、基本语法格式

ElasticSearch 提供了一个可以执行查询的 JSON 格式的 DSL(domain-specific language 领域特定语言),这个被称为 Query DSL。

  • Query DSL 的典型结构如下:
{QUERY_NAME:{ARGUMENT:VALUE,ARGUMENT:VALUE,...}
}
  • 如果是针对某个字段,那么结构如下:
{QUERY_NAME:{FILED_NAME:{ARGUMENT:VALUE,ARGUMENT:VALUE,...}}
}

案例:

GET /bank/_search
{"query": {"match_all": {}},"sort": [{"balance": {"order": "desc"}}],"from": 0,"size": 5
}
  • query 定义如何查询;
  • match_all 查询类型【代表查询所有的所有】,ES中可以在query中组合非常多的查询类型完成复杂查询;
  • 除了query参数之外,我们也可以传递其他的参数以改变查询结果。如sort、size等;
  • from + size 限定数,完成分页功能;
  • sort 排序,多字段排序,会在前序字段相等时后续字段内部排序,否则以前序字段为准。
2)、返回部分字段

案例:

GET /bank/_search
{"query": {"match_all": {}},"sort": [{"balance": {"order": "desc"}}],"from": 0,"size": 5,"_source": ["account_number","balance"]
}
  • 真正内容"_source"只查询"account_number"、"balance"两个字段
3)、match【匹配查询】
  • 基本类型(非字符串),精准匹配
GET /bank/_search
{"query": {"match": {"account_number": "20"}}
}

match返回 account_number = 20 的文档。

  • 字符串,全文检索(如是单词便进行全文检索;如多个单词的字符串,会先进行分词,并进行全文检索;都会根据相关性得分排序)
GET /bank/_search
{"query": {"match": {"address": "mill lane"}}
}

会对检索条件"mill lane"进行分词匹配,最终查询出 address 中包含 "mill "或者 "lane "或者 “mill lane” 的所有文档,并给出相关性得分,全文检索按照相关性得分进行排序。

4)、match_phrase【短语匹配】

将需要匹配的值当成一个整体单词(不分词)进行检索。

GET /bank/_search
{"query": {"match_phrase": {"address": "mill lane"}}
}

查出 address 中包含 “mill lane” 的所有文档,并给出相关性得分,全文检索按照相关性得分进行排序。

5)、multi_match【多字段匹配】
GET /bank/_search
{"query": {"multi_match": {"query": "mill movico","fields": ["address","city"]}}
}

会对 “mill movico” 进行分词,查出 address 或者 city 包含 "mill "或者 "movico "或者 “mill movico” 的所有文档。

6)、bool【复合查询】

bool 用来做复合查询:

复合语句可以合并任何其他查询语句,包括复合语句,意味着 复合语句之间可以互相嵌套,表达非常复杂的逻辑。

must、must_not、should:
  • must:必须达到 must 列举的所有条件

  • should:应该达到 should 列举的所有条件,如果达到会增加相关文档的评分(相关性得分),并不会改变查询的结果。如果 query 中只有 should 且只有一种匹配规则,那么 should 的条件就会被作为默认匹配条件而去改变查询结果

  • must_not:必须不是指定的情况

GET /bank/_search
{"query": {"bool": {"must": [{"match": {"gender": "M"}},{"match": {"address": "mill"}}],"must_not": [{"match": {"age": "18"}}],"should": [{"match": {"lastname": "Hines"}}]}}
}

查询出 gender 必须是 "M"并且 address 必须包含 “mill”,如果 lastname 里有 “Hines” 就最好并且会加额外相关性得分,但是 age 必须不能是 18 的所有文档。

7)、filter【结果过滤】

并不是所有的查询都需要产生相关性得分,特别是那些仅用于 “filtering”(过滤)的文档。为了不计算相关性得分 ElasticSearch 会自动检查场景并且优化查询的执行。

GET /bank/_search
{"query": {"bool": {"filter": [{"range": {"age": {"gte": 18,"lte": 30}}}]}}
}
GET /bank/_search
{"query": {"bool": {"must": [{"match": {"gender": "M"}},{"match": {"address": "mill"}}],"must_not": [{"match": {"age": "18"}}],"should": [{"match": {"lastname": "Hines"}}],"filter": [{"range": {"age": {"gte": 18,"lte": 30}}}]}}
}

filter 不会计算相关性得分,会直接将不满足 filter 的文档给过滤掉。

8)、term

和 match 一样,匹配某个属性的值。全文检索字段用 match其他非 text 字段匹配用 term

GET /bank/_search
{"query": {"term": {"age": "25"}}
}
GET /bank/_search
{"query": {"match_phrase": {"address": "927 Bay"}}
}
GET /bank/_search
{"query": {"match": {"address.keyword": "927 Bay"}}
}

非text(非文本)字段建议使用 term 进行匹配文本字段的全文检索建议使用 match

对于文本字段的匹配,“match_phrase” 与 “address.keyword” 不同的是整个 "address.keyword "的内容就是 “927 Bay” 的全部值,进行的是精确匹配;而 “match_phrase” 做的是短语匹配,意思是 address 文本里面包含一个完整短语 “927 Bay”

9)、aggregations(执行聚合)

聚合提供了从函数中分组和提取数据的能力,最简单的聚合方法大致等于SQL GROUP BY 和 SQL 聚合函数。在 ElasticSearch 中,可以执行搜索返回 hits(命中结果),并且同时返回聚合结果,把一个响应中的所有 hits(命中结果)分隔开。我们就能够执行查询和多个聚合,并且在一次使用中得到各自的(任何一个的)返回结果,使用一次简洁的 API 来避免网络往返。

  • 搜索 address 中包含 mill 的所有人的年龄分布以及平均年龄,但不显示这些人的详情。
GET /bank/_search
{"query": {                       # 先查询出来 address 中包含 mill 的所有文档"match": {"address": "mill"}},"aggs": {                           # 执行聚合"ageAgg": {                     # 本次聚合的名字,方便展示在结果集中"terms": {                  # 聚合的类型 【只看某个字段的信息】"field": "age",              # 对哪个字段进行聚合"size": 10                 # 对聚合的结果作取几条数据处理}},"ageAvg":{                     # 本次聚合的名字,方便展示在结果集中"avg": {                        # 聚合的类型 【取平均值】"field": "age"                # 对哪个字段进行聚合}},"balanceAvg":{                  # 本次聚合的名字,方便展示在结果集中"avg": {                        # 聚合的类型 【取平均值】"field": "balance"            # 对哪个字段进行聚合}}},"size": 0                          # 不显示搜索数据
}
  • 按照年龄聚合,并且请求这些年龄段的这些人的平均薪资

先根据年龄聚合,再在这些年龄的聚合中套用聚合算出薪资平均值

GET /bank/_search
{"query": {"match_all": {}},"aggs": {"ageAgg": {"terms": {"field": "age","size": 100},"aggs": {"balanceAvg": {"avg": {"field": "balance"}}}}}
}
  • 查出所有年龄分布,并且这些年龄段中 M 的平均薪资和 F 的平均薪资以及这个年龄段的总体平均薪资
GET /bank/_search
{"query": {"match_all": {}},"aggs": {"ageAgg": {"terms": {"field": "age","size": 100},"aggs": {"genderAgg": {"terms": {"field": "gender.keyword","size": 10},"aggs": {"balanceAvg": {"avg": {"field": "balance"}}}},"ageBalanceAvg":{"avg": {"field": "balance"}}}}}
}

3、Mapping【详细参考】

1)、字段类型【详细参考】
核心类型
字符串(String) text, keyword
数字类型(Numeric) long, integer, short, byte, double, float, half_float, scaled_float
日期类型(Date) date
布尔类型(Boolean) boolean
二进制类型(Binary) binary
复合类型
数组类型(Array) Array 支持 不针对特定的类型
对象类型(Object) object 用于 单JSON对象
嵌套类型(Nested) nested 用于 JSON对象数组
地理类型
地理坐标(Geo-Points) geo_point 用于描述 经纬度坐标
地理图形(Geo-Shape) geo_shape 用于描述 复杂形状,如多边形
特定类型
IP类型 ip 用于描述 ipv4 和 ipv6 地址
补全类型(Completion) completion 提供自动完成提示
令牌计数类型(Token count) token_count 用于 统计字符串中的词条数量
附件类型(Attachment) 参考 mapper-attachments 插件,支持将附件如 Microsoft Office格式、
Open Document格式、ePub、HTML等等索引为 attachment 数据类型
抽取类型(Percolator) 接受特定领域查询语言(query-dsl)的查询
多字段
通常用于为不同目的用不同的方法索引同一个字段。例如,string 字段可以映射为一个 text 字段用于全文检索,同样可以映射为一个 keyword 字段用于排序和聚合。另外,你可以使用 standard analyzer,english analyzer,french analyzer 来索引一个text字段。
这就是 muti-fields 的目的。大多数的数据类型通过 fields 参数来支持 muti-fields。
2)、映射

Mapping(映射)

Mapping 是用来定义一个文档(document),以及它所包含的属性(field)是如何存储和索引的。比如,使用 mapping 来定义:

  • 哪些字符串属性应该被看成全文本属性(full text firlds);
  • 哪些属性包含数字、日期或者地理位置;
  • 文档中的所有属性是否都能被索引( _all 配置);
  • 日期的格式;
  • 自定义映射规则来执行动态添加属性
查看 mapping 信息:
GET /bank/_mapping
3)、新版本改变
ElasticSearch7 及以后版本移除了 type 概念
  • 关系型数据库中两个数据表示是独立的,即使他们里面有相同名称的列也不影响使用,但 ES 中不是这样的。ElasticSearch 是基于 Lucene 开发的搜索引擎,而ES中不同 type 下名称相同的 filed 最终在 Lucene 的处理方式是一样的。

    • 两个不同 type 下的两个 user_name,在 ES 同一个索引下其实被认为是同一个 filed,必须在两个不同的 type 中定义相同的 filed 映射,否则,不同 type 中的相同字段名称就会在处理中出现冲突的情况,导致 Lucene 处理效率下降。

    • 移除 type 就是为了提高 ES 处理数据的效率。

  • ElasticSearch 7.X

    • URL 中的 type 参数为可选。比如,索引一个文档不再要求具体提供文档类型。
  • ElasticSearch 8.X

    • 不再支持 URL 中的 type 参数。
  • 解决:将索引从多类型迁移到单类型,每种类型文档一个独立索引;或者将已存在的索引下的类型数据,全部迁移到指定位置即可,详见数据迁移。

1、创建索引,并指定索引下每一个数据的类型,指定数据的映射规则
PUT /my_index                            # 发送PUT请求,指定索引,在索引后不需要加type了
{"mappings": {                            # "mappings" 创建映射规则"properties": {                      # "properties" 指明每一个属性的映射类型"age":{"type": "integer"},       # "属性名":{【详细规则:】"type": "指定什么类型"}"email":{"type": "keyword"},        # "属性名":{"type": "指定什么类型"}"name":{"type": "text"}           # "属性名":{"type": "指定什么类型"}}}
}
2、添加新的字段映射
PUT /my_index/_mapping                   # 发送PUT请求,指定修改某个索引"index"下的映射"_mapping",仅限于添加新的字段
{"properties": {                      # "properties" 指明每一个属性的映射类型"employee-id": {                 # 定义新增加的属性,为"employee-id""type": "keyword",                # 指定类型"index": false                  # 映射参数"index"用于控制该属性能否被索引,能否被检索到,默认为true可以被索引}}
}
3、更新映射

对于已经存在的映射字段,不能通过上面两个操作实现更新操作。更新必须通过创建新的索引并进行数据迁移。

4、数据迁移

先创建出一个正确映射,同时最好正确指定好每一个数据的类型,然后使用 “_reindex” 进行数据迁移

创建步骤参考第一个创建索引并指定每一个数据类型操作,字段名要统一,可以先查看旧索引的 mapping 信息,然后复制 properties 属性再进行字段属性类型修改
POST _reindex                            # 发送POST请求,进行"_reindex"索引下数据迁移操作
{"source": {                          # 来源于哪个旧索引"index": "bank",                  # 旧索引的索引名"type": "account"                  # 如果是带有type的,就写上type名。没有的话就可以不写},"dest": {                             # 目标索引,新索引"index": "newbank"                 # 新索引的名字}
}

4、分词

ES有个分词器 tokenizer 能接收一个字符流,将之分割为独立的tokens(词元,通常是独立的单词),然后输出 tokens 流。

同时ES提供了很多内置的分词器,可以用来构建 custom analyzer(自定义分词器)。

1)、安装ik分词器

注意:不要用默认 elasticsearch-plugin install xxx.zip 进行自动安装。

要进入 https://github.com/medcl/elasticsearch-analysis-ik/releases 对应ES版本安装

  1. 进入 ES 容器内部 plugins 目录
  2. docker exec -it 容器id /bin/bash
  3. wget https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.10.1/elasticsearch-analysis-ik-7.10.1.zip
  4. upzip 下载的文件
  5. rm -rf *.zip
  6. mv elasticsearch/ ik
  7. 可以确认是否安装好了分词器
  8. cd …/bin
  9. elasticsearch plugin list:即可列出系统的分词器
2)、测试分词器
POST _analyze
{"analyzer": "ik_smart","text": ["我是中国人"]
}
POST _analyze
{"analyzer": "ik_max_word",             # 找到最大的单词组合"text": ["我是中国人"]
}
3)、自定义词库

修改 /usr/share/elasticsearch/plugins/ik/config 中的 IKAnalyzer.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties><comment>IK Analyzer 扩展配置</comment><!--用户可以在这里配置自己的扩展字典 --><entry key="ext_dict"></entry><!--用户可以在这里配置自己的扩展停止词字典--><entry key="ext_stopwords"></entry><!--用户可以在这里配置远程扩展字典 --><entry key="remote_ext_dict">http://192.168.56.10/es/fenci.txt</entry><!--用户可以在这里配置远程扩展停止词字典--><!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>

五、ElasticSearch-Rest-Client

1、对比

1)、9300:TCP
  • spring-data-elasticsearch:transport-api.jar

    • springboot版本不同,transport-api.jar 不同,不能适配 es 版本

    • 7.x 已经不建议使用,8 以后就要废弃

2)、9200:HTTP
  • JestClient:非官方,更新慢

  • RestTemplate:模拟发 HTTP 请求,ES 很多操作需要自己封装,麻烦

  • HttpClient:同上

  • Elasticsearch-Rest-Client:官方 RestClient,封装了 ES 操作,API 层次分明,上手简单

最终选择 Elasticsearch-Rest-Client(elasticsearch-high-level-client)

2、实例

1)、导入依赖后编写配置类
/*** 1、导入依赖* 2、编写配置,给容器中注入一个 RestHighLevelClient* 3、参照 API https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.x/java-rest-high.html*/
@Configuration
public class MyElasticSearchConfig {public static final RequestOptions COMMON_OPTIONS;static {RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder();
//        builder.addHeader("Authorization", "Bearer " + TOKEN);
//        builder.setHttpAsyncResponseConsumerFactory(
//                new HttpAsyncResponseConsumerFactory
//                        .HeapBufferedResponseConsumerFactory(30 * 1024 * 1024 * 1024));COMMON_OPTIONS = builder.build();}@Beanpublic RestHighLevelClient esRestClient() {RestClientBuilder builder = null;builder = RestClient.builder(new HttpHost("IP", 9200, "http"));RestHighLevelClient client = new RestHighLevelClient(builder);
//        RestHighLevelClient client = new RestHighLevelClient(
//                RestClient.builder(
//                        new HttpHost("IP", 9200, "http")));return client;}}
2)、测试类
@RunWith(SpringRunner.class)
@SpringBootTest
class MymallSearchApplicationTests {@Autowiredprivate RestHighLevelClient client;/****/@ToString@Datastatic class Account {private int account_number;private int balance;private String firstname;private String lastname;private int age;private String gender;private String address;private String employer;private String email;private String city;private String state;}/****/@Testpublic void searchIndex() throws IOException {//1、创建检索请求SearchRequest searchRequest = new SearchRequest();//指定索引searchRequest.indices("bank");//指定 DSL ,检索条件// SearchSourceBuilder searchSourceBuilder 封装的条件SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();//1.1)、构造检索条件searchSourceBuilder.query(QueryBuilders.matchQuery("address", "mill"));//1.2)、按照年龄的值分布进行聚合TermsAggregationBuilder ageAgg = AggregationBuilders.terms("ageAgg").field("age").size(10);searchSourceBuilder.aggregation(ageAgg);//1.3)、计算平均薪资AvgAggregationBuilder balanceAvg = AggregationBuilders.avg("balanceAvg").field("balance");searchSourceBuilder.aggregation(balanceAvg);System.out.println("检索条件:" + searchSourceBuilder.toString());searchRequest.source(searchSourceBuilder);//2、执行检索SearchResponse searchResponse = client.search(searchRequest, MymallElasticSearchConfig.COMMON_OPTIONS);//3、分析结果 searchResponseSystem.out.println(searchResponse.toString());
//        Map map = JSON.parseObject(searchResponse.toString(), Map.class);//3.1)、获取所有查到的数据SearchHits hits = searchResponse.getHits();SearchHit[] searchHits = hits.getHits();for (SearchHit hit : searchHits) {/*** "_index": "bank",* "_type": "account",* "_id": "970",* "_score": 5.4032025,* "_source": {}*/
//            hit.getIndex();hit.getType();hit.getId();String sourceAsString = hit.getSourceAsString();Account account = JSON.parseObject(sourceAsString, Account.class);System.out.println("account:" + account);}//3.2)、获取这次检索到的分析信息Aggregations aggregations = searchResponse.getAggregations();
//        for (Aggregation aggregation : aggregations.asList()) {//            System.out.println("当前聚合:"+aggregation.getName());
//        }Terms ageAgg1 = aggregations.get("ageAgg");for (Terms.Bucket bucket : ageAgg1.getBuckets()) {String keyAsString = bucket.getKeyAsString();System.out.println("年龄:" + keyAsString +     "==>" + bucket.getDocCount());}Avg balanceAvg1 = aggregations.get("balanceAvg");System.out.println("平均薪资:" + balanceAvg1.getValue());}/*** 测试存储数据到 ES* 也可以进行更新操作*/@Testpublic void indexData() throws IOException {IndexRequest indexRequest = new IndexRequest("users");indexRequest.id("1");//数据的id
//        indexRequest.source("username","PrPrPr","age",22,"gender","女");User user = new User();user.setUserName("PrPrPr");user.setAge(23);user.setGender("女");String jsonString = JSON.toJSONString(user);indexRequest.source(jsonString, XContentType.JSON);//要保存的内容//执行操作IndexResponse index = client.index(indexRequest, MymallElasticSearchConfig.COMMON_OPTIONS);//提取有用的响应数据System.out.println(index);}
}

六、安装 nginx

  • 随便启动一个 nginx 实例,只是为了复制出配置(如果没有该镜像,也会先下载镜像后启动容器实例)
[root@localhost mydata]# mkdir nginx
[root@localhost mydata]# ls
elasticsearch  mysql  mysql8  nginx  redis
[root@localhost mydata]# docker run -p 80:80 --name nginx -d nginx:1.19
Unable to find image 'nginx:1.19' locally
1.19: Pulling from library/nginx
a076a628af6f: Already exists
0732ab25fa22: Pull complete
d7f36f6fe38f: Pull complete
f72584a26f32: Pull complete
7125e4df9063: Pull complete
Digest: sha256:10b8cc432d56da8b61b070f4c7d2543a9ed17c2b23010b43af434fd40e2ca4aa
Status: Downloaded newer image for nginx:1.19
227cc822c4679c2f6de23bbc6cdd4b27c7555214a959e31bc2aff0ef4c8df0c4
  • 将容器内的配置文件拷贝到当前目录【别忘了命令后的点,并且 nginx 和点之间有个空格】
[root@localhost mydata]# ll nginx/
total 0
[root@localhost mydata]# docker container cp nginx:/etc/nginx .
[root@localhost mydata]# ll nginx/
total 36
drwxr-xr-x. 2 root root   26 Feb 27 16:39 conf.d
-rw-r--r--. 1 root root 1007 Dec 15 13:59 fastcgi_params
-rw-r--r--. 1 root root 2837 Dec 15 13:59 koi-utf
-rw-r--r--. 1 root root 2223 Dec 15 13:59 koi-win
-rw-r--r--. 1 root root 5231 Dec 15 13:59 mime.types
lrwxrwxrwx. 1 root root   22 Dec 15 13:59 modules -> /usr/lib/nginx/modules
-rw-r--r--. 1 root root  643 Dec 15 13:59 nginx.conf
-rw-r--r--. 1 root root  636 Dec 15 13:59 scgi_params
-rw-r--r--. 1 root root  664 Dec 15 13:59 uwsgi_params
-rw-r--r--. 1 root root 3610 Dec 15 13:59 win-utf
[root@localhost mydata]# docker stop nginx
nginx
[root@localhost mydata]# docker rm nginx
nginx
  • 修改文件 nginx 名称为 conf,并把这个 conf 文件夹移动到 /mydata/nginx 下
[root@localhost mydata]# mv nginx conf
[root@localhost mydata]# ls
conf  elasticsearch  mysql  mysql8  redis
[root@localhost mydata]# mkdir nginx
[root@localhost mydata]# mv conf nginx/
[root@localhost mydata]# ls
elasticsearch  mysql  mysql8  nginx  redis
  • 创建新的 nginx,执行以下命令
docker run -p 80:80 --name nginx \
-v /mydata/nginx/html:/usr/share/nginx/html \
-v /mydata/nginx/logs:/var/log/nginx \
-v /mydata/nginx/conf:/etc/nginx \
-d nginx:1.19

ElasticSearch的学习笔记并整合SpringBoot做测试相关推荐

  1. Shiro框架学习笔记、整合Springboot、redis缓存

    本笔记基于B站UP主不良人编程 目录 1.权限的管理 1.1什么是权限管理 1.2什么是身份认证 1.3什么是授权 2.什么是Shiro 3.Shiro的核心架构 3.1 S核心内容 4.shiro中 ...

  2. 【ElasticSearch】学习笔记(三)es的高级操作

    [ElasticSearch]学习笔记(三)es的高级操作 文章目录 [ElasticSearch]学习笔记(三)es的高级操作 1. 数据聚合 1.1 聚合总类 1.2 DSL实现聚合 1.2.1 ...

  3. ElasticSearch查询学习笔记章节5——geo_distance,geo_bounding_box,geo_polygon地图检索geo查询

    ElasticSearch查询笔记目录   涉及的常用查询内容较多,将分多个章节进行笔记整理,具体如下: ElasticSearch查询学习笔记章节1--term,terms,match,id查询   ...

  4. SpringMVC:学习笔记(10)——整合Ckeditor且实现图片上传

    SpringMVC:学习笔记(10)--整合Ckeditor且实现图片上传 配置CKEDITOR 精简文件 解压之后可以看到ckeditor/lang下面有很多语言的js,如果不需要那么多种语言的,可 ...

  5. [学习笔记] Cordova+AmazeUI+React 做个通讯录 - 单页应用 (With Router)

    [学习笔记] Cordova+AmazeUI+React 做个通讯录 系列文章 目录 准备 联系人列表(1) 联系人列表(2) 联系人详情 单页应用 (With Router) 使用 SQLite 传 ...

  6. spring学习笔记06-spring整合junit(出现的问题,解决的思路)

    spring学习笔记06-spring整合junit(出现的问题,解决的思路) 文章目录 spring学习笔记06-spring整合junit(出现的问题,解决的思路) 3.1测试类中的问题和解决思路 ...

  7. [学习笔记] Cordova+AmazeUI+React 做个通讯录 - 使用 SQLite

    [学习笔记] Cordova+AmazeUI+React 做个通讯录 系列文章 目录 准备 联系人列表(1) 联系人列表(2) 联系人详情 单页应用 (With Router) 使用 SQLite 传 ...

  8. 【从线性回归到 卷积神经网络CNN 循环神经网络RNN Pytorch 学习笔记 目录整合 源码解读 B站刘二大人 绪论(0/10)】

    深度学习 Pytorch 学习笔记 目录整合 数学推导与源码详解 B站刘二大人 目录传送门: 线性模型 Linear-Model 数学原理分析以及源码详解 深度学习 Pytorch笔记 B站刘二大人( ...

  9. python白帽子学习笔记(整合)

    python白帽子学习笔记(整合) 学习笔记目录 python白帽子学习笔记(整合) 前言 一.基础篇 1.正则表达式 2.列表 3.元组带上了枷锁的列表 4.奇葩的内置方法 5.格式化字符 6.序列 ...

最新文章

  1. 失业后跑摩的985高校硕士,被质疑学历、深“扒”论文...
  2. SP11469 SUBSET - Balanced Cow Subsets(折半搜索+状态压缩)难度⭐⭐⭐⭐★
  3. 编写Dockerfile文件,构建自己的centos镜像
  4. mfc messagebox 非模态_進博尋寶記:當進博遇見非遺?愛上中國傳統文化--財經-
  5. Oracle 每个session的限制,限制oracle普通用户能且只能kill自己的会话
  6. android不是16位,16位图像和Android处理
  7. 00_kubernetes组件版本和配置策略
  8. 京东联盟高级API - 京东联盟商品类目查询接口
  9. 115网盘视频播放速度调节
  10. WordCloud 中英文词云图绘制,看这一篇就够了
  11. 汇编语言,两个数字的想加_8085微处理器中的汇编语言程序将两个16位数字相乘...
  12. 阿里 P9 用 500 多页手册完成双十一高并发秒杀系统,绝了
  13. ubuntu加装固态硬盘设置
  14. 前端 vue 解决按1920*1080设计图做的页面适配屏幕缩放并适配4K屏
  15. 绘画板 java_非常值得学习的java 绘图板源代码
  16. 基于 K-means 算法实现的文本聚类(干货)
  17. SQL数据库基本语句
  18. Flickr 的最受欢迎图片
  19. Web Atoms Crack,JavaScript 桥接器
  20. luogu 1327 数列排序 2017 ACM-ICPC 亚洲区(南宁赛区)网络赛 J题 循环节

热门文章

  1. MacBookPro M1芯片安装brew
  2. [深度学习]Part1 Python学习进阶Ch23爬虫Spider——【DeepBlue学习笔记】
  3. 用PHP访问JasperReport
  4. Java实现Linux的md5加密,Linux_详细讲解:Linux系统GRUB的MD5加密方法,1、用grub-md5-crypt成生GRUB的md5密 - phpStudy...
  5. 【收藏】六度分隔、六度空间(Six Degrees of Separation)理论
  6. iptables 学习笔记 (下)
  7. C语言画奥运五环以及五角星
  8. 安徽师范大学计算机与信息学院研究生导师,安徽师范大学数学计算机科学学院导师介绍:郭要红...
  9. 方差的概念及其计算公式
  10. 如何在Ubuntu上安装OnlyOffice Docs 7.1?