ElasticSearch
是一个基于 Lucene
的分布式搜索引擎,业内简称ES。它提供了基于 RESTful
风格的全文搜索API。Elasticsearch
是用 Java
开发的,并作为 Apache
许可条款下的开放源码发布,是当前最流行的企业级搜索引擎。另外,它的分布式设计让它天生就适合用于云计算中,并能够达到准实时搜索,而且安装使用方便,还拥有稳定,可靠,快速等特性。本文是我对 ES 的一个完整记录,方便后期查阅。另外大家还可以查阅更多的相关资料对 ElasticSearch
有更深入的了解。
1. 安装
1.1. 单机安装
ElasticSearch 要求本地的 JDK 版本不低于1.8
去官网下载最新版的 ES 软件包 https://www.elastic.co/downloads/elasticsearch ,目前 ES 最新版本为6.1.1,我这里采用 wget 命令在终端下载
1
2cd apps
wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.1.1.tar.gz如果出现
command not found: wget
,如果是 Linux,可以用yum install -y wget
下载,如果是 Mac 就可以用brew install wget
下载检查本地 JDK 版本,必须保证为1.8版本以上
1
2
3
4java -version
java version "1.8.0_131"
Java(TM) SE Runtime Environment (build 1.8.0_131-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)解压软件包
1
tar -zxvf elasticsearch-6.1.1.tar.gz
启动 ES
1
2cd elasticsearch-6.1.1
./bin/elasticsearch测试,打开 PostMan 测试 http://localhost:9200 ,查看返回的 JSON 信息
1.2. 分布式安装
这里我会在本地启动3个 ES 节点,分别用不同的端口号来模拟分布式的环境,一个节点为 master,另外两个节点为 slave 节点。
下载安装包,解压3份,分别命名为
elasticsearch-master
,elasticsearch-slave1
,elasticsearch-slave2
修改
elasticsearch-master
的配置文件,config/elasticsearch.yml
1
2
3
4
5
6
7
8
9
10
11
12http.cors.enabled: true
http.cors.allow-origin: "*"
## 用于指定集群名称
cluster.name: xkcoding
## 用于指定节点名称
node.name: master
## 用于指定当前节点是 master 节点
node.master: true
network.host: 127.0.0.1
http.port: 9200修改
elasticsearch-slave1
的配置文件,config/elasticsearch.yml
1
2
3
4
5
6
7
8
9
10
11
12
13http.cors.enabled: true
http.cors.allow-origin: "*"
## 用于指定集群名称
cluster.name: xkcoding
## 用于指定节点名称
node.name: slave1
network.host: 127.0.0.1
http.port: 8200
## 用于发现 master 节点
discovery.zen.ping.unicast.hosts: ["127.0.0.1"]修改
elasticsearch-slave2
的配置文件,config/elasticsearch.yml
1
2
3
4
5
6
7
8
9
10
11
12
13http.cors.enabled: true
http.cors.allow-origin: "*"
## 用于指定集群名称
cluster.name: xkcoding
## 用于指定节点名称
node.name: slave2
network.host: 127.0.0.1
http.port: 7200
## 用于发现 master 节点
discovery.zen.ping.unicast.hosts: ["127.0.0.1"]启动 head 插件,打开浏览器,访问 http://localhost:9100,查看分布式节点的运行状态
1.3. 插件安装
1.3.1. head 插件
独立安装
独立安装是指,head插件安装在es外部,
独立安装 head 插件,要求本地的 Node 版本不低于8.0
前往 GitHub 搜索
elasticsearch-head
,这里我直接给出插件的 GitHub 仓库地址,https://github.com/mobz/elasticsearch-head ,clone 源代码1
2cd ~/apps
git clone https://github.com/mobz/elasticsearch-head.git检查本地 Node 版本,必须保证为8.0版本以上
1
2node -v
v8.5.0编译 head 插件
1
2cd ~/apps/elasticsearch-head
npm install如果觉得这一步的依赖下载比较慢的话,有两种解决方式:
- 可以选择科学上网
- 使用国内阿里的镜像源,使用 cnpm 安装,具体如何配置,本文不做赘述。具体参考:http://npm.taobao.org/
配置 ES 支持跨域访问,让 head 插件可以访问到
1
2cd ~/apps/elasticsearch-6.1.1
vim config/elasticsearch.yml添加进下面两行对跨域的配置
1
2http.cors.enabled: true
http.cors.allow-origin: "*"保存
:wq!
配置文件,启动 ES1
./bin/elasticsearch
运行 head 插件
1
2cd ~/apps/elasticsearch-head
npm run start打开浏览器,访问 http://localhost:9100/ ,查看 head 插件运行效果
集成安装
ES 版本 5.x 以上,不支持这种方式安装,如果想使用head插件,请使用独立安装
使用ES提供的插件安装方式安装
1
./bin/plugin install mobz/elasticsearch-head
打开浏览器,访问 http://localhost:9200/_plugin/head/ ,查看 head 插件运行效果
1.3.2. ik 中文分词插件
ik 分词插件版本与ES版本对照,请查阅:https://github.com/medcl/elasticsearch-analysis-ik#versions
手动安装
在 ES 的 plugins 目录下创建 ik 目录
1
cd ./plugins && mkdir ik
下载编译包到 ik 目录,下载地址:https://github.com/medcl/elasticsearch-analysis-ik/releases
解压下载的压缩包
1
unzip elasticsearch-analysis-ik-{ ES 版本 }.zip
重启 ES
自动安装
使用 ES 提供的插件安装方式安装,替换下面的ES 版本,具体信息可以去 https://github.com/medcl/elasticsearch-analysis-ik/releases 查看
1
./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/{ ES 版本 }/elasticsearch-analysis-ik-{ ES 版本 }.zip
重启 ES
2. 常见错误
错误1:进程虚拟内存
1 | [3]: max virtual memory areas vm.max_map_count [65530] likely too low, increase to at least [262144] |
vm.max_map_count:限制一个进程可以拥有的VMA(虚拟内存区域)的数量。
切换到root用户,修改配置文件:
1 | vim /etc/sysctl.conf |
添加下面的内容:
1 | vm.max_map_count=655360 |
然后执行命令:
1 | sysctl -p |
错误2:文件权限不足
1 | [1]: max file descriptors [4096] for elasticsearch process likely too low, increase to at least [65536] |
用的是es用户,而不是root,所以文件权限不足。
使用root用户登录
修改配置文件:
1 | vim /etc/security/limits.conf |
添加下面的内容:
1 | * soft nofile 65536 |
重启终端窗口
所有错误修改完毕,一定要重启你的终端,否则配置无效。
3. 基础概念
3.1. 集群和节点
每个节点都是一个 ES 的单独实例,通过 node_name 来指定各个节点的名字。
集群是通过配置cluster_name来使得节点找到集群。
3.2. 索引
索引是含有相同属性的文档集合,在 ES 中是通过一个名字来识别的,而且要求是英文字母小写且不包含中划线
索引对应于 SQL 的 database
3.3. 类型
索引可以含有一个或者多个类型,文档必须属于一个类型
类型对应于 SQL 的 table
3.4. 文档
文档是可以被索引的基本数据单位
文档对应于 SQL 的一条记录
3.5. 分片
每个索引都有多个分片,每个分片都是一个 Lucene 索引
3.6. 备份
拷贝一份分片就完成了分片的备份
4. 基本用法
4.1. 请求方式
API 基本格式:http://<ip>:<port>/<索引>/<类型>/<文档 id>
API 请求方式:GET、POST、PUT、DELETE
4.2. 索引
创建
假设创建一个 people 的索引,打开 PostMan,输入地址 http://localhost:9200/people ,将方法改为 PUT 方法,将👇的 json 放入 Body 请求体,点击 Send,若出现 "acknowledged":true
,则代表索引创建成功。
请求体的 json:
1 | { |
json 请求体字段解释:
- settings 字段可以不指定
- number_of_shards 代表分片数(默认为5)
- number_of_replicas 代表备份数(默认为1)
- text 类型的字段搜索时将会被分词
- keyword 类型的字段搜索时将不会被分词
- epoch_millis 类型代表时间戳格式
返回值:
1 | { |
如图所示:
删除
打开 PostMan,输入地址 http://localhost:9200/people ,将方法改为 DELETE 方法,点击 Send。
返回值:
1 | { |
4.3. 插入
现在我们向之前创建的类型中添加一条文档记录,插入分为2种方式,一种是指定 ID,一种是不指定 ID,当不指定 ID 时,ID 由 ES 生成。
指定 ID 插入
打开 PostMan,输入地址 http://localhost:9200/people/person/1 ,将文档的 json 放入 Body 请求体,将方法改为 PUT 方法,点击 Send。
文档内容:
1 | { |
返回值:
1 | { |
如图所示:
不指定 ID 插入
打开 PostMan,输入地址 http://localhost:9200/people/person ,将文档的 json 放入 Body 请求体,将方法改为 POST 方法,点击 Send。
文档内容:
1 | { |
返回值:
1 | { |
如图所示:
然后前往 head 插件查看是否插入数据
4.4. 修改
修改文档数据,打开 PostMan,输入地址 http://localhost:9200/people/person/1/_update ,将请求的 json 放入 Body 请求体,将方法改为 POST 方法,点击 Send。
请求体:
1 | { |
注意:修改的时候 URL 必须后面跟_update,然后要修改的字段必须放在 doc 字段里。
返回值:
1 | { |
如图所示:
4.5. 删除
打开 PostMan,输入地址 http://localhost:9200/people/person/1 ,将方法改为 DELETE 方法,点击 Send。
返回值:
1 | { |
4.6. 查询
ES 正如其名,本就是为了 Search 而生,所以查询是 ES 最牛逼的地方。使用上面提到的插入语法,预先插入一堆原始数据,用 head 查看。
简单查询
打开 PostMan,输入地址 http://localhost:9200/people/person/1 ,将方法改为 GET 方法,点击 Send。
返回 id 为1的文档数据:
1 | { |
条件查询
这里还是使用 PostMan 来测试我们的条件查询
请求地址:http://localhost:9200/people/_search
请求方式:POST
返回值因为文章篇幅有限,就不将返回的内容贴在文章中了,请自行测试下方请求体,验证结果
查询所有文档数据
请求体:
1
2
3
4
5{
"query":{
"match_all":{}
}
}分页查询文档数据,第 0 条开始,每页 3 条数据
请求体:
1
2
3
4
5
6
7{
"query":{
"match_all":{}
},
"from":0,
"size":3
}查询名字中包含「小」的文档
请求体:
1
2
3
4
5
6
7{
"query":{
"match":{
"name":"小"
}
}
}查询名字中包含「小」的文档,并且按照生日降序排序
请求体:
1
2
3
4
5
6
7
8
9
10
11
12
13
14{
"query":{
"match":{
"name":"小"
}
},
"sort":[
{
"birthday":{
"order":"desc"
}
}
]
}
聚合查询
请求地址:http://localhost:9200/people/_search
请求方式:POST
按照年龄聚合数据,查出文档中不同年龄所占的人数
请求体:
1
2
3
4
5
6
7
8
9{
"aggs":{
"group_by_age":{
"terms":{
"field":"age"
}
}
}
}多个聚合,分别按照年龄、生日聚合数据
请求体:
1
2
3
4
5
6
7
8
9
10
11
12
13
14{
"aggs":{
"group_by_age":{
"terms":{
"field":"age"
}
},
"group_by_birthday":{
"terms":{
"field":"birthday"
}
}
}
}年龄最小
请求体:
1
2
3
4
5
6
7
8
9{
"aggs":{
"grades_ages":{
"min":{
"field":"age"
}
}
}
}年龄最大
请求体:
1
2
3
4
5
6
7
8
9{
"aggs":{
"grades_ages":{
"max":{
"field":"age"
}
}
}
}平均年龄
请求体:
1
2
3
4
5
6
7
8
9{
"aggs":{
"grades_ages":{
"avg":{
"field":"age"
}
}
}
}年龄总和
请求体:
1
2
3
4
5
6
7
8
9{
"aggs":{
"grades_ages":{
"sum":{
"field":"age"
}
}
}
}统计,将3、4、5、6的信息统一查询
请求体:
1
2
3
4
5
6
7
8
9{
"aggs":{
"grades_ages":{
"stats":{
"field":"age"
}
}
}
}
5. 高级查询
5.1. query
模糊匹配
查询名字中包含「小」的文档
请求体:
1 | { |
词组匹配
查询名字只包含「小凯」的文档,我们先使用如下的请求体查询
1 | { |
返回的结果:
1 | // 省略其余部分 |
通过结果,可以发现,通过 match 去查询的时候,ES 返回的是分别包含「小」、「凯」的文档,如何去查询 name 字段只包含「小凯」的文档呢?使用 match_phrase 可以满足要求。
请求体:
1 | { |
字段查询
查询所有的中国人
请求体:
1 | { |
范围查询(支持数值型和日期型)
查询年龄 24 ≤ age<30 直接的数据
请求体:
1 | { |
5.2. filter
一般结合 bool 一起使用,
查询年龄为23的文档数据
请求体:
1 | { |
5.3. 复合条件查询
固定分数查询
查询名字中包含「小」的文档,并固定查询分数
请求体:
1
2
3
4
5
6
7
8
9
10
11{
"query":{
"constant_score":{
"filter":{
"match":{
"name":"小"
}
}
}
}
}查询名字中包含「小」的文档,并固定查询分数为2
请求体:
1
2
3
4
5
6
7
8
9
10
11
12{
"query":{
"constant_score":{
"filter":{
"match":{
"name":"小"
}
},
"boost":2
}
}
}
布尔查询
查询是国家为中国或者年龄为30的数据
请求体:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17{
"query":{
"bool":{
"should":[
{
"match":{
"country":"中国"
}
},{
"match":{
"age":30
}
}
]
}
}
}查询国家为中国并且年龄为23的数据
请求体:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17{
"query":{
"bool":{
"must":[
{
"match":{
"country":"中国"
}
},{
"match":{
"age":23
}
}
]
}
}
}查询国家为中国并且年龄为23并且生日比1995-07-01早的数据
请求体:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24{
"query":{
"bool":{
"must":[
{
"match":{
"country":"中国"
}
},{
"match":{
"age":23
}
}
],
"filter":[{
"range":{
"birthday":{
"lt":"1995-07-01"
}
}
}]
}
}
}
6. Spring Boot 集成 ES
代码托管在 GitHub:戳我获取源码
6.1. Spring Boot 集成 ES 的配置类
在 Spring Boot 中配置类需要使用 @Configuration
来标注
application.yml
1 | server: |
ElasticSearchConfig.java
1 | package com.xkcoding.springbootdemoelasticsearch.config; |
6.2. 插入
1 | /** |
6.3. 修改
1 | /** |
6.4. 删除
1 | /** |
6.5. 简单查询
1 | /** |
6.6. 复合查询
1 | /** |
6.8. 搜索建议(有时间补充)
6.7. 聚合查询(有时间补充)
7. 结语
ElasticSearch 在现在是一个应用十分广泛,且火热的技术,本文只是我在入门 ES 的一点小小的记录,更多 ES 的专业知识,优化技巧,还需要大量的学习与实践!
推荐学习地址:
- 官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/current/getting-started.html
- Elastic 中文社区:https://elasticsearch.cn/