提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
下载地址:Elastic7.3.0
VM | IP地址 |
---|---|
CenOS | 192.168.142.134 |
一、安装
1.elasticsearch Single-Node 部署
- 安装
tar -zxvf elasticsearch-7.3.0-linux-x86_64.tar.gz
- 配置环境elasticsearch
编辑vim /install/elasticsearch/config/elasticsearch.yml ,注意冒号后面有个空格
改四个值
单机安装请取消注释:node.name: node-1,否则无法正常启动
- 按需修改vim /usr/elasticsearch/config/jvm.options内存设置
-Xms1g
-Xmx1g
- 添加es用户,es默认root用户无法启动,需要改为其他用户
useradd estest
修改密码
passwd estest
密码:123456
改变es目录拥有者账号
chown -R estest /install/elasticsearch-7.3.0
- 修改/etc/sysctl.conf
末尾添加:vm.max_map_count=655360
执行sysctl -p 让其生效
sysctl -p
- 修改/etc/security/limits.conf
vim /etc/security/limits.conf
末尾添加
* soft nofile 65536
* hard nofile 65536
* soft nproc 4096
* hard nproc 4096
- 启动es
切换刚刚新建的用户
su estest
[estest@node5 /]$ /install/elasticsearch-7.3.0/bin/elasticse
启动成功
2.安装配置kibana
下载地址:https://artifacts.elastic.co/downloads/kibana/kibana-7.3.0-linux-x86_64.tar.gz
- 安装
tar -zxvf kibana-7.3.0-linux-x86_64.tar.gz
改变es目录拥有者账号
chown -R estest /install/kibana-7.3.0/
还需要设置访问权限
chmod -R 777 /install/kibana-7.3.0/
修改配置文件
/install/kibana-7.3.0/config/kibana.yml
修改端口,访问ip,elasticsearch服务器ip
配置完成启动:
切换用户 su estest
./bin/kibana(路径:/install/kibana-7.3.0)
扩展kibana dev tools快捷键:
ctrl+enter 提交请求
ctrl+i 自动缩进
3. Elasticsearch集成IK分词器
IK分词器3.0的特性如下:
1)采用了特有的“正向迭代最细粒度切分算法“,具有60万字/秒的高速处理能力。
2)采用了多子处理器分析模式,支持:英文字母(IP地址、Email、URL)、数字(日期,常用中文数
量词,罗马数字,科学计数法),中文词汇(姓名、地名处理)等分词处理。
3)支持个人词条的优化的词典存储,更小的内存占用。
4)支持用户词典扩展定义。
5)针对Lucene全文检索优化的查询分析器IKQueryParser;采用歧义分析算法优化查询关键字的搜索
排列组合,能极大的提高Lucene检索的命中率。
安装
/install/elasticsearch-7.3.0/bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.3.0/elasticsearch-analysis-ik-7.3.0.zip
重启Elasticsearch 和Kibana
IK分词器有两种分词模式:ik_max_word和ik_smart模式。
- ik_max_word (常用)
会将文本 做最细粒度的拆分 - ik_smart
会做最粗粒度的拆分
POST _analyze { "analyzer": "ik_max_word", "text": "南京市长江大桥" }
如果现在假如江大桥是一个人名,是南京市市长,那么上面的分词显然是不合理的,该怎么办?----->
使用扩展词典
- 进入到 config/analysis-ik/(插件命令安装方式) 或 plugins/analysis-ik/config(安装包安装方式) 目录下, 新增自定义词典
vim lagou_ext_dict.dic
-
将我们自定义的扩展词典文件添加到IKAnalyzer.cfg.xml配置中
vim IKAnalyzer.cfg.xml
-
重启elastic
停用词典使用
同上
同义词典使用
- 创建/config/analysis-ik/synonym.txt 文件,输入一些同义词并存为 utf-8 格式。例如
china,中国
2)创建近义词索引
PUT /lagou-es-synonym { "settings": { "analysis": { "filter": { "word_sync": { "type": "synonym", "synonyms_path": "analysis-ik/synonym.txt" }
},"analyzer": { "ik_sync_max_word": { "filter": [ "word_sync" ],"type": "custom", "tokenizer": "ik_max_word" },"ik_sync_smart": { "filter": [ "word_sync" ],"type": "custom", "tokenizer": "ik_smart" } } } },"mappings": { "properties": { "name": { "type": "text", "analyzer": "ik_sync_max_word", "search_analyzer": "ik_sync_max_word" } } } }
3)插入数据
POST /lagou-es-synonym/_doc/1 { "name":"拉勾是中国专业的互联网招聘平台" }
测试
POST /lagou-es-synonym/_doc/_search
{
"query":{
"match":{
"name":"china"
}
}
}
4.索引操作(创建、查看、删除)
1.创建索引
PUT /lagou-company-index
2.判断索引是否存在
HEAD /lagou-company-index
3.查看索引
GET /lagou-company-index,hh-hh
产看所有索引
GET _all
4.打开索引
POST /索引名称/_open
5.关闭索引
POST /索引名称/_close
5.删除索引
DELETE /索引名称1,索引名称2,索引名称3
5. 映射操作
PUT /lagou-company-index/_mapping/ { "properties": { "name": { "type": "text", "analyzer": "ik_max_word" },"job": { "type": "text", "analyzer": "ik_max_word" },"logo": { "type": "keyword", "index": "false" },"payment": { "type": "float" } } }
GET /索引名称/_mapping
Elastic高级应用
1.Filter DSL
过滤器在概念上类似于查询,但是它们有非常快
的执行速度,执行速度快主要有以下两个原因:
- 过滤器不会计算相关度的得分,所以它们在计算上更快一些。
- 过滤器可以被缓存到内存中,这使得在重复的搜索查询上,其要比相应的查询快出许多。
POST /book/_search
{ "query": { "bool": { "must": { "match_all": {} },"filter": { "range": { "price": { "gte": 200, "lte": 1000 }
} } } } }
2.定位非法搜索及原因
将match写错测试
GET /book/_search?explain
{ "query": { "match1": { "name": "test" } } }
GET /book/_validate/query?explain
{ "query": { "match1": { "name": "test" } } }
3.Elasticsearch零停机索引重建
Elasticsearch是一个实时的分布式搜索引擎,为用户提供搜索服务,当我们决定存储某种数据时,在创建索引的时候需要数据结构完整确定下来,与此同时索引的设定和很多固定配置将不能改变。当需要改变数据结构时就需要重建索引,为此,Elasticsearch团队提供了辅助工具帮助开发人员进行索引重建。
- 方案一:外部数据导入方案
- 方案二:基于scroll+bulk+索引别名方案
- .方案三:Reindex API方案(最简单)
先构建mapping
3.Elasticsearch Suggester智能搜索建议
放入数据
PUT /blogs/
{ "mappings": { "properties": { "body": { "type": "text" } } } }
POST _bulk/?refresh=true
{ "index" : { "_index" : "blogs" } }
{ "body": "Lucene is cool"}
{ "index" : { "_index" : "blogs" } }
{ "body": "Elasticsearch builds on top of lucene"}
{ "index" : { "_index" : "blogs" } }
{ "body": "Elasticsearch rocks"}
{ "index" : { "_index" : "blogs" } }
{ "body": "Elastic is the company behind ELK stack"}
{ "index" : { "_index" : "blogs" } }
{ "body": "elk rocks"}
{ "index" : { "_index":"blogs"}}
{ "body": "elasticsearch is rock solid"}
POST /blogs/_search
{ "suggest": { "my-suggestion": { "text": "lucne and elasticsear rock",
"phrase": { "field": "body", "highlight": { "pre_tag": "<em>", "post_tag": "</em>" } } } } }
Completion Suggester 自动补全
特点:前缀查找速度极快。但是FST只能用于前缀查找,这也是
Completion Suggester的局限所在(全文搜索倒排索引快)
PUT /blogs_completion/ { "mappings": { "properties": { "body": { "type": "completion" } } } }
POST /blogs_completion/_search?pretty { "size": 0, "suggest": { "blog-suggest": { "prefix": "elastic i", "completion": { "field": "body" } } } }
三、ES集群
1.搭建
ES工作的发现机制是Discovery模块中的Zen和EC2
我们搭建一个三个节点的集群环境,为了学习方便,我这边只在一台服务器上来演示主从环境。调整虚拟机内存到3g以上
IP | 端口 | 是否能成为主节点 |
---|---|---|
192.168.142.134 | 9200 | 是 |
192.168.142.134 | 9201 | 是 |
192.168.142.134 | 9202 | 是 |
第一个节点配置
cluster.name: my-es #集群名称 ---
node.name: node-1 # 节点名称
node.master: true #当前节点是否可以被选举为master节点,是:true、否:false ---
network.host: 0.0.0.0
http.port: 9200
transport.port: 9300 # ---
#初始化一个新的集群时需要此配置来选举master
cluster.initial_master_nodes: ["node-1","node-2","node-3"] #写入候选主节点的设备地址 ---
discovery.seed_hosts: ["127.0.0.1:9300", "127.0.0.1:9301","127.0.0.1:9302"]
#跨域
http.cors.enabled: true http.cors.allow-origin: "*"
修改完配置文件之后,一定要把之前的data目录下node数据删除再重新服务即可。
复制节点二(节点3同)
cp /install/elasticsearch-7.3.0/ /install/elasticsearch1 -rf
chown -R estest elasticsearch1
进入elasticsearch1目录config文件夹,修改elasticsearch.yml配置文件并保存。
# 修改node.name 和 http.porttransport.port
node.name: node-2
http.port: 9201
transport.port: 9301
验证:http://192.168.142.134:9200/_cat/health?v
2.插件安装:Elasticsearch Head插件介绍及安装 和 验证主从环境
1es-head主要有三个方面的操作:
- 显示集群的拓扑 能够快速访问并显示集群的状态,并且能够执行索引和节点级别操作
- 搜索接口能够查询集群中原始json或表格格式的检索数据
- 有一个输入窗口,允许任意调用RESTful API。
1.安装步骤
ealsticsearch只是后端提供各种api,那么怎么直观的使用它呢?elasticsearch-head将是一款专门针
对于elasticsearch的客户端工具 elasticsearch-head配置包,下载地址:https://github.com/mobz/elasticsearch-head
elasticsearch-head是一个基于node.js的前端工程。
1. nodejs安装
wget https://nodejs.org/dist/v10.15.3/node-v10.15.3-linux-x64.tar.xz // 下载 tar xf node-v10.15.3-linux-x64.tar.xz // 解压
cd node-v10.15.3-linux-x64/ // 进入解压目录
./bin/node -v // 执行node命令 查看版本
解压文件的 bin 目录底下包含了 node、npm 等命令,我们可以使用 ln 命令来设置软连接:就可以直接执行node -v
ln -s /install/node-v10.15.3-linux-x64/bin/npm /usr/local/bin/
ln -s /install/node-v10.15.3-linux-x64/bin/node /usr/local/bin/
2.phantomjs安装配置
cd /usr/local
wget https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-2.1.1-linux-x86_64.tar.bz2
#注意安装
yum install -y bzip2
tar -jxvf phantomjs-2.1.1-linux-x86_64.tar.bz2
vim /etc/profile
export PATH=$PATH:/usr/local/phantomjs-2.1.1-linux-x86_64/bin #注意环境变量$Path移动在最前面
source /etc/profile
3. elasticsearch-head安装
npm install -g grunt-cli
npm install grunt
npm install grunt-contrib-clean
npm install grunt-contrib-concat
npm install grunt-contrib-watch
npm install grunt-contrib-connect
yum -y install git
git clone git://github.com/mobz/elasticsearch-head.git
cd elasticsearch-head
npm install -g cnpm --registry=https://registry.npm.taobao.org
4. elasticsearch-head发现主机 并连接 elasticsearch.yml配置文件修改:
解决跨域问题
http.cors.enabled: true
http.cors.allow-origin: "*"
5. 启动
在 elasticsearch-head 中执行命令
npm run start 如果启动出错 则把第三步中的依赖再在该head路径下安装一遍
kibna创建数据
/install/kibana-7.3.0/bin/kibana --allow-root
PUT /lagou-employee-index
{ "settings": {}, "mappings": { "properties": { "name": { "type": "text" } } } }
PUT /lagou-company-index
{ "settings": { "number_of_shards" : "2", "number_of_replicas" : "2" },"mappings": { "properties": {"name": { "type": "text" } } } }
2.集群规划
集群中的节点角色如何分配
节点角色:
Master
node.master: true 节点可以作为主节点
DataNode
node.data: true 默认是数据节点
Coordinate node 协调节点,一个节点只作为接收请求、转发请求到其他节点、汇总各个节点返回数据等功能的节点,就叫协调节点,如果仅担任协调节点,将上两个配置设为false。
说明:一个节点可以充当一个或多个角色,默认三个角色都有
节点角色如何分配:
- A. 小规模集群,不需严格区分。
- B. 中大规模集群(十个以上节点),应考虑单独的角色充当。特别并发查询量大,查询的合并量大,可 以增加独立的协调节点。角色分开的好处是分工分开,不互影响。如不会因协调角色负载过高而影响数据节 点的能力。
如何避免脑裂问题
脑裂问题:
一个集群中只有一个A主节点,A主节点因为需要处理的东西太多或者网络过于繁忙,从而导致其他从节点ping不通A主节点,这样其他从节点就会认为A主节点不可用了,就会重新选出一个新的主节点B。过
了一会A主节点恢复正常了,这样就出现了两个主节点,导致一部分数据来源于A主节点,另外一部分数据来源于B主节点,出现数据不一致问题,这就是脑裂。
常用做法(中大规模集群):
1)Master 和 dataNode 角色分开,配置奇数个master,如3
2)单播发现机制,配置master资格节点(5.0之前): discovery.zen.ping.multicast.enabled: false —— 关闭多播发现机制,默认是关闭的
3)延长ping master的等待时长 discovery.zen.ping_timeout: 30(默认值是3秒)——其他节点ping主节点多久时间没有响应就认 为主节点不可用了。 es7中换成了 discovery.request_peers_timeout
索引应该设置多少个分片
== 说明:分片数指定后不可变,除非重建索引。==
分片设置的可参考原则:
ElasticSearch推荐的最大JVM堆空间是30~32G, 所以把你的分片最大容量限制为30GB, 然后再对分片数量做合理估算. 例如, 你认为你的数据能达到200GB, 推荐你最多分配7到8个分片。
在开始阶段, 一个好的方案是根据你的节点数量按照1.5~3倍的原则来创建分片. 例如,如果你有3个节点,则推荐你创建的分片数最多不超过9(3x3)个。当性能下降时,增加节点,ES会平衡分片的放置。
对于基于日期的索引需求, 并且对索引数据的搜索场景非常少. 也许这些索引量将达到成百上千, 但每个索引的数据量只有1GB甚至更小. 对于这种类似场景, 建议只需要为索引分配1个分片。如日志管理就是一个日期的索引需求,日期索引会很多,但每个索引存放的日志数据量就很少。
分片应该设置几个副本
副本设置基本原则:
为保证高可用,副本数设置为2即可。要求集群至少要有3个节点,来分开存放主分片、副本。
如发现并发量大时,查询性能会下降,可增加副本数,来提升并发查询能力。
== 注意:新增副本时主节点会自动协调,然后拷贝数据到新增的副本节点,副本数是可以随时调整的!==
PUT /my_temp_index/_settings { "number_of_replicas": 1 }
3.分布式集群调优策略
1. Index(写)调优
- 1.1 副本数置0
- 1.2 自动生成doc ID
- 1.3 合理设置mappings
- 1.4 调整_source字段
- 1.5 对analyzed的字段禁用norms
Norms用于在搜索时计算doc的评分,如果不需要评分,则可以将其禁用:
"title": { "type": "string", "norms": { "enabled": false }
- 1.6 调整索引的刷新间隔
PUT /my_index/_settings
{
"index" : {
"refresh_interval": "30s"
}
}
这种方案以牺牲可见性的方式,提高了index操作的性能
- 1.7 批处理
- 1.8 Document的路由处理
值得注意的是线程数虽然降低了,但是单批的处理耗时可能增加了。和提高刷新间隔方法类似,这有可能会延长数据不见的时间。
2. Search(读)调优
在存储的Document条数超过10亿条后,我们如何进行搜索调优。
- 1.数据分组
很多人拿ES用来存储日志,日志的索引管理方式一般基于日期的,基于天、周、月、年建索引。如下图,基于天建索引 - 2.使用Filter替代Query
在搜索时候使用Query,需要为Document的相关度打分。使用Filter,没有打分环节处理,做的事情更少,而且filter理论上更快一些。
如果搜索不需要打分,可以直接使用filter查询。如果部分搜索需要打分,建议使用’bool’查询。这种方式可以把打分的查询和不打分的查询组合在一起使用,如:
GET /_search
{ "query": { "bool": { "must": { "term": { "user": "kimchy" } },"filter": { "term": { "tag": "tech" } } } } }
- 3.ID字段定义为keyword
- 4.别让用户的无约束的输入拖累了ES集群的性能
四、Elasticsearch之搜索实战
五、Elasticsearch之原理
第1节 索引文档写入和近实时搜索原理
- Refresh
在 Elasticsearch 中, _refresh 操作默认每秒执行一次, 意味着将内存 buffer 的数据写入到一个新的 Segment 中,这个时候索引变成了可被检索的。写入新Segment后 会清空内存buffer。 - Flush
Flush 操作意味着将内存 buffer 的数据全都写入新的 Segments 中, 并将内存中所有的 Segments全部刷盘, 并且清空 translog 日志的过程。
近实时搜索
refresh API
在 Elasticsearch 中,写入和打开一个新段的轻量的过程叫做 refresh 。 默认情况下每个分片会每秒自动刷新一次。这就是为什么我们说 Elasticsearch 是 近 实时搜索: 文档的变化并不是立即对搜索可见,但会在一秒之内变为可见
这些行为可能会对新用户造成困惑: 他们索引了一个文档然后尝试搜索它,但却没有搜到。这个问题的解决办法是用 refresh API 执行一次手动刷新
#刷新(Refresh)所有的索引。
1. POST /_refresh
#只刷新(Refresh) blogs 索引
3. POST /my_blogs/_refresh
# 只刷新 文档
5. PUT /my_blogs/_doc/1?refresh {"test": "test"} PUT /test/_doc/2?refresh=true {"test": "test"}
可能想优化索引速度而不是近实时搜索, 可以通过设置 refresh_interval , 降低每个索引的刷新频率
PUT /my_logs { "settings": { "refresh_interval": "30s" } }
refresh_interval 可以在既存索引上进行动态更新。 在生产环境中,当你正在建立一个大的新索引时,可以先关闭自动刷新,待开始使用该索引时,再把它们调回来:
PUT /my_logs/_settings { "refresh_interval": -1 } PUT /my_logs/_settings { "refresh_interval": "1s" }
持久化变更
原理:
如果没有用 fsync 把数据从文件系统缓存刷(flush)到硬盘,我们不能保证数据在断电甚至是程序正常退出之后依然存在。为了保证 Elasticsearch 的可靠性,需要确保数据变化被持久化到磁盘。
在动态更新索引时,我们说一次完整的提交会将段刷到磁盘,并写入一个包含所有段列表的提交点。Elasticsearch 在启动或重新打开一个索引的过程中使用这个提交点来判断哪些段隶属于当前分片。
即使通过每秒刷新(refresh)实现了近实时搜索,我们仍然需要经常进行完整提交来确保能从失败中恢复。但在两次提交之间发生变化的文档怎么办?我们也不希望丢失掉这些数据。
Elasticsearch 增加了一个 translog ,或者叫事务日志,在每一次对 Elasticsearch 进行操作时均进行了日志记录。通过 translog ,整个流程看起来是下面这样:
- 图21新的文档被添加到内存缓冲区并且被追加到了事务日志
- 刷新(refresh)使分片处于 图 22描述的状态,分片每秒被刷新(refresh)一次:
这些在内存缓冲区的文档被写入到一个新的段中,且没有进行 fsync 操作。
这个段被打开,使其可被搜索。
内存缓冲区被清空。
- 图22刷新(refresh)完成后, 缓存被清空但是事务日志不会
- 这个进程继续工作,更多的文档被添加到内存缓冲区和追加到事务日志(见 图 23 )。
- 图23事务日志不断积累文档
3. 每隔一段时间–例如 translog 变得越来越大–索引被刷新(flush);一个新的 translog 被创建,并且一个全量提交被执行(见 图 24):
所有在内存缓冲区的文档都被写入一个新的段。
缓冲区被清空。
一个提交点被写入硬盘。
文件系统缓存通过 fsync 被刷新(flush)。
老的 translog 被删除
- 图 24. 在刷新(flush)之后,段被全量提交,并且事务日志被清空
flush API
这个执行一个提交并且截断 translog 的行为在 Elasticsearch 被称作一次 flush 。 分片每 30 分钟被自动刷新(flush),或者在 translog 太大的时候也会刷新。
flush API 可以 被用来执行一个手工的刷新(flush):
#刷新(flush) blogs 索引。
POST /blogs/_flush
#刷新(flush)所有的索引并且等待所有刷新在返回前完成
POST /_flush?wait_for_ongoin