海量日志分析平台Elastic Stack
2021-08-28 15:52:06 0 举报
AI智能生成
海量日志分析平台Elastic Stack
作者其他创作
大纲/内容
海量日志分析平台Elastic Stack
1. ElasticSearch基础
介绍
ElasticSearch简称ES,是一个开源的可扩展的分布式的全文检索引擎,它可以近乎实时的存储、检索数据
它本身扩展性很好,可扩展到上百台服务器,处理PB级别的数据
它使用Java开发且使用Lucene作为其核心来实现索引和搜索功能,但是通过简单的RestfulAPI和javaAPI来隐藏Lucene的复杂性,从而让全文搜索更简单
功能
分布式搜索引擎
ElasticSearch自动将海量数据分散到多台服务器上去存储和检索
全文检索
提供模糊搜索等自动度很高的查询方式,并进行相关性排名、高亮等功能
数据分析引擎(分组/聚合)
对海量数据进行近实时的处理
因为是分布式,所以可以采用大量的服务器去存储和检索数据,自然可以实现海量数据的处理
近实时:可以实现秒级别的数据搜索和分析
特点
它提供了一个极速的搜索体验
Speed:这源于它的高速,相比较其他一些大数据引擎,ES可以实现秒级的搜索,速度非常有优势
Scale:ES集群是一种分布式部署,极易扩展,使得它很容易处理PB级的数据库容量
Relevance:ES还可以将搜索结果按照分数进行排序,提供最相关的搜索结果
1. 安装方便
没有其他依赖,下载后安装非常方便,只需要修改几个参数就可以搭建集群
2. Json
输入输出格式为JSON,意味着不需要定义Scheme,快捷方便
3. RESTful
基本所有操作(索引、查询、配置)都可以通过HTTP接口进行
4. 分布式
节点对外表现对等,加入节点自动负载均衡
5. 多租户
可根据不同的用途分索引,可以同时操作多个索引
6. 支持超大数据
可以扩展到PB级别的结构化和非结构化数据,海量数据的近实时处理
使用场景
搜索类场景
日志分析类场景
数据预警平台及数据分析场景
商业BI系统
主流全文搜索方案
Luncen、Solr、ES是目前主流的全文搜索方案,基于倒排索引机制完成快速全文搜索
Solr和ES都是基于Lucene实现的,但是它们之间也有区别
Solr利用ZK进行分布式管理,而ES自身带有分布式协调管理功能
Solr比ES实现更加全面,Solr官方提供功能更多,而ES本身更注重于核心功能,高级功能多由第三方插件提供
Solr在传统的搜索应用中表现好于ES,而ES在实时搜索应用方面比Solr表现好
版本介绍
ElasticSearch主流版本为5.x、6.x及7.x
7.x更新
1、集群连接变化:TranspartClient被废弃
Es7的java代码,只能使用restClient
对于java变成,建议采用High-level-rest-client的方式操作ES集群
2、ES数据存储结构变化:简化了Type,默认使用_doc
3、ES程序包默认打包JDK
4、默认配置变化
默认节点名称为主机名,默认分片数为1,不再是5
5、Lucene升级为Lucene8,查询相关性速度优化
Weak-AND算法
核心原理:取TOP_N结果集,估算命中记录数,TOP_N时会跳过得分低于10000的文档来达到更快的性能
ES可以看作是分布式Lucene,Lucene的性能直接决定ES的性能,Lucene8在top_k及其他查询上有很大的性能提升
6、间隔查询
Intervals_query允许用户精确控制查询词在文档中出现的先后关系,实现了对terms顺序、terms之间的距离以及它们之间的包含关系的灵活控制
7、引入新的集群协调子系统,移除minimum_master_nodes参数,让Elasticsearch自己选择可以形成仲裁的节点
8、7.0将不会再有OOM的情况,JVM引入了新的circuit_breaker(熔断)机制,当查询或聚合的数据量超出单机处理的最大内存限制时会被截断
设置indices.breaker.fielddata.limit的默认值已经从JVM堆大小的60%降到40%
9、分片搜索空闲时跳过refresh
以前版本的数据插入,每秒都会有refresh动作,这使得ES能称为一个近实时的搜索引擎
但是没有查询需求时,该动作会使得ES的资源得到较大的浪费
单节点部署
1. 配置JDK
可以不配置,ES内置有
2. 配置ES
1. 编辑elasticsearch.yml
单机取消注释
node.name:node-1
修改网络和端口,取消注释master节点,单机只保留一个node
2. 按需修改jvm.options内存设置
按实际情况修改占用内存,默认都是1G,单机1G内粗,启动会占用700m+,然后再安装kibana基本就无法运行了
3. 添加es用户,es默认root用户无法启动,需要改为其他用户
useradd esuser
passwd esuser
chown -R esuser /root/tools/es
4. 修改/etc/sysctl.conf
末尾添加
vm.max_map_count=655360
生效
sysctl -p
5. 修改/etc/security/limits.conf
6. 启动
2. ElasticSearch使用
核心概念
索引 Index
类似的数据放在一个索引,非类似的数据放不同索引,一个索引也可以理解成一个关系型数据库
类型 Type
代表document属于index中的哪个类别
ES每个大版本之间区别很大
5.x中一个index可以有多种type
6.x中一个index只能有一种type
7.x以后要逐渐移除type概念
映射 Mapping
定义了每个字段的类型等信息,相当于关系型数据库中的表结构
常用数据类型:text、keyword、number、array、range、boolean、date、geo_point、ip、nested、object
API介绍
ES提供了Rest风格的API,即HTTP请求接口,而且也提供了各种语言的客户端API
ES没有自带图形化界面,可以通过安装ElasticSearch图形化插件,完成图形化界面的效果,完成索引数据的查看
安装配置kibana
介绍
Kibana是一个基于Node.js的ES索引库数据统计工具,可以利用ES的聚合功能,生成各种图表,如柱形图、线状图、饼图等
它提供了操作ES索引数据的控制台,且提供了一定的API提示,非常有利于学习ES语法
安装
1. 下载解压
2. 改变目录拥有者账号,设置访问权限
3. 修改配置文件 config/kibana.yml
server.port
server.host
elasticsearch.hosts
4. 启动
IK分词器
介绍
IKAnalyzer是一个开源的,基于Java语言开发的轻量级中文分词工具包
最初,它是以开源项目Lucene为应用主体,结合词典分词和文法分析算法的中文分词组件
新3.0版本则为面向Java的公用分词组件,独立于Lucene项目,同时提供了对Lucene的默认优化实现
3.0特性
采用了特有的“正向迭代最细粒度切分算法”,具有60万字/s的高速处理能力
采用了多子处理器分析模式,支持:英文字母、数字、中文词汇等分词处理
支持个人词条的优化的词典存储,更小的内存占用
支持用户词典扩展定义
针对Lucene全文检索优化的查询分析器IKQueryParser;采用歧义分析算法优化查询关键字的搜索排列组合,能极大的提高Lucene检索的命中率
安装
在plugins新建analysis-ik,拷贝插件解压文件,重启ES和Kibana
测试
IK分词器有两种分词模式
ik_max_word
常用,会将文本做最细粒度的拆分
ik_smart
会做最粗粒度的拆分
扩展词典使用
扩展词
就是不想被切分的词
自定义
进入config/analysis-ik(插件命令方式安装)
新增自定义词典,以.dic结尾
将自定义的扩展词典文件添加到IKAnalyzer.cfg.xml配置中
重启ES
停用词典使用
停用词
有些词在文本种出现的频率很高,但对文本的语义产生不了多大影响,这样的词称为停用词
停用词经常被过滤掉,不会被进行索引
检索过程中,如果用户的查询词中含有停用词,系统会自动过滤掉
停用词可以加快索引的速度,减少索引库文件的大小
自定义
进入config/analysis-ik(插件命令方式安装)
新增自定义词典,以.dic结尾
将自定义的扩展词典文件添加到IKAnalyzer.cfg.xml配置中
重启ES
同义词典使用
同义词
扩展词和停用词是在索引时使用,而同义词是检索时使用
配置
ES自带一个名为synonym的同义词filter,为了让IK和synonym同时工作,需要定义新的analyzer,用IK做tokenizer,synonym做filter
索引操作
创建索引库
settings:索引库设置,其中可以定义索引库的各种属性,如分片数、副本数等
判断索引是否存在
查看索引
Get请求可以查看索引的相关属性信息
打开索引
关闭索引
删除索引库
映射操作
说明
索引创建之后,等于有了关系型数据库中的database
ES7.x取消了索引type的设置,不允许指定类型,默认为_doc,但字段仍然存在,需要设置字段的约束信息,即字段映射
字段约束包括但不限于
字段的数据类型
是否要存储
是否要索引
分词器
创建映射字段
映射属性
1. type
ES支持的数据类型非常丰富
String
text
可分词,不可参与聚合
keyword
不可分词,数据会作为完整字段进行匹配,可参与聚合
Numerical
基本数据类型
long、integer、short、byte、double、float、half_float
浮点数的高精度类型
scaled_float,需要指定一个精度因子,如10或100,ES会把真实值乘以这个因子后存储,取出时还原
Date
ES可以对日期格式化为字符串存储,但建议存储为毫秒值,存储为long,节省空间
Array
进行匹配时,任意一个元素满足,都认为满足
排序时,如果升序则用数组中的最小值来排序,如果降序则用最大值来排序
Object
如果存储到索引库的是对象类型,会把对象变成多个字段
2. index
影响字段的索引情况
true
字段会被索引,可以用来进行搜索,默认值
false
字段不会被索引,不能用来搜索
3. store
是否将数据进行独立存储
原始的文本会存储在_source里,默认情况下其他提取出来的字段都不是独立存储的是从_source里提取出来的
可以独立的存储某个字段,设置store:true即可
获取独立存储的字段要比从_store中解析快得多,但也会占用更多的空间
4. analyzer
指定分词器,一般处理中文会选择IK分词器
查看映射关系
查看单个索引映射关系
查看所有索引映射关系
修改索引映射关系
修改映射增加字段,做其他修改只能删除索引,重新建立映射
一次性创建索引和映射
在创建索引库的同时,可以直接指定索引库中的映射
文档操作
说明
文档,即索引库中的数据,会根据规则创建索引,将来用于搜索
新增文档
新增文档时,涉及到id的创建方式,手动指定或自动生成
查看单个文档
元数据项
_index
document所属index
_type
document所属type,7.x默认type为_doc
_id
代表document的唯一标识,与index和type一起,可以唯一标识和定位一个document
_version
document的版本号,ES利用_version来确保应用中相互冲突的变更不会导致数据丢失
需要修改数据时,需要指定想要修改文档的version号,如果该版本不是当前版本号,请求将会失败
_seq_no
严格递增的顺序号,每个文档一个,Shard级别严格递增,保证后写入的Doc_seq_no大于先写入的
_primary_term
任何类型的写操作,包括index、create、update和delete,都会生成一个_seq_no
found
true/false,是否查找到文档
_source
存储原始文档
查看所有文档
_source定制返回结果
某些业务场景下,不需要搜索引擎返回source中的所有字段,可以使用source进行定制
例子:GET /lagou-index/_doc/1?_source=name,job
更新文档(全部更新)
把新增的请求方式改为PUT,就是修改,不过修改必须指定id
id对应文档存在,则修改
id对应文档不存在,则新增
更新文档(局部更新)
ES执行更新操作时,先将旧的文档标记为删除状态,然后添加新的文档,旧的文档不会立即消失,但是无法访问
ES会在继续添加更多数据是在后台清理已经标记为删除状态的文档
全部更新是直接把之前的老数据标记为删除状态,然后再添加一条新的
局部更新,只是修改某个字段(使用POST)
删除文档
根据id进行删除
根据查询条件进行删除
删除所有文档
全量替换
语法与创建文档一样,如果文档id不存在,就是创建,如果id已存在,就是全量替换操作,替换文档的json串内容
文档是不可变的,要修改文档内容,第一种方式就是全量替换,直接对文档重新建立索引,替换里面所有的内容,ES会将老的文档标记为deleted,然后新增
强制创建
3. ElasticSearch高级应用
高级映射
地理坐标点数据类型
地理坐标点
指地球表面可以用经纬度描述的一个点,可以用来计算两个坐标点间的距离,还可以判断一个坐标是否在一个区域中
需要显式声明对应字段类型为geo_point
经纬度坐标格式
字段被声明为geo_point后,就可以索引包含了经纬度信息的文档了
经纬度信息的形式可以是字符串、数组或对象
字符串形式以半角逗号分割,如[lat, lon]
对象形式显式命名为 lat 和 lon
数组形式表示为 [lon, lat]
通过地理坐标点过滤
过滤器
geo_bounding_box
找出落在指定矩形框中的点
目前为止最有效的地理坐标过滤器,因为计算起来非常简单
指定一个举行的顶部,底部、左边界、右边界,然后过滤器只需判断坐标的经度是否在左右边界之间,纬度是否在上下边界之间
geo_distance
找出与指定位置在给定距离内的点
过滤仅包含与地理位置相距特定位置内的匹配文档
geo_distance_range
找出与指定点距离在给定最小距离和最大距离之间的点
geo_polygon
找出落在多边形中的点
这个过滤器使用代价很大
动态映射
ES遇到文档中以前未遇到的字段,可以使用dynamic_mapping来确定字段的数据类型并自动把新的字段添加到类型映射
ES的动态映射机制可以进行开关控制,通过设置mappings.dynamic
true:遇到陌生字段就执行dynamic_mapping处理机制
false:遇到陌生字段就忽略
strict:遇到陌生字段就报错
自定义动态映射
如果想在运行时添加新字段,可能会启动动态映射,但有时动态映射规则不够智能
可以通过设置去自定义这些规则,以便更好的适用数据
日期检测
当ES遇到一个新的字符串字段时,它会检测这个字段是否包含一个可识别的日期,如果像日期,这个字段就会被作为date类型添加,否则会被作为string类型添加
日期检测可能会导致问题,将字符串字段识别为日期字段
日期检测可以通过在根对象上设置date_detection=false来关闭
ES判断字符串为日期的规则可以通过dynamic_date_formats来设置
dynamic_templates
使用dynamic_templates可以完全控制新生成字段的映射,甚至可以通过字段名称或数据类型来应用不同的映射
每个模板都有一个名称(用来描述该模板的用途),一个mapping(用来指定映射怎么使用),以及至少一个参数(如match,来定义该模板适用于哪个字段)
模板按照顺序来检测,第一个匹配的模板会被启用
参数
match_mapping_type
允许应用模板到特定类型的字段上,就像有标准动态映射规则检测一样
match
只匹配字段名称
path_match
匹配字段在对象上的完整路径
Query DSL
说明
Domain Specific Language 特定域的语言
ES提供了基于JSON的完整查询DSL来定义查询,将查询DSL视为查询的AST,它由两种子句组成
叶子查询子句
在特定域中寻找特定的值,如match,term,range
复合查询子句
包装其他叶子查询或复合查询,并用逻辑方式组合多个查询,如bool、dis_max,或更改行为,如constant_score
基本语法
query代表一个对象,里面有不同的查询属性
查询类型
match_all、match、term、range等
查询条件
根据类型不同,写法有差异
查询所有 match_all_query
参数
query
代表查询对象
match_all
代表查询所有
结果
took
查询花费时间,单位ms
time_out
是否超时
_shards
分片信息
hits
搜索结果总览对象
total
搜索到的总条数
max_score
所有结果中文档得分的最高分
hits
搜索结果的文档对象数组,每个元素就是一条搜索到的文档信息
_index
索引库
_type
文档类型
_id
文档Id
_score
文档得分
_source
文档源数据
全文搜索 full-text query
全文搜索能够搜索已分析的文本字段,使用索引期间应用于字段的同一分析器处理查询字符串
匹配搜索 match query
全文搜索的标准查询,可以对一个字段进行模糊、短语查询
match_query接收text/numerics/dates,对它们进行分词分析,再组织成一个boolean查询
可通过operator指定bool组合操作
or
默认match类型查询,会把查询条件进行分词,然后进行查询,多个词条之间是or关系
and
某些情况下,需要更精确查找,可以使用and
短语搜索 match phrase query
match_phrase用来对一个字段进行短语查询,可以指定analyzer、slop移动因子
query_string
提供了无需指定某字段而对文档全文进行匹配查询的一个高级查询,同时可以指定在哪些字段上进行匹配
多字段匹配搜索 multi match query
可以使用multi_match在match的基础上支持多个字段进行文本查询
可以使用 * 匹配多个字段
词条级搜索 term-level queries
说明
可以使用词条级搜索根据结构化数据中的精确值查找文档,结构化数据的值包括日期范围、IP地址、价格或产品ID等
与全文查询不同,词条级搜索不分析搜索词,词条与存储在字段级别中的术语完全匹配
词条搜索 term query
term查询用于查询指定字段包含某个词项的文档
词条集合搜索 terms query
terms用于查询指定字段包含某些词项的文档
范围搜索 range query
gte:大于等于
gt:大于
lte:小于等于
lt:小于
boost:查询权重
不为空搜索 exists query
查询指定字段值不为空的文档
词项前缀搜索 prefix query
通配符搜索 wildcard query
正则搜索 regexp query
regexp允许使用正则表达式进行term查询
如果使用不正确,会给服务器带来很严重的性能压力
如.*开头的查询,将会匹配搜索的倒排索引中的关键字,几乎相当于全表扫描
模糊搜索 fuzzy query
ids搜索
复合搜索 compound query
constant_score query
用来包装另一个查询,将查询匹配的文档的评分设为一个常数
bool query
用bool操作来组合多个查询子句为一个查询
可用关键字
must:必须满足
filter:必须满足,但执行的是filter上下文,不影响评分
should:或
must_not:必须不满足,在filter上下文中执行,不参与评分
minimum_should_match
代表了最小匹配精度,如果设置了,则should语句中至少需要有一个条件满足
排序
相关性评分排序
默认情况下,返回结果按照相关性进行排序
为了按照相关性排序,需要将相关性表示为一个数值,在ES中,相关性得分由一个浮点数表示,并在结果中通过_score参数返回
默认按照_score降序
字段值排序
多级排序
分页
size:每页显示几条
from:当前页起始索引
高亮
在match查询时,加上一个highlight属性
pre_tags:前置标签
post_tags:后置标签
fields:需要高亮的字段
批量操作
mget 批量查询
bulk 批量增删改
Bulk操作将文档的增删改一系列操作,通过一次请求全都完成,减少网络传输次数
功能
delete
删除一个文档,只要一个json串即可,删除的批量操作不需要请求体
create
相当于强制创建
index
普通的put操作,可以是创建文档,也可以是全量替换文档
update
执行的是局部更新操作
格式
每个json不能换行,相邻json必须换行
隔离
每个操作互不影响,操作失败的行会返回其失败信息
实际用法
buld请求一次不要太大,否则一下积压到内存中,性能会下降
一次请求几千个操作、大小在几M内正好
bulk会将要处理的数据载入内存中,所以数据量是有限的,最佳的数据量不是一个确定数据,取决于硬件、文档大小及复杂度,索引及搜索负载
一般建议1000-5000个文档,大小5-15M,默认不能超过100M,可在ES配置中修改
http.max_content_length: 10mb
Filter DSL
ES中所有查询都会触发相关度得分的计算
如果不需要相关度得分,ES以过滤器的形式提供了另一种查询功能
过滤器在概念上类似于查询,但是它们有非常快的执行速度
执行速度快主要原因
过滤器不会计算相关度得分,所以它们计算上更快一些
过滤器可以被缓存到内存中,这使得在重复查询上,要比相应的查询快得多
示例
定位非法搜索/原因
ES提供了API协助定位不合法的查询
_validate
聚合分析
介绍
聚合分析是数据库中重要的功能特性,完成对一个查询的数据集中数据的聚合计算,ES同样提供了强大聚合分析能力
对于一个数据集求最大、最小、和、平均值等指标聚合,在ES中称为指标聚合metric
ES中group_by称为分桶,桶聚合bucketing
语法
指标聚合
max min sum avg
count
value_count
统计某字段有值的文档数
cardinality
去重计数
stats
统计count、max、min、avg、sum5个值
Extended stats
高级统计,比stats多4个统计结果:平方和、方差、标准差、平均值加/减两个标准差的区间
Percentiles
占比百分位对应的值统计
Percentiles rand
统计值小于等于指定值的文档占比
桶聚合
执行的是对文档分组的操作(group_by),把满足相关特性的文档分到一个桶里,输出结果往往是一个个包含多个文档的桶
零停机索引重建
说明
ES是一个实时的分布式搜索引擎,当决定存储某种数据时,在创建索引时需要数据结构完整确定下来,同时索引的设定和很多固定配置将不能改变
但需要改变数据结构时就需要重建索引,为此,ES提供了辅助工具帮助开发人员进行索引重建
方案
外部数据导入
介绍
系统架构设计中,由关系型数据库存储数据,ES在架构中起到加速查询的作用
如果遇到索引重建的操作,待系统模块发布新版本后,从数据库将数据查询出来,重新灌入ES即可
执行步骤
建议方案:数据库+MQ+应用模块+ES
可以在MQ控制台发送消息来触发重导数据,按批次对数据进行导入,整个过程异步化处理
操作步骤
1、通过MQ的web控制台或cli命令行,发送指定的MQ消息
2、MQ消息被微服务模块的消费者消费,触发ES数据重新导入功能
3、微服务模块从数据库里查询数据的总数及批次信息,并将每个数据批次的分页信息重新发送给MQ消息,分页信息包含查询条件和偏移量,此MQ消息还是会被微服务的MQ消息者接收处理
4、微服务根据接收的查询条件和分页信息,从数据库获取到数据后,根据索引结构的定义,将数据组装成ES支持的JSON格式,并执行bulk命令,将数据发送给ES集群
5、完成
特点
MQ中间件的选型不做具体要求,常见的RabbitMQ、ActiveMQ、RocketMQ等均可
在微服务模块方面,提供MQ消息处理接口、数据处理模块需要实现开发,一般是创建新索引时,配套把重建的功能也一起做好,整体功能公用一个Topic,针对每个索引,由单独的结构定义和MQ消息处理Tag,代码尽可能复用。处理的批次大小需要根据实际的情况设置
微服务模块实例会部署多个,数据是分批处理的,批次信息会一次性全部先发送给MQ,各个实例处理的数据相互不重叠,利用MQ消息的异步处理机制,可以充分利用并发的优势,加快数据重建的速度
缺点
1、对数据库造成读取压力,短时间内大量的读操作,会占用数据库的硬件资源,严重时可能引起数据库性能下降
2、网络带宽占用多
3、数据重建时间稍长,跟迁移的数据量大小有关
基于scroll+bulk+索引别名
介绍
利用ES自带的一些工具完成索引的重建工作,在方案实际落地时,可能会依赖客户端的一些功能,如Java客户端持续的做scroll查询,bulk命令的封装等
数据完全自给自足,不依赖其他数据源
执行步骤
0、假设原索引名为book,新索引名为book_new,Java客户端使用别名book_alias连接ES,该别名指向原索引book
1、若Java客户端没有使用别名,需要给客户端分配一个
2、新建索引book_new,将mapping/settings信息按新要求定义好
3、使用scroll_api将数据批量查询出来
为了使用scroll,初始搜索请求应该在查询中指定scroll参数,这可以告诉ES需要保持搜索的上下文环境多久
4、采用bulk_api将scroll查出来的一批数据,批量写入新索引
5、反复执行修改后的步骤3和4,查询一批导入一批
6、切换别名book_alias到新索引book_new上,此时Java客户端仍然使用别名访问,也不需要修改任何代码,不需要停机
7、验证别名查询的是否为新索引数据
特点
在数据传输上基本自给自足,不依赖其他数据源,Java客户端不需要停机等待数据迁移,网络传输占用带宽较小
scroll和bulk这部分,数据量大时需要依赖一些客户端工具
补充
在Java客户端或其他客户端访问ES集群时,使用别名时一个好习惯
Reindex API
ES6.3.1已经支持Reindex_API,它对scroll、bulk做了一层封装,能够对文档重建索引而不需要任何插件和外部工具
基础命令
如果不手动创建新索引的mapping信息,则ES将启动自动映射模板对数据进行类型映射,可能不是期望的类型
version_type
使用reindex_api也是创建快照后再执行迁移,这样目标索引的数据可能会与原索引有差异
version_type属性可以决定乐观锁并发处理的规则
internal
直接拷贝文档到目标索引,对相同的type、文档ID直接进行覆盖,默认值
external
迁移文档到目标索引时,保留version信息,对目标索引中不存在的文档进行创建,已存在的文档按version进行更新,遵循乐观锁机制
op_type/conflicts
如果op_type设置为create,那么迁移时只在目标索引中创建ID不存在的文档,已存在的文档,会提示错误
如果加上conflicts=proceed配置项,那么冲突信息将不展示,只展示冲突的文档数量
query支持
reindex_api支持数据过滤、数据排序、size设置、_source选择等,也支持脚本执行
小结
三个方案来说,做为ES的使用者,三个方案的参与度是逐渐弱化的,但稳定性却是逐渐上升
需要清楚的了解各个方案的优劣,适宜的场景,然后根据实际情况去权衡
智能搜索建议
Suggesters基本的运作原理是将输入的文本分解为token,然后在索引的字典里查找相似的term并返回
根据使用场景不同,ES设计了4种类型的Suggester
Term Suggester
suggest_mode
missing
popular
always
ES通过Levenstein_edit_distance算法来判断两个term的相似性,核心思想就是一个词改动多少个字符就可以和另一个词一致
Phrase Suggester
在Term的基础上,会考量多个term之间的关系,如是否同时出现在索引原文里,相邻程度,词频等
结果options直接返回一个phrase列表,可以加highlight选项,将被替换的term高亮
Completion Suggester
主要针对的场景是“Auto_completion”,该场景下用户每输入一个字符,就需要即时发送一次查询请求到后端查找匹配项,在用户输入速度较高时对后端响应速度要求比较苛刻
它和以上两个Suggester采用了不同的数据结构,索引并非通过倒排来完成,而是将Analyzer过的数据编码成FST和索引一起存放
对于一个Open状态的索引,FST会被ES整个装载到内存中,进行前缀查找,速度极快,但是FST只能用户前缀查找,这也是Completion的局限所在
为了使用Completion,索引字段的类型需要定义为“completion”
Completion在索引原始数据时也要经过analyzer阶段,取决于选用的analyzer不同,会影响FST编码结果,也会影响查找匹配的结果
其他能影响结果的
preserve_seperators
默认false,即忽略空格之类的分隔符
preserve_position_increments
默认true,如果见一次第一个词时停用词,且使用了过滤停用词的分析器,需要设置为false
搜索时选用Fuzzy Queries
Context Suggester
Completion的扩展
可以在搜索中加入更多的上下文信息,然后根据不同的上下文信息,对相同的输入,提供不同的建议值
匹配输入
精准程度上:Completion>phrase>term,召回率则反之
性能上来说,Completion最快,如果能满足业务需求,Completion是最理想的选择
Phrase和Term由于是做倒排索引的搜索,相对来说性能要低不少,应该尽量控制用到的索引的数据量,最理想状况是经过一定时间预热后,索引可以全量map到内存
概念
召回率 = 系统检索到的相关文件 / 系统所有相关的文件总数
准确率 = 系统检索到的相关文件 / 系统所有检索到的文件总数
从一个大规模数据集合中检索文档时,可把文档分为四组
系统检索到的相关文档 A
系统检索到的不相关文档 B
相关但是没有检索到的文档 C
不相关且没有检索到的文档 D
召回率R:R = A / (A + C)
精度P:P = A / (A + B)
ElasticSearch Java Client
说明
ES提供多种不同的客户端
TransportClient,ES提供的传统客户端,官方计划8.0版本删除此客户端
RestClient,官方推荐的,包含
Java Low Level REST Client
ES 6.0之后提供
Java High Level REST Client
官方更加推荐
4. ElasticSearch集群
核心概念
集群
一个ES集群由多个节点组成,每个集群都有一个共同的集群名称作为标识
节点
一个ES实例即一个节点,一台机器可以有多个实例
ES配置文件可以通过node.master、node.data来设置节点类型
node.master
表示节点是否具有成为主节点的资格
true/false
node.data
表示节点是否存储数据
Node节点组合
主节点+数据节点
默认,节点既有成为主节点的资格,又存储数据
node.master: true
node.data: true
数据节点
节点没有成为主节点的资格,不参与选举,只会存储数据
node.master: false
node.data: true
客户端节点
不会成为主节点,也不会存储数据,主要是针对海量请求时可以进行负载均衡
node.master: false
node.data: false
分片
每个索引有1或多个分片,每个分片存储不同的数据
分片分为主分片/复制分片,复制分片时主分片的拷贝
默认每个主分片有一个复制分片,每个索引的复制分片数可以动态的调整,复制分片从不与它的主分片在同一个节点上
副本
指主分片的副本分片,即主分片的拷贝
作用
提高恢复能力:当主分片宕机,某个复制分片可以变成主分片
提高性能:get和search请求既可以由主分片又可以由复制分片处理
分布式架构
ES的架构遵循其基本概念
一个采用RESTful_API标准的高扩展性和高可用性的实时数据分析的全文搜索引擎
特性
高扩展
体现在ES添加节点非常简单,新节点无需做复杂的配置,只要配置好集群信息将会被集群自动发现
高可用
因为ES是分布式的,每个节点都会有备份,所以宕机一两个节点也不会出现问题,集群会通过备份进行自动复盘
实时性
使用倒排索引来建立存储结构,搜索时常在百毫秒内完成
分层
一、Gateway
ES支持索引快照的存储格式,默认是先把索引放到内存中,当内存满了之后再持久化到本地磁盘
Gateway对索引快照进行存储,当ES关闭再启动时,它就会从这个Gateway里读取索引数据
支持的格式有
Local FileSystem
分布式的Shared FileSystem
Hadoop/HDFS
Amazon:S3
二、Lucene框架
ES基于Lucene框架
三、ElasticSearch数据的加工处理方式
IndexModule,SearchModule、Mapping、River
River
代表ES的一个数据源,运行在ES集群内部的一个插件,主要用来从外部获取异构数据,然后在ES里创建索引
常见有RabbitMQ_River、TwitterRiver
四、ElasticSearch发现机制、脚本
Discovery是ES自动发现节点机制的模块
Zen Discovery
相当于SolrCloud中的Zookeeper
功能上可以分为两部分
1.集群刚启动时的选主,或是新加入集群的节点发现当前集群的Master
2.选主完成后,Master和Follower相互探活
EC2 Discovery
亚马逊弹性计算云
Scripting是脚本执行功能,有这个功能可以很方便对查询出来的数据进行加工处理
3rd_Plugins表示ES支持安装很多第三方插件
五、ElasticSearch交互方式
有Thrift、Memcached、Http三种协议,默认使用Http协议传输
六、ElasticSearch的API支持模式
RESTful_API标准当下十分流行,ES作为分布式集群,客户端到客户端,节点到节点间通信有TCP和Http通信协议,底层实现为Netty框架
解析
分布式架构的透明隐藏特性
ES是一个分布式系统,隐藏了复杂的处理机制
分片机制
将文本数据切割成n个小份存储在不同的节点上,减少大文件存储在单个节点上对设备带来的压力
分片副本
在集群某个节点宕机后,通过副本可以快速对缺失数据进行复盘
集群发现机制
在当前启动一个ES进程,在启动第二个ES进程时,这个进行将作为一个node自动发现集群,并自动加入,前提时这些node都必须配置一套集群信息
Shard负载均衡
ES会均衡的分配分片到节点,以保持每个节点均衡的负载请求
扩容机制
垂直扩容
用新机器替换已有机器,服务器台数不变,容量增加
水平扩容
直接增加新机器,服务器台数和容量都增加
rebalance
增加或减少节点时会自动负载
主节点
主要职责是和集群操作的相关内容,如创建或删除索引,跟踪哪些节点是集群的一部分,并决定哪些分片分配给相关的节点
稳定的主节点对集群的健康是非常重要的
节点对等
每个节点都能接收请求,每个节点接收到请求后都能把该请求路由到有相关数据的其他节点上,接受原始请求的节点负责采集数据并返回给客户端
搭建
elasticsearch.yml
cluster.name
集群名称,相同名称一个集群
node.name
节点名称,集群模式下每个节点名称唯一
node.master
当前节点是否可以被选举为master节点
node.data
当前节点是否用于存储数据
path.data
索引数据存放的位置
path.logs
日志文件存放的位置
boostrap.memory_lock
是否锁住物理内存
network.host
监听地址,用于访问该实例
http.port
ES对外提供的http端口,默认9200
transport.port
节点选举的通信端口,默认9300
discovery.seed_hosts
EX7.x之后新增的配置,写入候选主节点的设备地址,在开启服务后可以被选为主节点
cluster.initial_master_nodes
ES7.x之后新增的配置,初始化一个新的集群时需要此配置来选举master
http.cors.enabled
是否支持跨域,在使用head插件时需要此配置
http.cors.allow-origin "*"
表示支持所有域名
步骤
搭建多节点,配置保持一致
cluster.name
node.name
network.host
http.port
transport.port
cluster.initial_master_nodes
discovery.seed_hosts
修改各节点配置
单机部署需要修改各节点端口
node.name
和cluster.initial_master_nodes对应
transport.port
和discovery.seed_hosts对应
启动各节点
验证
http://ip:port/_cat/health?v
head插件
简介
ElasticSearch-head是一个界面化的集群操作和管理工具,可以对集群进行傻瓜式操作,可以通过插件把它集成到ES
是一个基于node.js的前端工程
主要操作
1、显示集群的拓扑,能够快速访问并显示集群的状态,且能够执行索引和节点级别操作
2、搜索接口能够查询集群中原始json或表格格式的检索数据
3、有一个输入窗口,允许任意调用RESTful_API
安装
1. 安装nodejs
2. 安装phantomjs
3. 安装head
4. head发现主机
5. 启动
在head文件夹中:npm run start
规划
需要多大规模集群
考虑方面
1、当前数据量大小,数据增长情况
2、机器配置如何:CPU、内存、硬盘容量
推算依据
ES_JVM_heap最大可以设置32G
30G_heap大概能处理数据量10T
如果内存很大,可在一台机器上运行多个ES节点实例
集群规划满足当前规模+适量增长规模即可,后续按需扩展
节点角色分配
角色
Master
node.master:true
节点可作为主节点
Data
node.data:true
默认是数据节点
Coordinate
协调节点,一个节点只作为接收请求、转发请求到其他节点、汇总各个节点返回数据等功能的节点
仅担任协调节点,上两个配置均设为false
如何分配
A、小规模集群,不需严格区分
B、中大规模集群(十个以上节点)
应考虑单独的角色充当
特别并发查询大,查询的合并量大,可以增加独立的协调节点
角色分开好处是分工分开,互不影响
避免脑裂
6.x和之前版本,尽量避免脑裂,需要添加最小数量的主节点配置
discovery.zen.minimum_master_nodes
有master资格节点数 / 2 + 1
该参数控制,选举主节点时需要看到最少几个具有master资格的活节点,才能进行选举
7.x中,对ES的集群发现系统做了调整
不再有discovery.zen.minimum_master_nodes配置,转而由集群自主控制
且在启动一个新集群时需要有cluster.initial_master_nodes初始化集群列表
部分discovery.zen.*配置,已经失效
常用做法(中大规模集群)
1、master和data分开,配置奇数个master
2、单播发现机制,配置master资格节点(5.0之前)
discovery.zen.ping.multicast.enabled: false
3、延长ping master等待时长
discovery.zen.ping_timeout: 30
7.x换成discovery.request_peers_timeout
索引分片数
分片数指定后不可改变,除非重建索引
设置原则
ES推荐的最大JVM堆空间为30-32G,所以分片最大容量限制为30G,然后再对分片数最合理估算
如数据能达到200G,最多分配7-8个分片
开始阶段,一个好的方案是根据节点数按照1.5-3倍原则来创建分片
对于基于日期的索引需求,且对索引数据的搜索场景很少,类似场景每个索引量可能很多,但每个索引数据量不大,建议只需要为索引分配一个分片
索引副本数
基本原则
为保证高可用,副本数设为2即可
集群至少有3个节点
如果发现并发量大,查询性能降低,可增加副本数,提升并发查询能力
注意
新增副本时主节点会自动协调,然后拷贝数据到新增副本节点
副本数是可以随时调整的
调优策略
Index调优
副本数置0
如果是集群首次灌入数据,可以将副本数置为0,写入完毕再调整回去,这样副本分片只需要拷贝,节省了索引过程
自动生成docID
如果写入doc时外部指定了ID,则es会先尝试读取原来doc的版本号,以判断是否需要更新
这会涉及一次读取磁盘的操作,通过自动生成docID可以避免这个环节
合理设置mappings
将不需要建立索引的字段index属性设置为not_analyzed或no
对字段不分词,或不索引,可以减少很多运算操作,降低CPU占用
尤其是binary类型,默认下占用CPU非常高,而这种类型进行分词通常没什么意义
使用不同的分析器,不同分析器在索引过程中运算复杂度也有较大的差异
调整_source字段
一般用于索引和数据分离,这样可以降低IO的压力,不过实际场景中大多不会禁用source
source字段用于存储doc原始数据,对部分不需要存储的字段,可以用过includes/excludes过滤,或将source禁用
对analyzed的字段禁用norms
Norms用于在搜索时计算doc的评分,如果不需要评分,则可以将其禁用
调整索引的刷新间隔
该参数缺省是1s,强制ES每秒创建一个新Segment,从而保证新写入的数据近实时的可见、可被搜索
可以适当调高,降低刷新的次数,把刷新操作消耗的系统资源释放出来给index操作
这种方案以牺牲可见性的方式,提高index操作的性能
批处理
批处理把多个index操作请求合并起来
每批1000个documents是一个性能较好的size
每批中多少documents合适,受很多因素影响而不同
ES官网建议通过在单个Node、单个Shard做性能基准测试来确定
document的路由处理
对一批中的documents进行index操作时,该批index操作所需的线程数由要写入的目的shard个数决定
Search调优
数据分组
常用ES存储日志,日志的索引管理方式一般基于日期,基于天、周、月、年建索引
搜索单天的数据,只需要查询一个索引的shards即可,需要查询多天的数据,则需要查询多个索引的shards
原始方案是建一个index,数据量增大时,就扩容增加index的shard个数,shards增多时,要搜索的shards个数也随之上升
基于数据分组,可以基于client进行数据分组,每个client只需依赖自己的index的数据shards进行搜索,而不是所有的shards,大大提高了搜索的性能
使用Filter代替Query
搜索时使用Query,需要为Document相关度打分,使用Filter则没有,理论上filter会更快一些
ID字段定义为keyword
一般情况下,ID不会被用作Range类型的搜索字段,都可以定义为keyword类型
因为keyword会被优化,以便进行terms查询,Integers等数值型会被优化来进行range类型搜索
integers改成keyword之后,搜索性能大约能提升30%
禁止用户的无约束输入
5. 数据模型构建
介绍
数据模型是抽象描述现实世界的一种工具和方法,通过抽象实体之间的联系,用图形化的形式去描述业务规则的过程,从而表示现实世界中事务及相互关系的一种映射
核心概念
实体
现实世界中存在的可以相互区分的事物或概念
属性
每个实体都有自己的特性,利用实体的属性可以描述不同的实体
建模过程
1. 概念建模
主要做三件事
客户交流
理解需求
形成实体
确定系统的核心需求和范围边界,设计实体之间的关系
本阶段,只需关注实体即可,不用关注任何实现细节
在整个过程中占比10%
2. 逻辑建模
主要做两件事
进一步梳理业务需求
确定每个实体的属性、关系和约束等
逻辑模型是对概念模型的进一步分解和细化,描述了实体、实体属性及实体之间的关系,是概念模型延伸
模型的主要元素为主题、实体、属性和关系
一般的逻辑模型有第三范式,星型模型和雪花模型,雪花和星型的主要区别是维度的层次,星型只有一层,而雪花可能涉及多层
作用
便于技术开发人员和业务人员及用户进行沟通交流,使得整个概念模型更易于理解,进一步明确需求
作为物理模型设计的基础,由于逻辑模型不依赖于具体的数据库实现,使用逻辑模型可以生成针对具体DBMS的物理模型,保证物理模型充分满足用户需求
在整个过程中占比60~70%
3. 物理建模
主要事情:结合具体的数据库产品,在满足业务读写性能等需求前提下,确定最终的定义
物理模型是在逻辑模型的基础上描述模型实体的细节,包括数据库产品对应的数据类型、长度、索引等,为逻辑模型选择一个最优的物理存储环境
逻辑模型转化为物理模型的过程即实体名转化为表名,属性名转化为物理列名的过程
设计物理模型时,还需要考虑数据存储空间的分配,包括对列属性必须做出明确的定义
意义
数据模型支撑了系统和数据,系统和数据支撑了业务系统
好的数据模型
能让系统更好的集成、能简化接口
能简化数据冗余、减少磁盘空间、提升传输效率
兼容更多数据,不会因数据类型的新增而导致实现逻辑更改
能帮助更多的业务机会,提高业务效率
能减少业务风险、降低业务成本
Mapping设置
ES是基于Lucene以倒排索引为基础实现的存储体系,不遵循关系型数据库中的范式约定
属性
enable
默认true,仅存储,不做搜索和聚合分析
index
默认true,是否构建倒排索引
index_option
docs | freqs | positions | offsets
存储倒排索引的哪些信息
norms
默认true,是否存储归一化相关参数
如果字段仅用于过滤和聚合分析,可关闭
doc_values
默认true,是否启动doc_values用户聚合和排序分析
fielddata
默认true,是否为text类型启动fielddata实现排序和聚合分析
store
默认false,是否存储字段值
coerce
默认true,是否开启自动数据类型转换功能
multifields
灵活的使用多字段解决多样的业务需求
dynamic
默认true(true|false|strict),控制mapping的自动更新
字段设置流程
1、判断数据类型
字符串类型:需要分词text,否则keyword
枚举类型:基于性能keyword
数值类型:尽量选择贴近大小的类型
其他:布尔、日期、地理位置
2、是否需要检索
enable: false,完全不需要检索、排序、聚合分析
index:true|false
index_options
3、是否需要排序、聚合分析
doc_values
fielddata
4、是否需要另行存储
store
source
ES关联关系处理
1. Application-side joins
该方式下,索引之间完全独立(利于对数据进行标准化处理),由应用端的多次查询来实现近似关联关系查询
这种方法适用于关联的实体只有少量的文档记录的情况,且它们很少改变
使用ES的terms查询具有上限,默认1024,具体可在elasticsearch.yml中修改
这将允许应用程序对结果进行缓存,并避免经常运行第一次查询
2. Data denormalization
该方式就是通过字段冗余,以一张大宽表来实现粗粒度的index,这样可以充分发挥扁平化的优势
但是这是以牺牲索引性能及灵活度为代价的
使用前提:冗余字段是很少改变,比较适合与一对少量关系的处理
当业务数据库并非采用非规范化设计时,要将数据同步到作为二级索引库的ES中,就需要进行定制化开发,基于特定业务进行应用开发来处理join关联和实体拼接
说明:宽表处理在处理一对多、多对多关系时,会有字段冗余问题,适合“一对少量”且这个“一”更新不频繁的应用场景
3. Nested objects
索引性能和查询性能二者不可兼得,必须进行取舍
嵌套文档将实体关系嵌套组合在单文档内部,这种方式牺牲建立索引性能来换取查询性能,比较适合于一对少量的关系处理
文档内任一属性变化都需要重新索引该文档
当使用嵌套文档时,使用通用的查询方式是无法访问的,必须使用合适的查询方式(nested_query、nested_filter、nested_facet等)
很多场景下,使用嵌套文档的复杂度在于索引阶段对关联关系的组织拼装
4. Parent/child relationships
父子文档牺牲了一定的查询性能来换取索引性能,适用于写多读少的场景
父子文档相比嵌套文档较灵活,适用于“一对大量”且“一”不是海量的应用场景,该方式比较耗内存和CPU,比嵌套方式慢5~10倍,且需要特定的has_parent和has_child过滤器查询语法,查询结构不能同时返回父子文档
受限于父子文档必须在同一分片上(可以通过routing执行父文档ID),操作子文档时需要指定routing
7. 深度应用/原理剖析
文档写入和近实时搜索
基本概念
Segments in Lucene
ES存储单元是Shard,ES中一个Index可能分为多个Shard,每个Shard都是一个Lucene的Index,且每个Lucene_index由多个Segment组成
每个Segment事实上是一些倒排索引的集合,每次创建一个Document,都会归属于一个新的Segment,而不会去修改原来的Segment
且每次的文档删除操作,会仅仅标记Segment中该文档为删除状态,而不会真正的立即物理删除
Commits in Lucene
Commit意味着将Segment合并,并写入磁盘,保证内存数据尽量不丢失
但刷盘是很重的IO操作,为了机器性能和近实时搜索,并不会刷盘及时
Translog
新文档被索引意味着文档会被先写入内存buffer和translog文件,每个Shard都对应一个translog文件
Refresh in ElasticSearch
在ES中,_refresh操作默认每秒执行一次,意味着将内存buffer的数据写入到一个新的Segment中,这时索引变成可检索的
写入新Segment后,会清空内存buffer
Flush in ElasticSearch
Flush操作意味着将内存buffer的数据全都写入新Segments中,并将内存中的所有Segments全部刷盘,且清空translog日志的过程
近实时搜索
说明
提交一个新的段到磁盘需要一个fsync来确保段被物理性地写入磁盘,这样断电时就不会丢失数据
但是fsync操作代价很大,如果每次索引一个文档都执行一次会造成很大的性能问题
需要一个更轻量的方式来使一个文档可被索引,意味着fsync要从整个过程中移除
在ES和磁盘间是系统文件缓存,在内存索引缓冲区中的文档会被写入到一个新的段中
这里新段会被先写入到文件系统缓存,这步代价较低,稍后再被刷新到磁盘,这步代价较高
但只要文件已经在系统缓存中,就可以像其他文件一样打开读取
Lucene允许新段被写入和打开,使其包含的文档在未进行一次完整提交时便对搜索可见
这种方式比进行一次提交代价要小得多,且在不影响性能的前提下可以被频繁执行
原理
ES写操作
当一个写请求发送到ES后,ES将数据写入memory_buffer中,并添加事务日志(translog)
如果每次写入内存就立即刷盘,由于写入的数据是离散的,因此写入磁盘的操作也是随机写入了
硬盘随机写入效率相当低,会严重降低ES性能
ES在设计时在memory_buffer和硬盘之间加入了Linux的高速缓存(FSC)来提高ES的写效率
当写请求发送到ES后,ES将数据暂时写入memory_buffer,此时写入数据还不能被查询
默认设置下,ES每秒将memory_buffer中的数据refresh到Linux的FileSystemCache,并清空memory_buffer,此时写入的数据就可以查询了
refresh API
在ES中,写入和打开一个新段的轻量的过程叫refresh,默认下每个分片会每秒自动执行一次
所以说ES是近实时的,文档变化并不是立即可见,但会在一秒之内变为可见
实际中,索引一个文档后需要立即搜索,可以使用refresh_API执行一次手动刷新
并不是所有情况都需要每秒刷新,可以通过设置refresh_interval,降低每个搜索的刷新频率
refresh_interval可以在索引上进行动态更新,建立一个大索引时,可以先关闭自动刷新(-1),待完成后,再把参数调整会来
持久化变更
原理
如果没有用fsync把数据从文件系统缓存刷到硬盘,不能保证数据的可靠性
在动态更新索引时,一次完整的提交会将段刷到磁盘,并写入一个包含所有段列表的提交点,ES在启动或重新打开一个索引的过程中使用这个提交点来判断那些段属于当前分片
ES增加了一个translog(事务日志),在每次对ES进行操作时均进行了日志记录,通过translog的流程
1、一个文档被索引之后,会被添加到内存缓冲区,且追加到了translog
2、进程继续工作,更多文档被添加到内存缓冲区且追加到事务日志
3、每隔一段时间,索引被刷新;一个新的translog被创建,并且一个全量提交被执行
所有在内存缓冲区的文档都被写入一个新的段
缓冲区被清空
一个提交点被写入硬盘
文件系统缓存通过fsync被刷新
老的translog被删除
translog提供所有还没有被刷到磁盘的操作的一个持久化记录,ES启动时,它会从磁盘中使用最后一个提交点去恢复已知的段,且会重放translog中所有在最后一次提交后发生的变更操作
translog也被用来提供实时CRUD,当尝试通过ID查询、更新、删除一个文档,它会在尝试从相应的段中检索之前,首先检查translog任何最近的变更
这意味着它总是能够实时地获取文档的最新版本
flush API
执行一个提交且阶段translog的行为,分片每30分钟被自动刷新,或translog过大时也会刷新
flush_API可以手动执行
在重启节点或关闭索引前执行flush有益于索引,当ES尝试恢复或重新打开一个索引,它需要重放translog中所有的操作,所以如果日志越短,恢复越快
Translog
目的是保证操作不丢失,文件被fsync到磁盘前,被写入文件在重启之后就会丢失,默认translog每5秒被fsync到磁盘,或在每次写请求完成之后执行
translog的flush操作在主分片和复制分片都会发生,最终意味着在整个请求被fsync到主/复分片的translog之前,客户端不会得到200响应
在每次写请求后都执行一个fsync会带来一些性能损失,所以使用异步的fsync是比较有益的,可以通过设置durability为async来启用该行为
索引文件存储段合并
机制
启动段合并在进行索引和搜索时会自动进行
1、当索引的时候,刷新操作会创建新的段并将段打开以供搜索使用
2、合并进程选择一小部分相似的段,且在后台将它们合并到更大的段中,这并不会中断索引和搜索
3、合并完成时的活动
新的段被刷新到磁盘,写入一个包含新段且排除旧的小的段的新提交点
新的段被打开用来搜索
老的段被删除
合并大的段需要消耗大量的IO和CPU字段,ES默认情况下会对合并流程进行资源限制
归并线程的限速配置
indices.store.throttle.max_bytes_per_sec=20MB
对于写入量较大,磁盘转速较高,甚至使用SSD的服务器来说,这个限速明显过低
对于ELK应用,建议可以适当调整到100M或更高
用于控制归并线程的数据,推荐设置为CPU核心数的一半,如果觉得磁盘性能跟不上,可以降低配置,免得IO陷入瓶颈
index.merge.scheduler.max_thread_count
归并策略
归并线程按照一定的运行策略来挑选segment进行归并
index.merge.policy.floor_segment
默认2MB,小于该值的segment,优先被归并
index.merge.policy.max_merge_at_once
默认10,一次最多归并segment的个数
index.merge.policy.max_merge_at_once_explicit
默认optimize时,一个最多归并30个segment
index.merge.policy.max_merged_segment
默认5G,大于该值的segment,不参与归并,optimize除外
optimize API
可看做时强制合并API,它将一个分片强制合并到max_num_segments指定大小的段数目,意图是减少段的数量(通常减少到一个),来提升搜索性能
特定情况下,使用该API颇有益处,如日志用例下,每天、月、年的日志被存储在一个索引中,可以使用optimize优化老的索引
并发冲突处理
乐观锁
ES的后台都是多线程异步的,多个请求之间乱序
ES的多线程异步并发修改时基于自己的_version版本号进行乐观锁并发控制的
后修改的先到时,比较版本号,相同则进行修改
先修改的后到时,比较版本号,不相等则再次读取新数据进行修改
删除操作也会更新版本号,因为不是立即删除
并发控制基于最新的数据和版本号
以前是version,现在是if_seq_no和if_primary_term
external_version
ES提供了一个feature,可以不用_version来进行并发控制,而是基于自己维护的一个版本号来进行并发控制
?version=1&version_type=external
区别
version方式,只有当提供的version和es中的version相同,才可以进行修改
external方式,提供的version比es中的version大时,可以完成修改
分布式数据一致性
ES5.0之前
发送任何一个增删改操作时,可以带上一个consistency参数,指明想要的写一致性
one
只要有一个primary shard是active,就可以执行
all
必须所有的primary shard和replica shard都是活跃的,才可以执行
quorum
默认值,要求所有shard中,必须是指定数的shard活跃,才可以执行
quorum
公式
int((primary_shard + number_of_replicas)/ 2 ) + 1
number_of_replicas > 1时有效
timeout
quorum不齐全时,会默认wait1分钟
可以设置timeout手动调整,默认单位ms
等待期间,期望活跃的shard数量可以增加,最后无法满足就会timeout
可以在写操作时,加一个timeout参数,自定义quorum不齐全时的timeout时长
ES5.0及之后
不支持consistency参数
使用wait_for_active_shards
Query文档搜索
版本
2.0前
QUERY_AND_FETCH、DFS_QUERY_AND_FETCH、QUERY_THEN_FETCH、DFS_QUERY_THEN_FETCH
2.0后
QUERY_THEN_FETCH、DFS_QUERY_THEN_FETCH
类型
QUERY_AND_FETCH
像索引的所有shard发出查询请求,各分片返回时把元素文档和计算后的排名信息一起返回
该方式最快,因为只需要去shard查询一次,但各shard返回的结果数量之和可能是用户要求的size的n倍
优点
速度最快
缺点
返回数据量不准确,可能返回的数据排名也不准确
DFS_QUERY_AND_FETCH
DFS:Distributed frequency Scatter,分布式词频率和文档频率散发
DFS就是在进行真正查询之前,先把各分片的词频率和文档频率收集,然后进行词搜索时各分片依据全局的词频率和文档频率进行搜索和排名
该方式比第一种多了一个DFD步骤,可以更精确控制搜索打分和排名
优点
数据排名准确
缺点
性能一般,返回数据量不准确,可能返回(N*分片数)的数据
QUERY_THEN_FETCH
默认方式,大概步骤
一,现先所有shard发出请求,各分片只返回文档id和排名相关的信息,然后按照各分片返回的文档的分数进行重新排序和排名,取前size个文档
二、根据文档id去相关shard取document,返回文档数和用户要求的一致
详细过程
1.发送查询到每个shard
2.找到所有匹配的文档,并使用本地的Term/Document Frequency信息进行打分
3.对结果构建一个优先队列(排序、标页等)
4.返回关于结果的元数据到请求节点
实际文档还未发送,只是分数
5.来自所有shard的分数合并起来,并在请求节点上进行排序,文档被按照查询要求进行选择
6.最终,实际文档从各自所在的独立shard上检索出来
7.返回用户结果
优点
返回数据量准确
缺点
性能一般,且数据排名不准确
DFS_QUERY_THEN_FETCH
比第三种方式多一个DFS步骤
在查询之前,先对所有分片发送请求,把所有分片中的词频和文档频率等打分依据全部汇总,在执行后面的操作
详细步骤
1. 预查询每个shard,询问Term和Document Frequency
2. 发送查询到每个shard
3. 找到所有匹配文档,并使用全局的Term/Doucment Frequency信息进行打分
4. 对结果构建一个优先队列(排序,标页等)
5. 返回关于结果的元数据到请求节点
实际文档还未发送,只是分数
6. 来自所有shard的分数合并起来,并在请求节点上进行排序,文档被按照查询要求进行选择
7. 最终,实际文档从各自所在的独立shard上检索出来
8. 返回用户结果
优点
返回数据量准确,排名准确
缺点
性能最差
只是表示在四种方式中性能最慢,也不至于不能忍受
如果对查询性能要求不高,且对查询准确度要求较高可以考虑
文档增删改和搜索请求过程
增删改流程
1、客户端首先选择一个节点Node发送请求,该节点可能是协调节点
2、协调节点会对document数据进行路由,将请求转发给对应node(含有primary shard)
3、实际node的primary shard处理请求,然后将数据同步到对应的replica shard的node
4、协调节点如果发现primary和replica的node符合要求数量,就会返回响应结果给客户端
search流程
1、客户端首先选择一个节点Node发送请求,该节点可能是协调节点
2、协调节点将搜索请求转发到所有shard
3、每个shard将自己的搜索结果元数据发到请求节点,由协调节点进行数据合并、排序、分页等操作,产出最终结果
4、协调节点根据docId去各个节点拉取实际的document数据,最终返回给客户端
BM25(相关性评分算法)
介绍
BM(Best_Match)25是在信息检索系统中根据提出的query对document进行评分的算法
BM25是在TF-IDF算法上改进的
TF算法在文本内容多时不可靠,多篇文档内容长度不同,对TF算法的结果影响很大,所以需要将文本的平均长度考虑进去
改进
k1
词语频率饱和度,用于调节饱和度变化的速率
一般介于1.2~2.0,数值越低则饱和过程越快速
ES应用中为1.2
b
字段长度规约,将文档的长度规约化到全部文档的平均长度
值介于0~1,1表示全部规约化,0表示不进行规约化
ES应用中为0.75
说明
k1用来控制公式对词项频率tf的敏感程度,即k1是衡量高频term所在文档和低频term所在文档的相关性差异
b单个文档对相关性的影响力与它和平均长度的比值有关,用来控制文档长度L对权值的惩罚程度
调整
ES7前
ES7
DocValues压缩
起源
倒排索引的检索性能非常高,但是在字段值排序时却不是理想的结构
doc_values
true
默认,ES会增加一个对应的正排索引,这会增加磁盘占用,也会导致索引数据速度慢一点
false
无法基于该字段排序、聚合、在脚本中访问字段值
介绍
DocValues转置倒排索引和正排索引两者间的关系
倒排索引将词项映射到包含它们的文档,DocValues将文档映射到它们包含的词项
数据被转置后,想要收集到每个文档行,获取所有的词项就非常简单了
深入
DocValues在索引时和倒排索引同时生成,即它和倒排索引一样,基于Segment生成且不可变
同时DocValues和倒排索引一样序列化到磁盘,这对性能和扩展性有很大帮助
DocValues通过序列化把数据结构持久化到磁盘,可以充分利用操作系统的内存,而不是JVM的heap
当workingset远小于系统可用内存,系统会自动将DocValues保存在内存中,使其读写十分高速
当其远大于可用内存时,操作系统会自动把DocValues写入磁盘,如此性能比在内存中差很多,但是大小就不再局限于内存了
压缩
DocValues本质上是一个序列化的列式存储,这个结构非常适用于聚合、排序、脚本等操作
该存储方式也非常便于压缩,特别是数字类型
这样可以减少磁盘空间且提高访问速度
DocValues在压缩过程中使用如下技巧,它会依次检测以下压缩模式
如果所有数值各不相同(或缺失),设置一个标记并记录这些值
如果这些值小于256,将使用一个简单的编码表
如果这些值大于256,检测是否存在一个最大公约数
如果不存在最大公约数,从最小的数据开始,统一计算偏移量进行编码
如果存储String类型,一样可以通过顺序表对String类型进行数字编码,然后再把数字类型构建DocValues
禁用
DocValues默认对所有字段启用,除了analyzed_strings
analyzed_strings暂时不能使用DocValues,因为经过分析后的文本会生成大量的Token,这样非常影响性能
如果存储的数据确实不需要该特性,可以禁用它,以节省磁盘空间,并提升索引速度
在mapping中设置doc_values: false
Filter过滤
1、在倒排索引中查找搜索穿,获取document list
2、Filter为每个在倒排索引中搜索到的结果,构建一个bitset,如[0,0,1,0,1,0]
bitset数据结构简单,可以节省内存空间,提升性能
3、多个过滤条件时,遍历每个过滤条件对应的bitset,优先从最稀疏的开始搜索,查找满足所有条件的document
4、caching_bitset,跟踪query,在最近256个query中超过一定次数的过滤条件,缓存其bitset,对于小segment(<1000或<3%),不缓存bitset
5、如果document有新增或修改,则caching_bitset会被自动更新
6、filter大部分情况下,在query之前执行,先尽量过滤尽可能多的数据
搜索精准度
boost
搜索条件权重,可以将某个搜索条件的权重加,默认情况下,搜索条件的权重都是1
dis_max
best fields策略
搜索到的结果,应该是某一个field中匹配到了尽可能多的关键词,被排在前面,而不是尽可能多的field匹配到了少数的关键词,排在前面
语法
直接取多个query中,分数最高的那一个query的分数即可
function_score
ES进行全文搜索时,结果默认以文档的相关度进行排序,而”文档相关度“,可以通过function_score自定义
function_score查询提供了几种类型的得分函数
script_score
weight
random_score
field_value_factor
decay functions: gauss、linear、exp
field_value_factor
该函数可以使用文档中的字段来影响得分,与使用script_score类似,但避免了脚本编写的开销
如果用于多值字段,则计算中仅使用该字段第一个值
选项
field
要从文档中提取的字段
factor
字段值倍数,默认1
modifier
字段值的修饰符
取值
none
不对字段值应用任何乘数
log
去字段值的常用对数
log1p
将字段值加1取对数
log2p
将字段值加2取对数
ln
取字段值的自然对数
ln1p
将字段值加1取自然对数
ln2p
将字段值加2取自然对数
square
对字段值求平方
sqrt
对字段值取平方根
reciprocal
交换字段值,1/x
函数产生的分数必须为非负数,否则将引发错误
Decay functions
衰减函数对文档进行评分,该函数的衰减取决于文档的数字字段值与用户给定原点的距离
要在具有数字字段的查询上使用距离计分,必须为每个字段定义
origin
定义从中间计算距离的”中心点“
scale
定义衰减率
属性
origin
计算距离的原点,对于数字字段,必须指定为数字,对于日期字段,必须指定为日期,对于地理字段,必须指定为地理点
地理位置和数字字段必填,日期字段默认为现在
原始日期支持日期数学(如now-1h)
scale
所有类型必需,定义原点的距离+偏移,计算出的分数将等于衰减参数
地理字段:数字+单位,如1m、2km,默认单位m
日期字段:数字+单位,如1h、10d,默认单位ms
数字字段:任何数字
offset
如果定义了偏移量,则衰减函数将仅计算距离大于定义偏移量的文档的衰减函数,默认为0
decay
衰减函数定义如何按比例给定的距离对文档进行评分
如果未定义衰减,则距离尺度的文档将获得0.5分
支持函数
gauss高斯
linear线性
exp指数
bulk数据格式和底层性能
bulk中的每个操作都可能要转发到不同node的shard上执行
bulk处理流程
如果采用良好json数组格式
1、将Json数组解析为JsonArray对象,此时,整个数据,会在内存中出现一份一摸一样的拷贝
2、解析Json数组中的每个Json,对每个请求中的document进行路由
3、为路由到同一个shard的多个请求,创建一个请求数组
4、将该请求数组序列化
5、将序列化的请求数组发送到对应节点
使用丑陋的json
1、不同转换Json对象,直接按照换行符切割Json
2、对每两个一组的Json,读取meta,进行document路由
3、直接将对应Json发送到对应node上
对比
优雅格式
耗费更多内存,更多JVM_GC开销
占用更多内存可能会积压其他请求的内存使用量,可能导致其他请求的性能急速下降
占用更多内存,对导致ES的JVM_GC次数更多,更频繁
丑陋格式
最大优势在于无需将Json数组解析为一个JSONArray对象,形成大数据的拷贝,浪费内存空间,尽可能保证性能
深度分页
说明
ES默认分页方式是from+size,当请求数据量较大时,ES会对分页做出限制,因为此时性能消耗很大(CPU、内存、IO、网络带宽)
ES有个设置index.max_result_window,默认为10000,如果分页数据超过该值,就拒绝返回结果
可以根据实际适当放大该参数
解决方案
1、利用scroll遍历
scroll分为初始化和遍历两步,初始化时将所有符合搜索条件的结果缓存起来,遍历时,从缓存快照中取数据
初始化后对索引的插入、删除、更新都不会影响遍历结果,所以scroll不适合用来做实时搜索,而更适用于后台批处理任务
说明
初始化
需要像普通search一样,指明index和type,然后加上scroll参数,表示暂存搜索结果的时间
返回一个scroll_id,用来下次取数据用
遍历
scroll_id即上次遍历或初始化返回的,同样,操作需要带scroll参数
重复该步骤,直到返回的数据为空,即遍历完成
每次都需要传参数scroll,刷新搜索结果的缓存时间
2、Search after
满足实时获取下一页的文档信息,该方式根据上页的最后一条数据来确定下页的位置
在分页请求过程中,如果有索引数据的增删改,变更也会实时反映到游标上
该方式在ES5.x之后提供,为了找到每页最后一条数据,每个文档的排序字段必须有一个全局的唯一值,使用_id即可
下页的数据依赖上页的最后一条信息,所以不能跳页
比较
from+size
性能低,灵活性好,实现简单,不能解决深度分页
适用于数据量较小,能容忍深度问题的场景
scroll
性能中,解决了深度分页问题,但无法反应数据实时性,维护成本高
适用于海量数据的导出
search_after
性能高,不存在深度分页问题,能够反映实时数据,但实现连续分页比较复杂
适用于海量数据的分页
1
0 条评论
下一页