ElasticSearch简介
基本介绍
Elastic search 是一个基于Lucene(一个开源的全文搜索引擎工具包)构建的开源、分布式、RESTful接口全文搜索引擎。es还是一个分布式文档数据库,可以扩展至数以百计的服务器存储和处理PB(1024TB)级的数据。
Elasticsearch是一个接近实时的搜索平台。这意味着,从索引一个文档直到这个文档能够被搜索到有一个轻微的延迟(通常是1秒)
Lucene 是一个开源的全文检索引擎工具包, 最初由 Doug Cutting 开发。 早在 1997 年, 资深全文检索专家 Doug Cutting 用一个周末的时间, 使用 Java 语言创作了一个文本搜索的开源函数库, 目的是为各种中小型应用软件加入全文检索功能。 不久之后, Lucene 诞生了, 2000年 Lucene 成为 Apache 开源社区的一个子项目。 随着 Lucene 被人们熟知, 越来越多的用户和研发人员加入其中, 完善并壮大项目的发展, Lucene 已成为最受欢迎的具有完整的查询引擎和索引引擎的全文检索库。
lucene简介
数据库和全文检索的区别
数据库和Lucene建立索引都是为了查找方便,但是数据库仅仅针对部分字段进行建立,且需要把数据转化为格式化信息,并予以保存。而全文检索是将全部信息按照一定方式进行索引。
比较项 | Lucene检索 | 数据库检索 |
数据检索 | 从Lucene的索引文件中检出 | 由数据库索引检索记录 |
索引结构 | Document(文档) | Record(记录) |
查询结果 | Hit:满足关系的文档组成 | 查询结果集:包含关键字的记录组成 |
全文检索 | 支持 | 不支持 |
结果排序 | 设置权重,进行相关性排序 | 不能排序 |
简单来说,数据库是模糊查询:
select * from product where pname like '%服%',速度较慢。且不灵活
全文检索可以快速、准确找到想要的数据
快:先从索引库查找,准确找到数据
准:对查询条件进行分词,然后对查询的结果进行相关度排序,得分越高,排的越靠前。
倒排索引
文档通常保存在各种数据库管理系统之中, 比如 Oracle、MySQL 等。但是搜索引擎中的数据不能保存到数据库中,主要是因为数据库不能满足搜索引擎的需求,
原因有二:
一是搜索引擎中的数据量非常庞大;
二是搜索引擎使用的数据操作非常简单,一般只需增删改查这几个基本功能,一般的数据库系统则支持大而全的功能,损失了速度和空间,大量用户检索则要求搜索引擎响应时间必须很快,检索效率要非常高,数据库系统在检索响应时间和检索并发度方面都不能满足需求。
倒排索引 Clnverted index ),也常被称为反向索引,是一种索引方法,被用来存储在全文搜索下某个单词在一个文档或者一组文档中的存储位置的映射,它是文档检索系统中最常用的数据结构。
下面以简单通俗的例子来理解倒排索引 ,假设现在有两个文档 doc1、 doc2, doc1包含3个关键词 :中国、 美国、韩国, doc2 中包含4个关键词:中国、美国、德国、英国,文档和词语的包含关系(也就是正排索引),见表 1-2。
那么词语所属的文档关系,也就是倒排索引,见表 1-3
如果想查找包含关键词“美国”的文档 那么结果就是 doc1 和 doc2 。这样从文档包含单 词到单词所属文档的转换 就是倒排的由来。我们在搜索引擎中输入关键词进行查询,就是一次查找哪些文档包含查询关键词的过程。
下面我们通过具体实例深入理解倒排索引,通过简单文档以小见大,体验倒排索引的构建过程。
如表所示,在互联网上找了4条科技新闻作为一个文档集合,我们以新闻标题作为文档内容,给每个文档设置一个连续的整数编号作为文档 ID。
对于文档内容先要经过词条化处理。和英文不同的是,英文通过空格分隔单词,中文的词与词之间没有明确的分隔符号,经过分词系统进行中文分词以后把矩阵切分成一个个的词条,文档4会被分成“谷歌” “开源” “机器” “学习” “工具” 5个词项。
文档频率也是倒排记录表的长度。依次统计各个词项的文档频率和倒排记录表,构建倒排索引过程如表所示。
检索模型
布尔检索模型等(原理略)
lucene特点
稳定, 索引性能高
- 现代硬盘上每小时能够索引 150GB 以上的数据。
- 对内存的要求小:只需要 1MB 的堆内存。
- 增量索引和批量索引一样快。
- 索引的大小约为索引文本大小的 20%〜30%。
高效、准确、高性能的搜索算法
- 搜索排名—最好的结果显示在最前面。
- 许多强大的查询类型: 短语查询、 通配符查询、 近似查询、 范围查询等。
- 对字段级别搜索(如标题, 作者, 内容) 。
- 可以对任意字段排序。
- 支持搜索多个索引并合并搜索结果。
- 支持更新操作和查询操作同时进行。
- 灵活的切面、 高亮、 join 和 group by 功能。
- 速度快, 内存效率高, 容错性好。
- 可选排序模型, 包括向量空间模型和 BM25 模型。
- 可配置存储引擎。
高效、准确、高性能的搜索算法
- 作为 Apache 开源许可, 在商业软件和开放程序中都可以使用 Lucene。
- 100%纯 Java 编写。
- 对多种语言提供接口。
几个重要概念
analyzer
Analyzer是分析器,它的作用是把一个字符串按某种规则划分成一个个词语,并去除其中的无效词语。
document
用户提供的源是一条条记录,它们可以是文本文件、字符串或者数据库表的一条记录等等。一条记录经过索引之后,就是以一个Document的形式存储在索引文件中的。用户进行搜索,也是以Document列表的形式返回。
field
一个Document可以包含多个信息域,例如一篇文章可以包含“标题”、“正文” 等信息域,这些信息域就是通过Field在Document中存储的。
Field有两个属性可选:存储和索引。通过存储属性你可以控制是否对这个Field进行存储;通过索引属性你可以控制是否对该Field进行索引。
term
term是搜索的最小单位,它表示文档的一个词语,term由两部分组成:它表示的词语和这个词语所出现的field。
tocken
tocken是term的一次出现,它包含term文本和相应的起止偏移,以及一个类型字符串。一句话中可以出现多次相同的词语,它们都用同一个term表示,但是用不同的tocken,每个tocken标记该词语出现的地方。
segment
添加索引时并不是每个document都马上添加到同一个索引文件,它们首先被写入到不同的小文件,然后再合并成一个大索引文件,这里每个小文件都是一个segment。
索引流程
- 索引过程如下:
- 创建一个IndexWriter用来写索引文件,它有几个参数,#{INDEX_DIR}是索引文件所存放的位置,Analyzer便是用来对文档进行词法分析和语言处理的。
- 创建一个Document代表我们要索引的文档。
- 将不同的Field加入到文档中。我们知道,一篇文档有多种信息,如题目,作者,修改时间,内容等。不同类型的信息用不同的Field来表示。
- IndexWriter调用函数addDocument()将索引写到索引文件夹中。
- 搜索过程如下:
- IndexReader将磁盘上的索引信息读到内存,#{INDEX_DIR}就是索引文件存放的位置。
- 创建IndexSearcher准备惊醒搜索。
- 创建Analyzer用来对查询语句进行词法分析和语言处理。
- 创建QueryParser用来对查询语句进行语法分析。
- QueryParser调用parser()进行语法分析,形成查询语法树,放到Query中。
- IndexSearcher调用search()对查询语法树Query进行搜索,得到结果TopScoreDocCollector。
elasticsearch
lucene与elasticsearch关系
如图中Lucene部署在单台机器上,磁盘空间为1T。当数据量很大,超过1T时,在单台机器上是放不了的,需要分布式的散落在多台机器上。如果其中一台机器宕机,将会导致数据丢失;而且自己来实现搜索功能和多台机器通信的过程,比较麻烦。
因此,Elasticsearch应运而生
Elasticsearch:基于Lucene,隐藏复杂性,提供简单易用的restful api接口、Java api接口及其它语言的api接口
elasticsearch特点
- 分布式的文档存储引擎,搜索引擎和分析引擎。
- 支持PB级数据
- 自动维护数据的分布到多个节点的索引的的建立,还有搜索请求分布到多个节点的执行。
- 自动维护数据的冗余副本,保证当有机器宕机时不会丢失任何数据
- 简单易用的restful api接口
- 封装了更多的高级功能,以给我们提供更多高级的支持,让我们快速的开发应用,开发更加复杂的应用,复杂的搜索功能,聚合分析的功能
elasticsearch与solr对比
优缺点对比
检索速度
- 当单纯的对已有数据进行搜索时,Solr更快。
- 当实时建立索引时, Solr会产生io阻塞,查询性能较差, Elasticsearch具有明显的优势。
- 随着数据量的增加,Solr的搜索效率会变得更低,而Elasticsearch却没有明显的变化。
- 大型互联网公司,实际生产环境测试,将搜索引擎从Solr转到Elasticsearch以后的平均查询速度有了50倍的提升。
ES VS solr总结
- 二者安装都很简单。
- Solr 利用 Zookeeper 进行分布式管理,而 Elasticsearch 自身带有分布式协调管理功能。
- Solr 支持更多格式的数据,比如JSON、XML、CSV,而 Elasticsearch 仅支持json文件格式。
- Solr 官方提供的功能更多,而 Elasticsearch 本身更注重于核心功能,高级功能多有第三方插件提供
- Solr 在传统的搜索应用中表现好于 Elasticsearch,但在处理实时搜索应用时效率明显低于 Elasticsearch。
- Solr 是传统搜索应用的有力解决方案,但 Elasticsearch 更适用于新兴的实时搜索应用。
elasticsearch核心概念
接近实时(NRT)
Elasticsearch 是一个接近实时的搜索平台。这意味着,从索引一个文档直到这个文档能够被搜索到有一个轻微的延迟(通常是1 秒)。
集群(cluster)
一个集群就是由一个或多个节点组织在一起,它们共同持有你整个的数据,并一起提供索引和搜索功能。一个集群由一个唯一的名字标识,这个名字默认就是“elasticsearch”。
这个名字是重要的,因为一个节点只能通过指定某个集群的名字,来加入这个集群。
节点(node)
一个节点是你集群中的一个服务器,作为集群的一部分,它存储你的数据,参与集群的索引和搜索功能。和集群类似,一个节点也是由一个名字来标识的,默认情况下,这个名字是一个随机的漫威漫画角色的名字,这个名字会在启动的时候赋予节点。
- 节点集群配置:一个节点可以通过配置集群名称的方式来加入一个指定的集群。默认情况下,每个节点都会被安排加入到一个叫做“elasticsearch”的集群中。
- 协同工作:节点是Elasticsearch运行中的实例,而集群则包含一个或多个具有相同cluster.name的节点,它们协同工作,共享数据,并共同分担工作负荷。由于节点是从属集群的,集群会自我重组来均匀地分发数据。
- 选主:集群中的一个节点会被选为master节点,它将负责管理集群范畴的变更,例如创建或删除索引,添加节点到集群或从集群删除节点。master节点无需参与文档层面的变更和搜索,这意味着仅有一个master节点并不会因流量增长而成为瓶颈。任意一个节点都可以成为master节点。我们可以访问包括master节点在内的集群中的任一节点。每个节点都知道各个文档的位置,并能够将我们的请求直接转发到拥有我们想要的数据的节点。无论我们访问的是哪个节点,它都会控制从拥有数据的节点收集响应的过程,并返回给客户端最终的结果。
索引(index)
一个索引就是一个拥有几分相似特征的文档的集合。比如说,你可以有一个客户数据的索引,另一个产品目录的索引,还有一个订单数据的索引。
一个索引由一个名字来标识(必须全部是小写字母的),并且当我们要对对应于这个索引中的文档进行索引、搜索、更新和删除的时候,都要使用到这个名字。在一个集群中,如果你想,可以定义任意多的索引。
类型(type)
在一个索引中,你可以定义一种或多种类型。一个类型是你的索引的一个逻辑上的分类/分区,其语义完全由你来定。
每一个类型都拥有自己的映射(mapping)或者结构定义,它们定义了当前类型下的数据结构,类似于数据库表中的列。所有类型下的文档会被存储在同一个索引下,但是映射会告诉Elasticsearch不同的数据应该如何被索引。
文档(document)
一个文档是一个可被索引的基础信息单元。比如,你可以拥有某一个客户的文档,某一个产品的一个文档,当然,也可以拥有某个订单的一个文档。文档以JSON(Javascript Object Notation)格式来表示,而JSON是一个到处存在的互联网数据交互格式。
在一个index/type里面,你可以存储任意多的文档。注意,尽管一个文档,物理上存在于一个索引之中,文档必须被索引/赋予一个索引的type。
索引->数据库
类型->表(es逐步去除type的概念。)
文档->记录
DB -> Databases -> Tables -> Rows -> Columns
ES -> Indices -> Types -> Documents -> Fields
映射(mapping)
mapping相当于表结构/java bean,它定义了索引中的每个字段的类型,和索引范围内的设置。映射可以事先被定义,也可以在第一次存储文档的时候自动识别
分片(shards)
一个索引可以存储超出单个结点硬件限制的大量数据。比如,一个具有10 亿文档的索引占据1TB 的磁盘空间,而任一节点都没有这样大的磁盘空间;或者单个节点的计算能力达不到期望的复杂功能的要求。这种情况下,可以将数据切分,每部分是一个单独的apache lucene索引,称为分片。每个分片可以被存储在集群的不同节点上。
为了解决这个问题,Elasticsearch 提供了将索引划分成多份的能力,这些份就叫做分片。当你创建一个索引的时候,你可以指定你想要的分片的数量。每个分片本身也是一个功能完善并且独立的“索引”,这个“索引”可以被放置到集群中的任何节点上。
分片之所以重要,主要有两方面的原因:
- 允许你水平分割/扩展你的内容容量
- 允许你在分片(潜在地,位于多个节点上)之上进行分布式的、并行的操作,进而提高性能/吞吐量
至于一个分片怎样分布,它的文档怎样聚合回搜索请求,是完全由Elasticsearch 管理的,对于作为用户的你来说,这些都是透明的。
复本(replicas)
在一个网络/云的环境里,失败随时都可能发生,在某个分片/节点不知怎么的就处于离线状态,或者由于任何原因消失了,这种情况下,有一个故障转移机制是非常有用并且是强烈推荐的。为此目的,Elasticsearch 允许你创建分片的一份或多份拷贝,这些拷贝叫做复制分片,或者直接叫复制。
复制之所以重要,有两个主要原因:
- 在分片/节点失败的情况下,提供了高可用性。因为这个原因,注意到复制分片从不与原/主要(original/primary)分片置于同一节点上是非常重要的。
- 扩展你的搜索量/吞吐量,因为搜索可以在所有的复制上并行运行
默认情况下,Elasticsearch 中的每个索引被分片5 个主分片和1 个复制,这意味着,如果你的集群中至少有两个节点,你的索引将会有5 个主分片和另外5 个复制分片(1 个完全拷贝),这样的话每个索引总共就有10 个分片。
River
代表es的一个数据源,也是其它存储方式(如:数据库)同步数据到es的一个方法。它是以插件方式存在的一个es服务,通过读取river中的数据并把它索引到es中,官方的river有couchDB的,RabbitMQ的,Twitter的,Wikipedia的。
Gateway
代表es索引的持久化存储方式,es默认是先把索引存放到内存中,当内存满了时再持久化到硬盘。当这个es集群关闭再重新启动时就会从gateway中读取索引数据。es支持多种类型的gateway,有本地文件系统(默认),分布式文件系统,Hadoop的HDFS和amazon的s3云存储服务。
discovery.zen
代表es的自动发现节点机制,es是一个基于p2p的系统,它先通过广播寻找存在的节点,再通过多播协议来进行节点之间的通信,同时也支持点对点的交互。
Transport
代表es内部节点或集群与客户端的交互方式,默认内部是使用tcp协议(9300端口)进行交互,同时它支持http协议(json格式)(9200端口)、thrift、servlet、memcached、zeroMQ等的传输协议(通过插件方式集成)。
elasticsearch核心api介绍
elasticsearch提供了 REST API 的操作接口对底层进行了封装,语法采用DSL语法结构。
DSL语法参考:https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl.html
RESTful接口URL的格式:
http://192.168.10.16:9200/<index>/<type>/[<id>]
其中index、type是必须提供的。
id是可选的,不提供es会自动生成。
index、type将信息进行分层,利于管理。
index可以理解为数据库;type理解为数据表;id相当于数据库表中记录的主键,是唯一的。
新建和删除 Index
新建一个名叫store的 Index。
|
通常服务器操作成功会返回一个 JSON 对象,里面的acknowledged
字段表示操作成功。
|
然后,我们发出 DELETE 请求,删除这个 Index。
|
简单增删改查
#向store索引中添加一些书籍
|
#在linux中通过curl的方式查询
|
#在添加一个书的信息
|
# 通过ID获得文档信息
|
#通过_source获取指定的字段
|
#可以通过覆盖的方式更新
|
# 或者通过 _update API的方式单独更新你想要更新的
|
#删除一个文档
|
基本查询:
- 查询所有的商品:
|
查询商品名称包含 toothbrush 的商品,同时按照价格降序排序
|
- 分页查询商品:
|
- 指定查询结果字段(field)
|
-
范围查询:例搜索商品名称包含 toothbrush,而且售价大于 400 元,小于 700 的商品
gte 大于或等于 gt 大于 lte 小于或等于 lt 小于
|
- match 用法(与 term 进行对比):查询的字段内容是进行分词处理的,只要分词的单词结果中,在数据中有满足任意的分词结果都会被查询出来
|
- match 还有一种情况,就是必须满足分词结果中所有的词,而不是像上面,任意一个就可以的。
看下面的JSON其实你也可以猜出来,其实上面的JSON和下面的 JSON 本质是operator的差别,上面是or,下面是and关系
|
- match还还有一种情况,就是必须满足分词结果中百分比的词,假如要求50%命中其中两个词就返回,我们可以这样)
|
- multi_match用法,查询product_name和product_desc字段中,只要有:toothbrush关键字的就查询出来
|
- match_phrase 用法(短语搜索)(与match进行对比),对这个查询词不进行分词,必须完全匹配查询词才可以作为结果显示
|
- term用法(与 match 进行对比)(term一般用在不分词字段上的,因为它是完全匹配查询
|
- terms用法,类似于数据库的in
|
- query和filter差异,只用query
|
- 只用filter, 下面语句使用了 constant_score 查询,它可以包含查询或过滤,为任意一个匹配的文档指定评分1,不需再计算评分
|
- query 和 filter 一起使用的话,filter 会先执行
- 从搜索结果上看:
- filter,只查询出搜索条件的数据,不计算相关度分数
- query,查询出搜索条件的数据,并计算相关度分数,按照分数进行倒序排序
- 从性能上看:filter(性能更好,无排序),无需计算相关度分数,也就无需排序,内置的自动缓存最常使用查询结果的数据;
- query(性能较差,有排序),要计算相关度分数,按照分数进行倒序排序,没有缓存结果的功能
- filter 和 query 一起使用可以兼顾两者的特性,需要具体业务具体分析。
多搜索条件组合查询
bool过滤查询,可以做组合过滤查询
SELECT * FROM books WHERE (price = 35.99 OR price = 99.99) AND publish_date != "2016-02-06"
类似的,Elasticsearch也有 and, or, not这样的组合条件的查询方式,格式如下:
{
"bool" : {
"must" : [],
"should" : [],
"must_not" : [],
}
}
# must: 条件必须满足,相当于 and
# should: 条件可以满足也可以不满足,相当于 or
# must_not: 条件不需要满足,相当于 not
- 经常会遇到复杂查询,例如:SELECT * FROM books WHERE price = 35.99 OR ( publish_date = "2016-02-06" AND price = 99.99 )
|
elasticsearch常用api:
1、获取ElasticSearch信息:集群名称、版本等
GET /
例:
|
2、获取Elasticsearch状态:分片健康状态、所有索引、每个索引文档数量、存储大小、操作历史等
GET /_stats
例:
|
3、获取节点状态:JVM、GC、进程线程等信息
GET /_nodes/stats
例:
|
4、获取集群节点:节点主从关系
GET /_nodes
例:
|
5、获取插件信息
GET /_nodes/plugins
例:
|
6、群集状态:所有分片信息
GET /_cluster/state
例:
|
7、集群健康值:
GET /_cluster/health
例:
|
8、模板:
GET /_template
elasticsearch索引原理
动态更新的 Lucene 索引
Lucene 把每次生成的倒排索引,叫做一个段(segment)。然后另外使用一个 commit 文件,记录索引内所有的 segment。而生成 segment 的数据来源,则是内存中的 buffer。也就是说,动态更新过程如下:
举例,当前索引有 3 个 segment 可用。如下图所示:
新接收的数据进入内存 buffer,如下图所示:
内存 buffer 刷到磁盘,生成一个新的 segment,commit 文件同步更新。如下图所示:
利用磁盘缓存实现的准实时检索
既然涉及到磁盘,那么一个不可避免的问题就来了:磁盘太慢了!对我们要求实时性很高的服务来说,这种处理还不够。所以,在第 3 步的处理中,还有一个中间状态:
- 内存 buffer 生成一个新的 segment,刷到文件系统缓存中,Lucene 即可检索这个新 segment。
- 文件系统缓存真正同步到磁盘上,commit 文件更新。
这一步刷到文件系统缓存的步骤,在 Elasticsearch 中,是默认设置为 1 秒间隔的,对于大多数应用来说,几乎就相当于是实时可搜索了。Elasticsearch 也提供了单独的 /_refresh
接口,用户如果对 1 秒间隔还不满意的,可以主动调用该接口来保证搜索可见。
不过对于 Elastic Stack 的日志场景来说,恰恰相反,我们并不需要如此高的实时性,而是需要更快的写入性能。所以,一般来说,我们反而会通过 /_settings 接口或者定制 template 的方式,加大 refresh_interval 参数:
|
如果是导入历史数据的场合,那甚至可以先完全关闭掉:
|
在导入完成以后,修改回来或者手动调用一次即可:
|
translog 提供的磁盘同步控制
既然 refresh 只是写到文件系统缓存,那么第 4 步写到实际磁盘又是有什么来控制的?如果这期间发生主机错误、硬件故障等异常情况,数据会不会丢失?
这里,其实有另一个机制来控制。Elasticsearch 在把数据写入到内存 buffer 的同时,其实还另外记录了一个 translog 日志。
在refresh 发生的时候,translog 日志文件依然保持原样,如下图所示:
也就是说,如果在这期间发生异常,Elasticsearch 会从 commit 位置开始,恢复整个 translog 文件中的记录,保证数据一致性。
等到真正把 segment 刷到磁盘,且 commit 文件进行更新的时候, translog 文件才清空。这一步,叫做 flush。同样,Elasticsearch 也提供了 /_flush 接口。
对于 flush 操作,Elasticsearch 默认设置为:每 30 分钟主动进行一次 flush,或者当 translog 文件大小大于 512MB (老版本是 200MB)时,主动进行一次 flush。这两个行为,可以分别通过 index.translog.flush_threshold_period 和 index.translog.flush_threshold_size 参数修改。
如果对这两种控制方式都不满意,Elasticsearch 还可以通过 index.translog.flush_threshold_ops 参数,控制每收到多少条数据后 flush 一次。
整个流程可参看下图示例:
translog 的一致性
索引数据的一致性通过 translog 保证。那么 translog 文件自己呢?
ES为了数据的安全, 在接受写入的文档的时候, 在写入内存buffer的同时, 会写一份translog日志,从而在出现程序故障/磁盘异常时, 保证数据的完整和安全。
flush会触发lucene commit,并清空translog日志文件。 translog的flush是ES在后台自动执行的,默认情况下ES每隔5s会去检测要不要flush translog,
默认条件是:每 30 分钟主动进行一次 flush,或者当 translog 文件大小大于 512MB主动进行一次 flush。
对应的配置是index.translog.flush_threshold_period 和 index.translog.flush_threshold_size
需要指出的是, 从ES2.0开始,每次 index、bulk、delete、update 完成的时候,一定触发flush translog 到磁盘上,才给请求返回 200 OK。
这个改变提高了数据安全性,但是会对写入的性能造成不小的影响。
如果你不在意这点可能性,还是希望性能优先,可以在 index template 里设置如下参数:
|
总结
translog的功能:
- 保证在filesystem cache中的数据不会因为elasticsearch重启或是发生意外故障的时候丢失。
- 当系统重启时会从translog中恢复之前记录的操作。
- 当对elasticsearch进行CRUD操作的时候,会先到translog之中进行查找,因为tranlog之中保存的是最新的数据。
- translog的清除时间时进行flush操作之后(将数据从filesystem cache刷入disk之中)。
flush操作的时间点:
- es的各个shard会每个30分钟进行一次flush操作。
- 当translog的数据达到某个上限的时候会进行一次flush操作。
有关于translog和flush的一些配置项:
- index.translog.flush_threshold_ops:当发生多少次操作时进行一次flush。默认是 unlimited。
- index.translog.flush_threshold_size:当translog的大小达到此值时会进行一次flush操作。默认是512mb。
- index.translog.flush_threshold_period:在指定的时间间隔内如果没有进行flush操作,会进行一次强制flush操作。默认是30m。
- index.translog.interval:多少时间间隔内会检查一次translog,来进行一次flush操作。es会随机的在这个值到这个值的2倍大小之间进行一次操作,默认是5s。
segment merge对写入性能的影响
从另一个方面看,开新文件也会给服务器带来负载压力。因为默认每 1 秒,都会有一个新文件产生,每个文件都需要有文件句柄,内存,CPU 使用等各种资源。
一天有 86400 秒,设想一下,每次请求要扫描一遍 86400 个文件,性能一定不好。主动将这些零散的 segment 做数据归并,尽量让索引内只保有少量的,每个都比较大的,segment 文件。
这个过程是有独立的线程来进行的,并不影响新 segment 的产生。如下图,尚未完成的较大的 segment 是被排除在检索可见范围之外的:
当归并完成,较大的这个 segment 刷到磁盘后,commit 文件做出相应变更,删除之前几个小 segment,改成新的大 segment。等检索请求都从小 segment 转到大 segment 上以后,删除没用的小 segment。这
时候,索引里 segment 数量就下降了
routing和replica的读写过程
当一个 ES 节点收到一条数据的写入请求时,它是如何确认这个数据应该存储在哪个节点的哪个分片上的?
作为一个没有额外依赖的简单的分布式方案,ES 在这个问题上同样选择了一个非常简洁的处理方式,对任一条数据计算其对应分片的方式如下:
shard = hash(routing) % number_of_primary_shards
每个数据都有一个 routing 参数,默认情况下,就使用其 _id 值。将其 _id 值计算哈希后,对索引的主分片数取余,就是数据实际应该存储到的分片 ID。
副本一致性
作为分布式系统,数据副本可算是一个标配。ES 数据写入流程,自然也涉及到副本。在有副本配置的情况下,数据从发向 ES 节点,到接到 ES 节点响应返回,流向如下图所示:
- 客户端请求发送给 Node 1 节点,注意图中 Node 1 是 Master 节点,实际完全可以不是。
- Node 1 用数据的 _id 取余计算得到应该讲数据存储到 shard 0 上。通过 cluster state 信息发现 shard 0 的主分片已经分配到了 Node 3 上。Node 1 转发请求数据给 Node 3。
- Node 3 完成请求数据的索引过程,存入主分片 0。然后并行转发数据给分配有 shard 0 的副本分片的 Node 1 和 Node 2。
- 当收到任一节点汇报副本分片数据写入成功,Node 3 即返回给初始的接收节点 Node 1,宣布数据写入成功。Node 1 返回成功响应给客户端。
elasticsearch java api
具体内容略,这里提供java api的官方接口文档:
elasticsearch相关插件
elasticsearch head
Es head插件是维护过程中必不可少的工具,可以方便查看集群运行情况,节点健康状态,浏览数据,查看数据。
ik分词器
支持中文的分词器
elasticsearch-sql
实现sql向DSL语法接口的转换