ElasticSearch是一个实时分布式的高拓展全文搜索和分析引擎,是ELK(ElasticSearch, Kibana, Logstach的)技术的核心。
ElasticSearch的优势在于模糊与全文查询,虽然关系型数据库也能够做到like关键字的模糊查询,但是会遍历整个表数据,响应很慢,因此需要使用搜索更加快捷的ElasticSearch来进行处理。
ElasticSearch和Solr都属于应用很广的搜索引擎,他们的基础都是Lucene, 一个Apache开源的全文搜索的java核心工具包
腾讯的大数据搜索引擎,与ES和Solr相比
数据格式的对比,Index相当于一个数据库,Type相当于一个表,而Document对应了一行数据,Field对应了一个列,不过在后期的ElasticSearch中已经删除了Type的概念,一个文档的数据序列化格式为JSON
{
"name" : "John",
"sex" : "Male",
"age" : 25,
"birthDate": "1990/05/01",
"about" : "I love to go rock climbing",
"interests": [ "sports", "music" ]
}
对于一个索引数据量过大的时候,一个节点可能是存储不下这个索引里所有的数据的,因此这里引入了分片的概念,也就是将所有的数据分片存储在不同的节点当中,查询的时候会查询整个集群里面所有属于同一索引的分片。这样的好处在于不仅可以突破节点的数据存储量,还可以并行操作提高效率和吞吐量。这部分对于用户而言是透明的,elasticsearch会自行进行管理。
允许创建分片的一个或多个拷贝,这个拷贝叫做复制分片/副本,分片的优势在于
分片的数量可以在创建索引的时候指定,创建索引之后可以动态地改变复制的数量,但是分片数量是不能改变的。默认情况下会有一个主分片和一个复制分片,分片分配给某个节点的过程是由master节点完成的
一个ES集群有一个对应的名字,节点可以通过这个名字加入到集群当中,默认集群名称为“elasticsearch”
一个节点也由一个对应的名字指定,默认是一个漫威漫画的名字,服务器通过指定节点名字可以对节点进行连接。一个集群内部节点的名称要唯一
如果没有指定集群的名称,同一网络下的若干节点只要一启动,就都会加入到“elasticsearch”这个集群当中,他们能够互相发现彼此。
在节点1中的数据在节点2里面也是能被查询到的,当一个节点被选为主节点master时,他就会负责集群范围内所有的变更,包括增加、删除索引或增加删除节点等。
分片是ES最小的工作单元
将文档中的内容进行分词,作为索引,索引对应的值是文档的id,也就是从id对应内容反向成了内容对应id
ElasticSearch是基于Luence的,Luence引入了按段搜索的概念,每一个段就是一个倒排索引,查询时会采取轮询每一个段的方式进行,同时将搜到的内容进行聚合。以保证所有的内容都被正确地计算。
除了所有的段之外,es还会存储一个提交点,即一个列出了所有已知段的文件。
索引更新流程如下
由于从缓存中向磁盘写入新的段是十分浪费事件的,因此elasticSearch采用了一个存在缓存中的段的方式,将缓存区的内容写入一个可以被搜索的段中,这样缓存区的内容就可以被搜索到了,再将耗费时间长的磁盘写入过程异步进行提交就可以了。这个过程被成为refresh,每秒(这个事件是可以修改的)执行一次,也就是添加的新段会在一秒内被搜索到,因此是近实时搜索的特性。
进实时搜索的缓存段如果断电的话就消失了,因此持久化,也就是异步存储段到磁盘的过程也是必须被执行的。elasticSearch引入了translog日志来进行处理。
在缓存写入的过程当中,translog也会记录相应的内容,隔一段时间会进行全量的提交,也就是
采用了分段搜索虽然更新索引的开销较低,但是随着段的暴增,数据的搜索会变得缓慢,因此在elasticSearch当中引入了段合并的后台过程,小的段被合并到了大的段当中。段合并的过程如下
refresh的过程中启用了缓存的段并可以被搜索到
产生一个大的缓存段
选择大小相似的小段,将其写入大的缓存段当中(这一步并不影响原先小段被搜索)
新段打开用于搜索
老段删除
合并过程占用了大量的CPU资源,因此elasticSearch对合并过程进行了资源的限制,保证搜索过程能被很好地执行
文档分析器的作用在于将一整块内容划分为独立的词条并进行一些相关的处理保证“可搜索性”,一次文档的分析过程被分成了三步
当然分词器是用在查询全文域的,当进行精确查询的时候,比如使用+关键字,是不会用分析器进行处理的
有标准分析器,简单分析器,空格分析器,语言分析器等,它们根据不同的规则进行了词条的划分
进行常见的中文分词并支持进行自定义拓展词典(远程的或者本地的都可以)
除了这些之外ES也是支持自定义分词器的
Web1做了-1操作,Web2也做了-1操作,但是二者引发了并发所带来的冲突,这就是文档冲突现象,其实就是一个并发问题
文档冲突现象有两种处理方式,一是悲观并发控制,二是乐观并发控制
采用RESTful风格进行处理,相信的条件封装在请求体的JSON格式数据当中
RESTful风格简而言之就是
支持以下几种操作:
同样支持上述的操作,包括排序、过滤、分页等等相关的操作
SpringDataElasticSearch对ES的相应API进行了封装,能够更方便地构建所需的代码
引入依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-elasticsearchartifactId>
dependency>
配置文件
spring:
data:
elasticsearch:
cluster-name: my-application
cluster-nodes: 192.168.211.132:9300
配置说明
connection-timeout:服务连接超时时间
socket-connect:HTTP请求超时时间
ribbon.ReadTimeout: Feign请求读取数据超时时间
timeoutInMilliseconds:feign连接超时时间
cluster-name:Elasticsearch的集群节点名称,这里需要和Elasticsearch集群节点名称保持一致
cluster-nodes:Elasticsearch节点通信地址
启动类
@SpringBootApplication(exclude={DataSourceAutoConfiguration.class})
@EnableEurekaClient
public class SearchApplication {
public static void main(String[] args) {
/**
* Springboot整合Elasticsearch 在项目启动前设置一下的属性,防止报错
* 解决netty冲突后初始化client时还会抛出异常
* availableProcessors is already set to [12], rejecting [12]
***/
System.setProperty("es.set.netty.runtime.available.processors", "false");
SpringApplication.run(SearchApplication.class,args);
}
}
对于POJO,设置Document和Feild注解设置,需要与elasticSearch中的设置一致
@Document(indexName = "skuinfo",type = "docs")
public class SkuInfo implements Serializable {
//商品id,同时也是商品编号
@Id
private Long id;
//SKU名称
@Field(type = FieldType.Text, analyzer = "ik_smart")
private String name;
//商品价格,单位为:元
@Field(type = FieldType.Double)
private Long price;
}
DAO层的设置也比较简单,实现相应的类即可
@Repository
public interface SkuEsMapper extends ElasticsearchRepository<Sku,Long> {
}
许多简单查询、分页查询、聚合查询、高亮查询都是可以用类中封装的方法进行实现的
系统中的数据,随着业务的发展,时间的推移,将会非常多,而业务中往往采用模糊查询进行数据的搜索,而模糊查询会导致查询引擎放弃索引,导致系统查询数据时都是全表扫描,在百万级别的数据库中,查询效率是非常低下的,而我们使用 ES 做一个全文索引,将经常查询的系统功能的某些字段,比如说电商系统的商品表中商品名,描述、价格还有 id 这些字段我们放入 ES 索引库里,可以提高查询速度。
简而言之,因为某些原因出现了多个master,比如两个机房分别存放了三个节点,机房间的网络中断导致机房2中的节点无法访问机房1中的节点,于是选取了两个master,就造成了脑裂
搜索被执行成一个两阶段过程,我们称之为 Query Then Fetch;
通过HLL算法基于概率进行估算所得到的,精度是可控的
elasticSearch-Head插件(丑的一批)
Kibana(属实好看)
字典树又称单词查找树,Trie 树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排
序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。
Trie 的核心思想是空间换时间,利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的。
它有 3 个基本性质:
集群是一个或多个节点(服务器)的集合,它们共同保存您的整个数据,并提供跨所有节点的联合索
引和搜索功能。群集由唯一名称标识,默认情况下为“elasticsearch”。此名称很重要,因为如果节点设
置为按名称加入群集,则该节点只能是群集的一部分。
节点是属于集群一部分的单个服务器。它存储数据并参与群集索引和搜索功能。
索引就像关系数据库中的“数据库”。它有一个定义多种类型的映射。索引是逻辑名称空间,映射到一个或多个主分片,并且可以有零个或多个副本分片。 MySQL =>数据库 Elasticsearch =>索引
文档类似于关系数据库中的一行。不同之处在于索引中的每个文档可以具有不同的结构(字段),但
是对于通用字段应该具有相同的数据类型。 MySQL => Databases => Tables => Columns / Rows Elasticsearch => Indices => Types =>具有属性的文档
类型是索引的逻辑类别/分区,其语义完全取决于用户。
倒排索引是搜索引擎的核心。搜索引擎的主要目标是在查找发生搜索条件的文档时提供快速搜索。ES中的倒排索引其实就是 lucene 的倒排索引,区别于传统的正向索引,倒排索引会再存储数据时将关键词和数据进行关联,保存到倒排表中,然后查询时,将查询内容进行分词后在倒排表中进行查询,最后匹配数据即可