一、 ES是什么
1. 简介
Elaticsearch简称为ES,是一个开源的可扩展的分布式的全文检索引擎,它可以近乎实时的存储、检索数
据。本身扩展性很好,可扩展到上百台服务器,处理PB级别的数据。
2. 功能
-
分布式的搜索引擎
分布式:Elasticsearch自动将海量数据分散到多台服务器上去存储和检索
-
全文检索
提供模糊搜索等自动度很高的查询方式,并进行相关性排名,高亮等功能
-
数据分析引擎
电商网站,最近一周笔记本电脑这种商品销量排名top10的商家有哪些?新闻网站,最近1个月
问量排名top3的新闻板块是哪些
-
对海量数据进行近实时的处理
海量数据的处理:因为是分布式架构,Elasticsearch可以采用大量的服务器去存储和检索数据,自
然而然就可以实现海量数据的处理
近实时:Elasticsearch可以实现秒级别的数据搜索和分析
3. 特点
Elasticsearch的特点是它提供了一个极速的搜索体验。这源于它的高速(speed)
。相比较其它
的一些大数据引擎,Elasticsearch可以实现秒级的搜索,速度非常有优势。Elasticsearch的
cluster是一种分布式的部署,极易扩展(scale )
这样很容易使它处理PB级的数据库容量。最重要
的是Elasticsearch是它搜索的结果可以按照分数进行排序,它能提供我们最相关的搜索结果
(relevance)
。
- 安装方便:没有其他依赖,下载后安装非常方便;只用修改几个参数就可以搭建起来一个集群
- JSON:输入/输出格式为 JSON,意味着不需要定义 Schema,快捷方便
- RESTful:基本所有操作 ( 索引、查询、甚至是配置 ) 都可以通过 HTTP 接口进行
- 分布式:节点对外表现对等(每个节点都可以用来做入口) 加入节点自动负载均衡
- 多租户:可根据不同的用途分索引,可以同时操作多个索引
- 支持超大数据: 可以扩展到 PB 级的结构化和非结构化数据 海量数据的近实时处理
4. 倒排索引
简单来说,通过value找key,适用于快速的全文搜索,一个倒排索引由文档中所有不重复词的列表构成,对于其中每个词,有一个包含它的文档列表。
倒排索引创建索引的流程:
- 首先把所有的原始数据进行编号,形成文档列表;
- 把文档数据进行分词,得到很多的词条,以词条为索引。保存包含这些词条的文档的编号信息;
搜索的过程:
- 当用户输入任意的词条时,首先对用户输入的数据进行分词,得到用户要搜索的所有词条,然后拿着这些词条去倒排索引列表中进行匹配。找到这些词条就能找到包含这些词条的所有文档的编号;
- 然后根据这些编号去文档列表中找到文档;
正向索引:通过key找value
5. 主流搜索方案
Lucene
Solr
Elasticsearch
-
三者之间的区别和联系
Solr和Elasticsearch都是基于Lucene实现的。但Solr和Elasticsearch之间也是有区别的
- Solr利用Zookpper进行分布式管理,而Elasticsearch自身带有分布式协调管理功能
- Solr比Elasticsearch实现更加全面,Solr官方提供的功能更多,而Elasticsearch本身更注重于
核心功能, 高级功能多由第三方插件提供
- Solr在传统的搜索应用中表现好于Elasticsearch,而Elasticsearch在实时搜索应用方面比Solr
表现好
6. 版本
主流版本为5.x , 6.x及7.x版本
7.x 更新的内容如下
-
集群连接变化:TransportClient被废弃
以至于,es7的java代码,只能使用restclient。对于java编程,建议采用 High-level-rest-
client 的方式操作ES集群。High-level REST client 已删除接受Header参数的API方
法,Cluster Health API默认为集群级别。
-
ES数据存储结构变化:简化了Type 默认使用_doc
es6时,官方就提到了es7会逐渐删除索引type,并且es6时已经规定每一个index只能有一个
type。在es7中使用默认的_doc作为type,官方说在8.x版本会彻底移除type。
api请求方式也发送变化,如获得某索引的某ID的文档:GET index/_doc/id其中index和id为具
体的值
-
ES程序包默认打包jdk:以至于7.x版本的程序包大小突然增大了200MB+, 对比6.x发现,包大了
200MB+, 正是JDK的大小
默认配置变化:默认节点名称为主机名,默认分片数改为1,不再是5。
-
Lucene升级为lucene 8 查询相关性速度优化:Weak-AND算法
es可以看过是分布式lucene,lucene的性能直接决定es的性能。lucene8在top k及其他查询上有
很大的性能提升。
weak-and算法 核心原理:取TOP N结果集,估算命中记录数。
TOP N的时候会跳过得分低于10000的文档来达到更快的性能。
-
间隔查询(Intervals queries): intervals query 允许用户精确控制查询词在文档中出现的先后关
系,实现了对terms顺序、terms之间的距离以及它们之间的包含关系的灵活控制。
-
引入新的集群协调子系统 移除 minimum_master_nodes 参数,让 Elasticsearch 自己选择可以形
成仲裁的节点。
-
7.0将不会再有OOM的情况,JVM引入了新的circuit breaker(熔断)机制,当查询或聚合的数据
量超出单机处理的最大内存限制时会被截断。
设置indices.breaker.fifielddata.limit的默认值已从JVM堆大小的60%降低到40%。
-
分片搜索空闲时跳过refresh
以前版本的数据插入,每一秒都会有refresh动作,这使得es能成为一个近实时的搜索引擎。但是
当没有查询需求的时候,该动作会使得es的资源得到较大的浪费。
7. 快速部署-单实例
# 创建网络,kibana 也接入这个网络
docker network create somenetwork
# 安装 es
docker run -d --name elasticsearch --net somenetwork -p 9200:9200 -p 9300:9300 -v /home/search/es/data:/usr/share/elasticsearch/data -v /home/search/es/logs:/usr/share/elasticsearch/logs -e "discovery.type=single-node" elasticsearch:7.14.2
# Kibana 安装
docker run -d --name kibana --net somenetwork -p 5601:5601 kibana:7.14.2
二、入门使用
1. 核心概念
索引(Index)
-
类型(type)
ES 7.x以后 要逐渐移除type这个概念。
-
映射(mapping)
mapping定义了每个字段的类型等信息。相当于关系型数据库中的表结构。
常用数据类型:text、keyword、number、array、range、boolean、date、geo_point、ip、
nested、object
关系型数据库(比如Mysql) | 非关系型数据库(Elasticsearch) |
---|---|
数据库Database | 索引Index |
表Table | 索引类型(原为Type) |
数据行Row | 文档Document |
数据列Column | 字段Field |
约束 Schema | 映射Mapping |
2. API
Elasticsearch提供了Rest风格的API,即http请求接口,而且也提供了各种语言的客户端API。\
-
Restful API
文档地址:https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html
-
客户端API
文档地址:https://www.elastic.co/guide/en/elasticsearch/client/index.html
3. 集成IK分词器
IKAnalyzer是一个开源的,基于java语言开发的轻量级的中文分词工具包。
K分词器有两种分词模式:ik_max_word和ik_smart模式。
-
ik_max_word (常用)
会将文本做最细粒度的拆分
-
ik_smart
会做最粗粒度的拆分
拓展词典
停用词典
同义词典
4. 索引操作
5. 映射操作
6. 文档增删改查及局部更新
三、高级应用
1. 映射高级
地理坐标点数据类型-geo_point
字符串形式以半角逗号分割,如 "lat,lon"
对象形式显式命名为 lat 和 lon
数组形式表示为 [lon,lat]
过滤器 | 作用 |
---|---|
geo_bounding_box | 找出落在指定矩形框中的点 |
geo_distance | 找出与指定位置在给定距离内的点 |
geo_distance_range | 找出与指定点距离在给定最小距离和最大距离之间的点 |
geo_polygon | 找出落在多边形中的点。 这个过滤器使用代价很大 。当觉得自己需要使用它,最好先看看 https://www.elastic.co/guide/cn/elasticsearch/guide/current/geo-shapes.html。 |
6. 零停机索引重建
Elasticsearch是一个实时的分布式搜索引擎,为用户提供搜索服务,当我们决定存储某种数据时,在创
建索引的时候需要数据结构完整确定下来,与此同时索引的设定和很多固定配置将不能改变。当需要改
变数据结构时就需要重建索引,为此,Elasticsearch团队提供了辅助工具帮助开发人员进行索引重建。
方案一:外部数据导入方案
系统架构设计中,有关系型数据库用来存储数据,Elasticsearch在系统架构里起到查询加速的作用,如
果遇到索引重建的操作,待系统模块发布新版本后,可以从数据库将数据查询出来,重新灌到
Elasticsearch即可。
方案二:基于scroll+bulk+索引别名方案
利用Elasticsearch自带的一些工具完成索引的重建工作,当然在方案实际落地时,可能也会依赖客户端
的一些功能,比如用Java客户端持续的做scroll查询、bulk命令的封装等。数据完全自给自足,不依赖
其他数据源。
方案三:Reindex API方案
Elasticsearch v6.3.1已经支持Reindex API,它对scroll、bulk做了一层封装,能够 对文档重建索引而不
需要任何插件或外部工具。
7. Suggester智能搜索建议
Suggesters基本的运作原理是将输入的文本分解为token,然后在索引的字典里查找相似的term并返回。 根据使用场景的不同,Elasticsearch里设计了4种类别的Suggester,分别是:
- Term Suggester
- Phrase Suggester
- Completion Suggester
- Context Suggester
8. Java Client
ES提供多种不同的客户端:
1、TransportClient ES提供的传统客户端,官方计划8.0版本删除此客户端。
2、RestClient RestClient是官方推荐使用的,它包括两种:Java Low Level REST Client和 Java High
Level REST Client。 ES在6.0之后提供 Java High Level REST Client, 两种客户端官方更推荐使用 Java
High Level REST Client, 使用时加入对应版本的依赖即可。
四、企业级高可用分布式集群
1. 核心概念
-
集群(Cluster)
一个Elasticsearch集群由多个节点(Node)组成,每个集群都有一个共同的集群名称作为标识
-
节点(node)
一个Elasticsearch实例即一个Node,一台机器可以有多个实例,正常使用下每个实例都应该
会部署在不同的机器上。Elasticsearch的配置文件中可以通过node.master、node.data来设
置节点类型。
node.master:表示节点是否具有成为主节点的资格 - true代表的是有资格竞选主节点 - false代表的是没有资格竞选主节点
node.data:表示节点是否存储数据
-
Node 节点组合
-
主节点+数据节点(master+data)默认
节点既有成为主节点资格,又存储数据
node.master: true node.date: true
-
数据节点(data)
节点没有成为主节点资格,不参与选举,只会存储数据
node.master: false node.date: true
-
客户端节点(client)
不会成为主节点,也不会存储数据,主要是针对海量请求的时候可以进行负载均衡
node.master: false node.date: false
-
-
分片
每个索引有1个或多个分片,每个分片存储不同的数据。分片可分为主分片(primary
shard)和复制分片(replica shard),复制分片是主分片的拷贝。默认每个主分片有一个复
制分片,每个索引的复制分片的数量可以动态地调整,复制分片从不与它的主分片在同一个
节点上
-
副本
这里指主分片的副本分片(主分片的拷贝)
提高恢复能力:当主分片挂掉时,某个复制分片可以变成主分片;
提高性能:get 和 search 请求既可以由主分片又可以由复制分片处理;
2. ES 的分布式架构
Elasticseasrch的架构遵循其基本概念:一个采用Restful API标准的高扩展性和高可用性的实时数据分
析的全文搜索引擎。
特性:
-
高扩展性:体现在Elasticsearch添加节点非常简单,新节点无需做复杂的配置,只要配置好集群信
息将会被集群自动发现。
-
高可用性:因为Elasticsearch是分布式的,每个节点都会有备份,所以宕机一两个节点也不会出现
问题,集群会通过备份进行自动复盘。
实时性:使用倒排索引来建立存储结构,搜索时常在百毫秒内就可完成。
分层:
-
第一层 —— Gateway:
Elasticsearch支持的索引快照的存储格式,es默认是先把索引存放到内存中,当内存满了之后再持久
化到本地磁盘。gateway对索引快照进行存储,当Elasticsearch关闭再启动的时候,它就会从这个
gateway里面读取索引数据;支持的格式有:本地的Local FileSystem、分布式的Shared FileSystem、Hadoop的文件系统HDFS、Amazon(亚马逊)的S3。
-
第二层 —— Lucene框架:
Elasticsearch基于Lucene(基于Java开发)框架。
-
第三层 —— Elasticsearch数据的加工处理方式:
Index Module(创建Index模块)、Search Module(搜索模块)、Mapping(映射)、River 代表
es的一个数据源(运行在Elasticsearch集群内部的一个插件,主要用来从外部获取获取异构数据,然后在Elasticsearch里创建索引;常见的插件有RabbitMQ River、Twitter River)。
-
第四层 —— Elasticsearch发现机制、脚本:
Discovery 是Elasticsearch自动发现节点的机制的模块,Zen Discovery和 EC2 discovery。EC2:亚
马逊弹性计算云 EC2 discovery主要在亚马云平台中使用。Zen Discovery作用就相当于solrcloud中的
zookeeper。zen Discovery 从功能上可以分为两部分,第一部分是集群刚启动时的选主,或者是新加
入集群的节点发现当前集群的Master。第二部分是选主完成后,Master 和 Folower 的相互探活。
Scripting 是脚本执行功能,有这个功能能很方便对查询出来的数据进行加工处理。
3rd Plugins 表示Elasticsearch支持安装很多第三方的插件,例如elasticsearch-ik分词插件、
elasticsearch-sql sql插件。
-
第五层 —— Elasticsearch的交互方式:
有Thrift、Memcached、Http三种协议,默认的是用Http协议传输
第六层 —— Elasticsearch的API支持模式:RESTFul Style API风格的API接口标准是当下十分流行的。Elasticsearch作为分布式集群,客户端到服务端,节点与节点间通信有TCP和Http通信协议,底层实现为Netty框架
解析Elasticsearch的分布式架构
分布式架构的透明隐藏特性
Elasticsearch是一个分布式系统,隐藏了复杂的处理机制
-
分片机制:将文本数据切割成n个小份存储在不同的节点上,减少大文件存储在单个节点上对设备带来
的压力。
分片的副本:在集群中某个节点宕掉后,通过副本可以快速对缺失数据进行复盘。
-
集群发现机制(cluster discovery):在当前启动了一个Elasticsearch进程,在启动第二个
Elasticsearch进程时,这个进程将作为一个node自动就发现了集群,并自动加入,前提是这些
node都必须配置一套集群信息。
-
Shard负载均衡:例如现在由10个 shard (分片),集群中由三个节点,Elasticsearch会进行均
衡的分配,以保持每个节点均衡的负载请求。
拓容机制
- 垂直扩容:用新机器替换已有的机器,服务器台数不变容量增加。
- 水平扩容:直接增加新机器,服务器台数和容量都增加。
reblance
- 增加或减少节点时会自动负载
主节点
主节点的主要职则是和集群操作的相关内容,如创建或删除索引,跟踪哪些节点是集群的一部分,并决
定哪些分片分配给相关的节点。稳定的主节点对集群的健康是非常重要的。
节点对等
每个节点都能接受请求,每个节点接受到请求后都能把该请求路由到有相关数据的其它节点上,接受原
始请求的节点负责采集数据并返回给客户端。
3. 集群环境搭建
4. 集群规划
1) 需要多大集群
从两个方面考虑:
- 当前的数据量有多大?数据增长情况如何?
- 机器配置如何?CPU、内存、硬盘规格?
推算的依据:
Elasticsearch JVM heap 最大可以设置32G 。
30G heap 大概能处理的数据量 10 T。如果内存很大如128G,可在一台机器上运行多个ES节点实例。
备注:集群规划满足当前数据规模+适量增长规模即可,后续可按需扩展。
两类应用场景:
-
A. 用于构建业务搜索功能模块,且多是垂直领域的搜索。数据量级几千万到数十亿级别。一般2-4台机
器的规模。
-
B. 用于大规模数据的实时OLAP(联机处理分析),经典的如ELK Stack,数据规模可能达到千亿或更
多。几十到上百节点的规模。
2) 集群的节点角色如何分配
节点角色:
Master
node.master: true 节点可以作为主节点
DataNode
node.data: true 默认是数据节点
Coordinate node 协调节点,一个节点只作为接收请求、转发请求到其他节点、汇总各个节点返回数
据等功能的节点,就叫协调节点,如果仅担任协调节点,将上两个配置设为false。
说明:一个节点可以充当一个或多个角色,默认三个角色都有
节点角色如何分配:A. 小规模集群,不需严格区分。B. 中大规模集群(十个以上节点),应考虑单独的角色充当。特别并发查询量大,查询的合并量大,可以增加独立的协调节点。角色分开的好处是分工分开,不互影响。如不会因协调角色负载过高而影响数据节点的能力。
3) 如何避免脑裂问题
什么是脑裂?
一个集群中只有一个A主节点,A主节点因为需要处理的东西太多或者网络过于繁忙,从而导致其他从节
点ping不通A主节点,这样其他从节点就会认为A主节点不可用了,就会重新选出一个新的主节点B。过
了一会A主节点恢复正常了,这样就出现了两个主节点,导致一部分数据来源于A主节点,另外一部分数
据来源于B主节点,出现数据不一致问题,这就是脑裂。
ES 如何解决?
-
6.x和之前版本 尽量避免脑裂,需要添加最小数量的主节点配置:
discovery.zen.minimum_master_nodes: (有master资格节点数/2) + 1
这个参数控制的是,选举主节点时需要看到最少多少个具有master资格的活节点,才能进行选举。官方
的推荐值是(N/2)+1,其中N是具有master资格的节点的数量。
在新版7.X的ES中,对es的集群发现系统做了调整,不再有discovery.zen.minimum_master_nodes这个控制集群脑裂的配置,转而由集群自主控制,并且新版在启动一个新的集群的时候需要有cluster.initial_master_nodes初始化集群列表。
常用做法(中大规模集群):
Master 和 dataNode 角色分开,配置奇数个master,如3
-
单播发现机制,配置master资格节点(5.0之前):
discovery.zen.ping.multicast.enabled: false —— 关闭多播发现机制,默认是关闭的
-
延长ping master的等待时长
discovery.zen.ping_timeout: 30(默认值是3秒)——其他节点ping主节点多久时间没有响应就认
为主节点不可用了。
es7中换成了 discovery.request_peers_timeout
4) 索引应该设置多少分片
注意:分片数指定后不可变,除非重建索引、
分片设置的可参考原则:ElasticSearch推荐的最大JVM堆空间是30~32G, 所以把你的分片最大容量限制为30GB, 然后再对分片数量做合理估算. 例如, 你认为你的数据能达到200GB, 推荐你最多分配7到8个分片。
在开始阶段, 一个好的方案是根据你的节点数量按照1.5~3倍的原则来创建分片. 例如,如果你有3个节点,
则推荐你创建的分片数最多不超过9(3x3)个。当性能下降时,增加节点,ES会平衡分片的放置。
对于基于日期的索引需求, 并且对索引数据的搜索场景非常少. 也许这些索引量将达到成百上千, 但每个
索引的数据量只有1GB甚至更小. 对于这种类似场景, 建议只需要为索引分配1个分片。如日志管理就是
一个日期的索引需求,日期索引会很多,但每个索引存放的日志数据量就很少。
5) 分片应该设置多少副本
副本设置基本原则:
为保证高可用,副本数设置为2即可。要求集群至少要有3个节点,来分开存放主分片、副本。
如发现并发量大时,查询性能会下降,可增加副本数,来提升并发查询能力。
注意:新增副本时主节点会自动协调,然后拷贝数据到新增的副本节点,副本数是可以随时调整的!
PUT /my_temp_index/_settings
{
"number_of_replicas": 1
}
五、数据模型构建
六、搜索实战
七、深度应用及原理剖析
1. 索引文档写入和近实时搜索原理
基本概念
-
Segments in Lucene
Elasticsearch 存储的基本单元是 shard , ES 中一个 Index 可能分为多个 shard, 事实上
每个 shard 都是一个 Lucence 的 Index,并且每个 Lucence Index 由多个 Segment 组成, 每个
Segment 事实上是一些倒排索引的集合, 每次创建一个新的 Document , 都会归属于一个新的
Segment, 而不会去修改原来的 Segment 。且每次的文档删除操作,会仅仅标记 Segment 中该文档
为删除状态, 而不会真正的立马物理删除, 所以说 ES 的 index 可以理解为一个抽象的概念。
-
Commits in Lucene
Commit 操作意味着将 Segment 合并,并写入磁盘。保证内存数据尽量不丢。但刷盘是很重的 IO 操
作, 所以为了机器性能和近实时搜索, 并不会刷盘那么及时。
-
Translog
新文档被索引意味着文档会被首先写入内存 buffffer 和 translog 文件。每个 shard 都对应一个 translog
文件
-
Refresh in Elasticsearch
在 Elasticsearch 中, _refresh 操作默认每秒执行一次, 意味着将内存 buffer 的数据写入到一个新
的 Segment 中,这个时候索引变成了可被检索的。写入新Segment后 会清空内存buffer。
-
Flush in Elasticsearch
Flush 操作意味着将内存 buffer 的数据全都写入新的 Segments 中, 并将内存中所有的 Segments
全部刷盘, 并且清空 translog 日志的过程。