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