ES简介
一个叫Shay Banon开发者,在2010年2月发布了第一个公开版本。
Elasticsearch(ES)是一个基于Lucene(Lucene:Lucene是一个Java全文搜索引擎,完全用 Java 编写。Lucene不是一个完整的应用程序,而是一个代码库和API)构建的开源、分布式、RESTful接口的全文搜索引擎。Elasticsearch还是一个分布式文档数据库,其中每个字段均可被索引,而且每个字段的数据均可被搜索,ES能够横向扩展至数以百计的服务器存储以及处理PB级的数据。可以在极短的时间内存储、搜索和分析大量的数据。通常作为具有复杂搜索场景情况下的核心发动机。
相关概念解读
全文检索引擎
其工作原理是计算机索引程序通过扫描文章中的每一个词,对每一个词建立一个索引,指明该词再文章中出现的次数和位置。当用户查询时,检索程序就根据实现建立的索引进行查找,并将查找的结果反馈给用户的检索方式(举例:字典)
数据类型
- 结构化数据:具有固定格式或有限长度的数据
- 非结构化数据:又称全文数据,指不定长度或无固定格式的数据
搜索方式
针对数据类型的不同,对应的搜索方式也有别:
- 结构化数据:通过关系型数据库的table方式存储和搜索
- 非结构化数据:
- 顺序扫描————按照顺序依次查找->耗时、低效
- 全文检索————将数据中的一部分信息提取出来,重新组织使其变得有一定结构,然后对此有一定结构的数据进行搜索,从而达到搜索相对较快的目的(这部分从非结构化数据中心提取出来的然后重新组织的信息,就叫索引)
全文检索使用背景
- 搜索数据对象是大量的非结构化文本数据
- 文件记录量达到数十万或数百万甚至更多
- 支持大量基于交互式文本的查询
- 需要非常灵活的全文搜索查询
- 对高度相关的搜索结构有特殊需求
- 对不同记录类型,非文本数据操作或事务处理需求相对较少
主流全文检索引擎
Lucene、Solr、Elastic Search
ES特点
- 基于分布式————将数据进行分段分片存储并在各个分片上进行查询操作
- 容差容错机制————集群部署时,通过设置副本分片的机制,实现即时一个节点挂掉,数据也能在别的节点分片上正常进行查询
- 基于文档————文档存储
- 全文全库检索
- 可处理数据量大
- 分布式实施文档存储,每个字段可以被索引和搜索
- 能胜任上百个服务节点的扩展,支持PB级别的结构化数据和非结构化数据
ES索引方式————倒排索引
一个倒排索引由文档中所有不重复词的列表构成,对于其中每个词,有一个包含它的文档列表。
对于不同的文档中每个词的出现与否做出标记。
例如有两个文档:
- The quick brown fox jumped over the lazy dog
- Quick brown foxes leap over lazy dogs in summer
生成的倒排索引如下图所示:
ES核心概念
- Cluster集群: 一个集群是由一个或多个节点组成的(集群中的节点通过设置相同的 cluster.name,来分类集群的)
- Node节点: 一个运行中的Elasticsearch实力称为一个节点
- Shade分片: 一个分片是一个底层的工作单元,它仅保存了全部数据中的一部分(主分片即主要存储数据的分片,副分片即主分片的备份,存在于不同的节点上,若节点越多,主分片对应的副分片存在的节点也会越多。容差容错机制就是在备份中产生的,如果运行中一个节点出现故障、主分片上的数据全部丢失,那么存有该主分片副本的节点就会自动接替之前的工作)
- Index索引: 相当于sql中的database
- Type类型: 相当于db中的table
- Document文档: 相当于table中的一条数据
集群内的原理
- 一个运行中的Elasticsearch实例称为一个节点,而集群是由一个或者多个拥有相同 cluster.name 配置的节点组成,它们共同承担数据和负载的压力。当有节点加入集群中或者从集群中移除节点时,集群将会重新平均分布所有的数据。
- 当一个节点被选举成为主节点时,它将负责管理集群范围内的所有变更,例如增加、删除索引,或者增加、删除节点等。而主节点并不需要涉及到文档级别的变更和搜索等操作。任何节点都可以成为主节点。
一个集群中有一个包含空内容的节点
同一个集群中有两个节点,其中Node1为主节点
分片与副本分片
- 一个分片是一个底层的工作单元,它仅保存了全部数据中的一部分。
- Elasticsearch 是利用分片将数据分发到集群内各处的。分片是数据的容器,文档保存在分片内,分片又被分配到集群内的各个节点里。当你的集群规模扩大或者缩小时,Elasticsearch会自动的在各节点中迁移分片,使得数据仍然均匀分布在集群里。
- 一个分片可以是主分片或者副本分片。索引内任意一个文档都归属于一个主分片,所以主分片的数目决定着索引能够保存的最大数据量。
关于索引和分片
一个Lucene索引在es称为分片,一个es索引是分片的集合。
Elasticsearch在索引中搜索时,它发送查询到每一个属于索引的分片,然后合并每个分片的结果到一个全局的结果集(分布式搜索,后面有提到)。
以下为分片的例子:
(上图表示有一个节点,节点中有三个主分片)
(上图表示有两个节点<其中Node1为主节点>,且Node中存有三个主分片,Node2中存有三个副本分片<主要的数据被复制了一次,产生了一套主分片的副本分片>)
(上图表示共有三个节点,主分片被复制了一次,产生了一套副本分片,主分片与副本分片平均分派在三个节点中)
(上图表示共有三个节点,主分片被复制了两次,产生了两套副本分片,主分片与副本分片平均分派在三个节点中)
(上图表示共有两个节点,其中Node1挂掉,随机分配Node2为主节点,并转移分配对应的主分片————容差容错机制的体现)
分片内的原理
以索引一个新文档为例:
当用户向一个节点提交了一个索引新文档的请求,节点会计算新文档应该加入到哪个分片(shard)中。每个节点都存储有每个分片存储在哪个节点的信息,因此协调节点会将请求发送给对应的节点。注意这个请求会发送给主分片,等主分片完成索引,会并行将请求发送到其所有副本分片,保证每个分片都持有最新数据。
(一个Lucene索引包含一个提交点和三个段,如上图所示)
(一个文档被索引之后,就会被添加到内存缓冲区,并且追加到了translog)
(分片每秒被刷新(refresh)一次,这些在内存缓冲区中的文档被写入到一个新的段中,这个段被打开,当前可以被搜索到,但该段并未被写入到磁盘中,因此,此时节点挂掉的话,该段将不复存在;内存缓冲区被清空,但事务日志不会<为节点挂掉重启后做数据恢复>)
(这个进程继续工作,更多的文档被添加到内存缓冲区和追加到事务日志)
(每隔一段时间--索引被刷新(flush);一个新的translog被创建,并且一个全量提交被执行;所有在内存缓冲区中的文档被写入一个新的段中,缓冲区被清空;一个提交点被写入磁盘中;文件系统缓存通过fsync被刷新;老的事务日志被删除)
段合并
图示(两个提交了的段和一个未提交的段正在被合并到一个更大的段)
- 背景:由于自动刷新流程每秒会创建一个新的段,这样会导致短时间内的段数量暴增。而段数目太多会带来较大的麻烦。每一个段都会消耗文件句柄、内存和cpu运行周期。更重要的是,每个搜索请求都必须轮流检查每个段;所以段越多,搜索也就越慢。
- 实施:合并进程选择一小部分大小相似的段,并且在后台将它们合并到更大的段中。这并不会中断索引和搜索。
- 结果:新的段被刷新(flush)到了磁盘;新的段被打开用来搜索;老的段被删除。
结果图示
总流程图
分布式搜索
图示
- 查询请求可以被某个主分片或某个副本分片处理,协调节点将在之后的请求中轮询所有的分片拷贝来分摊负载。
- 如果客户端要求返回结果排序中从第from名开始的数量为size的结果集,则每个节点都需要生成一个from+size大小的结果集,因此优先级队列的大小也是from+size。分片仅会返回一个轻量级的结果给协调节点,包含结果集中的每一个文档的ID和进行排序所需要的信息。
- 协调节点会将所有分片的结果汇总,并进行全局排序,得到最终的查询排序结果。此时查询阶段结束。
ES安装
系统环境
- CentOS 7.6.1810
- jdk 1.8.0_201
elasticsearch安装方法
tar -zxvf elasticsearch-6.6.0.tar.gz -C /opt/module/ # 解压安装包
vi elasticsearch.yml # 修改配置文件
cluster.name: my-application # 集群名称(多集群时候只需节点名称一直即可)
node.name: node-1 # 节点名称————同一集群中不能重复
path.data: /opt/module/elasticsearch-6.6.0/data # 数据路径
path.logs: /opt/module/elasticsearch-6.6.0/logs # 日志路径
bootstrap.memory_lock: false
bootstrap.system_call_filter: false
network.host: 192.168.1.8 # 网络地址
http.port: 9200 # 端口
discovery.zen.ping.unicast.hosts: ["Hosts"] # 主机名
ES启动
elasticsearch禁止使用root用户启动,需要新建一个用户
./bin/elasticsearch // 解压目录下执行
Spring Boot 集成
使用Spring Data Elasticsearch
增加POM文件
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
Spring data elasticsearch 与 es 版本对照
spring data elasticsearch | elasticsearch |
---|---|
3.2.x | 6.5.0 |
3.1.x | 6.2.2 |
3.0.x | 5.5.0 |
2.1.x | 2.4.0 |
2.0.x | 2.2.0 |
1.3.x | 1.5.2 |
增加配置
spring:
data:
elasticsearch:
cluster-name: elasticsearch
cluster-nodes: 172.0.0.1:9200
repositories:
enabled: true
使用
@Data
@AllArgsConstructor
@Document(indexName = "human", type = "student") ////indexName索引名称,type类别
@Id
public class Student {
private String name;
private Integer age;
private String sex;
}
@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
@Test
public void test() {
Student student = new Student(1, "张三", 100, "女");
//新增
IndexQuery indexQuery = new IndexQueryBuilder()
.withIndexName("human")
.withType("student")
.withId(student.getId()+"")
.withObject(student) //对象或集合
.build();
elasticsearchTemplate.index(indexQuery);
}
也可通过创建接口实现ElasticsearchRepository<?,?>方法,通过方法注解@Query来实现查询等操作,示例:
public interface StudentRepository extends ElasticsearchRepository<Student, String> {
@Query("{"bool" : {"must" : {"field" : {"name" : "?0"}}}}")
Page<Student> findByName(String name,Pageable pageable);
}
ES查询示例
查询相关转到