Elasticsearch知识大纲
2021-10-06 16:18:05 1 举报
AI智能生成
登录查看完整内容
Elasticsearch全部知识点
作者其他创作
大纲/内容
集群上所有索引
/search
指定某索引
/index1/search
多个索引
通配符方式
/index*/_search
q=title:2012
q=2012&df:title
指定字段查询
q=2012
泛查询
q指定查询语句
df默认字段 不指定则查询全字段
sort排序 from size分页
以上进行分析
profile:true用来查看如何被执行
OR
(beautiful mind)
title:(beautiful mind)
term query
AND 且顺序不能变
\"beautiful mind\"
title:\"beautiful mind\"
phrase query
AND/OR/NOT
布尔操作
q=year:>=1980
范围查询
q=title:b*
通配符
...还有几种
示例
格式
URI Search
基本示例
只返回某个字段
\"_source\":[\"name\"]
子主题
脚本字段
match中放具体的字段和值 上面一种是OR 下面才是AND
短语搜索 相当于must并且顺序一直
match phrase
Match
Query String
Simple Query String
Request Body Search
term查询不会对查询的内容进行分词
即使对term做keyword查询
也会进行相关度算分
查不到
即转小写
没给查询的内容iPhone分词
用term查询iPhone
命中了索引iphone
查得到
用trem查询iphone
比如你索引一个iPhone
Trem Query
Range Query
Exists Query
Prefix Query
Wildcard Query
term查询中term中是最小的查询单位
term查询很多时候不需要算分的
查keyword 就是精确匹配
查子字段keyword
不算分 提升性能
filter也可以用到缓存
通过constant score转为filter
Match Query
Match Phrase Query
Query String Query
全文本查询
term&全文本查询辨析
尽可能返回较少的无关文档
Precision查准率
尽量返回较多的相关文档
Recall查全率
是否能够按照相关度进行排序
Ranking
Information Retrieval
把最高分最具相关性的返回给用户
算分的本质是排序
搜索词出现的次数除以文档的总词数
停用词可以忽略
TF(term frequency)
检索词在所有文档中出现的频率
DF
简单就是log(全部文档数/检索词出现过的文档总数)
越少占比约大
IDF
默认算法为BM 25
img src=\
es5开始
查看如何算分
explain:true
打分相关度提升
>1
相对降低
0-1
负分
<0
boosting
算分
相关性
数字 日期 布尔值都是结构化数据
一些文本也是结构化数据
可以用term来搜索
constant score是包含匹配而不是精确的相同匹配
filter不算分性能好
需要对多值字段维护一个count 计数其size 借助boolquery才可以
对于多值的匹配
不需要算分的话就利用constant score
结构化搜索
搜索
修改模板不会影响已经创建的索引
模板仅在一个索引被新创建的时候,才会产生作用
这些设置会被merge在一起?
可以指定多个索引模板
指定order 控制merge的过程
一个索引被创建时的设置顺序1、最先使用es默认的settings mappings2、order从低到高使用覆盖3、用户定义的覆盖
PUT _template/tmplate_name
GET _template/template_name
index template
所有字符串设置成keyword类型或者关闭keyword字段
is开头设置成boolean
long_开头设置成long类型
举例
根据es识别的数据类型 结合字段名称 动态设定字段类型
PUT my_index{ \"mappings\": { \"dynamic_templates\": [ { \"strings_as_boolean\": { \"match_mapping_type\": \"string\
PUT my_index{ \"mappings\": { \"dynamic_templates\": [ { \"full_name\": { \"path_match\": \"name.*\
dynamic template
文档最初被写入到内存的位置
此时是搜索不到的
index buffer
index buffer写入到segment后 就可以被查到
segment
落盘的文件,顺序写
它这个落盘也不是实时落
5s落一次所以默认还是可能丢5s数据
配的越小落盘频率越高数据准确性高,但性能差,最小100ms
每次在写index buffer的时候同样会落盘到trans log上
为了保证数据的正确性而出现的
断点重启时可以从trans log中进行recover
transcation log
数据结构
默认1s发生一次 index.refresh.interval可配置
index buffer被清空写入到segment的过程
index buffer被占满时 也会触发 默认是JVM的10%
可以通过API手动refresh让数据能够立即被搜索到
refresh
调用refresh清空index buffer
调用fsync,将缓存中的segment写入磁盘
清空trans log
默认30分钟调用一次或trans log满的时候调一次 默认512M
flush
合并segment并真正删除.del中的文档
时间越长,segment越多
POST my_index/forcemerge
merge
写入/刷新步骤
无需考虑并发写文件问题 避免锁带来的性能问题
一旦读入内核文件系统缓存,只要文件系统缓存有足够空间,大部分请求就会走内存,不会命中磁盘,提升很大性能
缓存容易生成维护/数据可以被压缩
倒排索引不可变性
单个倒排索引文件被称为segment,自包含,不可变更
多个segment汇总在一起就是Lucene index,对应的就是es中的shard
commit point存储包含多个segment的信息
被删除的文档信息保存在.del文件中
Lucene index
前提
1s一次
为什么说是近实时
trans log
如何保证断点也不丢失数据
merge的时候删
为什么删除文档也不立刻释放空间
问题
若要优化索引速度 而不注重实时性,可降低refresh频率
当数据从hot移动到warm,官方建议手工执行一下_forcemerge
当节点数据量很大时,有重启节点的需要时,先手动flush,会为你节省很多时间。
trans log落盘的频率影响了数据的安全性
segment refresh的频率影响了数据的实时性
tips
分片生命周期
假如一个集群有3个主分片,副本分片是1则一共6个分片
请求过来,打到协调节点查询from + size
协调节点会从6个主副分片中随机选3个分片查询每个分片上都会查from+size 个数据
然后返回文档id和排序值
query
协调节点接收到文档id和排序值汇总到一起进行排序从from取size个数据通过mget从相应分片获取数据返回给用户
fetch
每个分片上都要查from size
最终协调节点需要处理number_of_shard *(from +size)
取的页数多了内存hold不住
深度分页
性能问题
由于算分的时候是每个分片独立的
所以分片数量多,文档总数过少会导致算分不准确
因此数据量小就1个分片,数据量大了,就尽量保证文档是均匀分布在分片上的,这样算分就准
可以通过_search?search_type=dfs_query_then_fetch这样它会把词频啥的汇总到协调节点上一起算完分再返回结果但这样势必性能差CPU 内存
相关性算分
query then fetch
机制
Analysis
#ik_max_word#ik_smart#hanlp: hanlp默认分词#hanlp_standard: 标准分词#hanlp_index: 索引分词#hanlp_nlp: NLP分词#hanlp_n_short: N-最短路分词#hanlp_dijkstra: 最短路分词#hanlp_crf: CRF分词(在hanlp 1.6.6已开始废弃)#hanlp_speed: 极速词典分词
分词器
针对原始文本进行处理,例如除去HTML或者&转换成and
可以有个0个或多个
Character Filters
按照规则切分为单词
至少一个
Tokenizer
将切分的单词进行加工,例如大小写转换,删除stop words,增加同义词
可以有0个或多个
Token Filters
组成
通过elasticsearch配置全局指定
创建索引或设置mapping时指定
ICU Analyzer IK/THULAC
中文分词器
种类
指定分词器,输入文本,可以查看该分词器是如何对文本分词
指定采用某索引的某字段的分析器进行分词分析
自己定义一个分词器进行文本分词分析 可以看到 I 被转了小写
文本分析
自定义analyzer
通过Analyzer实现
索引时会先分词
搜索时也会根据输入的查询条件分词
归一化词元 清除变音符号
抽取词根:清除单复数和时态差异
包含同义词
拼写错误或同音异形
一些可采取的优化
不同索引使用不同的语言
同一个索引不同的字段使用不同的语言
一个文档的一个字段混合不同的语言
具体多语言场景
词干提取:以色列文档包含了多语言
不正确的文档频率:英文为主的文章中,德文算分高(稀有)
需要判断用户搜索时使用的语言,语言识别Compact Language Detector
挑战
混合多语言的挑战
you're half-baked怎么分?
中文有歧义性
分词挑战
多语言及中文分词
方案1:不同语言用不同索引,例如 orders-cn ,orders-en
方案2:可以通过设置multi field 为期创建多个子字段,这个子字段可以使用不同的分词器。至于用户在搜索的时候使用什么语言,可以让用户指定,或者通过http header中的accept language来判定。至于你索引的数据,如果你明确知道他所用的语言,用方案一会很简单。否则你需要使用一个学习算法对文档的语言进行归类。有一些现成的库可以使用,例如chromiu-compact-language-detector ,基于google的CLD开发,支持160多种语言的detect
多语言场景 最佳实践
分词
1.text类型和keyword类型2. 多字段定义3.text下keyword的作用一切文本类型的字符串可以定义成 “text”或“keyword”两种类型。区别在于,text类型会使用默认分词器分词,当然你也可以为他指定特定的分词器。如果定义成keyword类型,那么默认就不会对其进行分词。es对字符串类型的mapping设定,会将其定义成text,同时为他定义一个叫做keyword的子字段。keyword只是他的名字,你也可以定义成kw。这个字段的类型是keyword(这是一个类型的关键字)精确查询/terms中的聚合
more about keyword
Text/Keyword
Date
Integer/Floating
Boolean
IPV4 IPV6
对象类型/嵌套类型
geo_point&geo_shape/percolator
数据类型
自动推断你索引的数据的类型
匹配日期 设置成Date
数字则设置为float long
增加keyword字段
设置为text
字符串
由第一个非空数值的类型决定
数组
忽略
空值
dynamic mapping
自动增加
dynamic设置为true
数据会被存入 但不会被索引
false
报错
strict
PUT user/_mapping{ \"properties\": { \"qq\": { \"type\": \"keyword\
新增字段
必须删除索引重建
即reindex
修改字段
mapping字段类型更改
使用动态mapping的隐患设置成strict,万一有一条数据里带着不存在的字段,写入就会失败设置成true,数据可以写入,还会在mapping中增加那个字段的设置;随着时间的流逝,这类数据会导致mapping设定的膨胀
如果mapping的dynamic设置成了false,然后新写了字段数据进来,可以使用更改mapping使用update by query来使得新增的字段重新被索引https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-update-by-query.html#picking-up-a-new-property
picking-up-a-new-property
默认true
不被索引 不不能查询
index
不需要高亮 freqs就够了 不需要算分高亮 docs就够了
index_option
为null的值数组中的null值都是不会被索引和搜索的 现在设置当可能有值为null的字段时,让它null的字段设置成\"NULL\"索引进去 搜索的时候搜\"NULL\" 这样就查的到那些为null的字段了
null
copy to
显式mapping设置
多字段类型
Mapping
定义
一些列满足特定条件的文档的集合
类似于SQL中的group
Bucket
Bucket Aggregation
一些数学运算 可以对文档字段进行统计分析
类似于SQL中的count,进行数学运算
Metric
Metric Aggregation
对其他的聚合结果进行二次聚合
Pipeline Aggregation
支持对多个字段的操作并提供一个结果矩阵
Matrix Aggregation
相当于group 支持嵌套
会进行分词后的计算
对text进行计算要开启fielddata:true一般用其子字段keyword 打开太昂贵
某人返回前10个 按doc_count由大到小排序
如果经常聚合会该索引一直有数据输入在mapping设置中把eagar_global_ordinals:true 提升聚合性能
terms
POST employees/_search{ \"size\
range
data range
histogram
date histogram
常用函数
结合结构来看 可以看到max_salary实际上就是聚合的名字max就是具体的函数然后指定字段
计算数值
max min sum avg cardinality(类似distinct count)
单值分析
stats
percentile
percentile rank
size
from
sort
top hits
多值分析
对聚合分析再做一个聚合分析有buckets_path的就是
Bucket Script Aggregation 与Bucket Selector Aggregation 这两种pipeline在实际中基本会用到Bucket Script Aggregation可对聚合集合做算术运算,生成一个新的结果Bucket Selector Aggregation可用于对聚合结果进行过滤,不会增加新字段
结果和现有分析同级
max min avg sum bucket
stats extend stats bucket
percentiles bucket
sibling
结果内嵌到现有的聚合分析结果之中
derivative求导
cumultive sum累计求和
moving function滑动窗口
parent
pipeline
默认是query查询的结果集
可以指定具体的范围再聚合 不影响外部结果集的聚合
filter
不影响聚合的结果 但是通过该filter 可以获取聚合结果中 你指定的数据
post filter
忽略平级的其他查询范围 对该级别所有的数据进行聚合
global
作用范围
默认按count降序排序
可以通过_count_key来指定排序
排序
https://www.elastic.co/guide/en/elasticsearch/reference/6.5/search-aggregations-bucket-terms-aggregation.html#search-aggregations-bucket-terms-aggregation-approximate-counts官方文档解释的很好
https://github.com/elastic/elasticsearch/issues/35987
The maximum possible doc_count for terms not returned by any bucket (this is currently considered)The maximum possible doc_count for terms returned by some buckets but that did not make the final list (this is not currently considered)
有可能遗漏的最大的文档值
doc_count_error_upper_bound这个计算有bug
没在返回桶中的文档总数
sum_other_doc_count
指定返回桶的数量
对于只有一个分片的shard_size = size
对于>1分片shard_size = size * 1.5 + 10
可以通过指定shard_size提高统计结果的精确度
精准度问题
切记zise设置成0
结构
聚合
启动
安装插件
计算等
脚本文件
bin
elasticsearch.yml
集群配置
用户配置等
配置文件
config
基于Java运行
JDK
存储的数据
data
Java类库
lib
运行日志
logs
ES各模块
modules
安装的插件
pulgins
文件结构
Xms = Xmx & <= host mem * 50%
https://www.elastic.co/blog/a-heap-of-trouble
堆太小,频繁GC
堆太大,STW时间过长,响应过长,影响集群状态
尽量设置4G,但实际情况下太小
少即是多
然后尽可能的少设置
尽量30G以下
不要超过30G
https://stackoverflow.com/questions/43651167/is-there-any-advantage-in-setting-xms-and-xmx-to-the-same-value
减少GC次数
向OS申请内存影响性能
提升性能
为啥xms xmx设置成一样的
题外话
JVM配置建议
索引Index
映射Mapping
文档Document
{ \"_index\": \"kibana_sample_data_ecommerce\
元数据
名词术语1
cluster
集群
分片的副本
副本
划分分片
保证高可用和分布式(扩展)
将数据分布到所有节点之上
Primary Shard 主分片
可动态调整
副本分片提升系统读取性能 通过增加replica个数 一定程度可以提高读取的吞吐量
从主写 可服务读
副本分片保证高可用
Replica Shard 副本分片
分片
一个集群中只有一个master
只有master可以修改集群中必要信息
其他节点保持一致
master node
每个节点启动后就是一个这样的节点
可通过设置node:master:false让它无法成为master
这样的节点有权被选举成master
默认第一个启动的成为master
master eligible node
存储数据的节点
data node
协调节点
接收请求,分发请求,汇总结果
默认都是协调节点
coordinating node
hot&warm node
machine learning node
节点设置
相比logstash处理数据功能较简单局限性高,但部署起来也简单
作为文档索引中的一环,用来处理数据,再将文档索引进es
预处理节点
https://cloud.tencent.com/developer/article/1354027
ingest node
生产中尽量让一个节点 单一职责
节点
名词术语2
Index即索引,对应表名
Document即文档,对应Row一条记录
Field即字段,对应column
7.0开始 一个mapping下默认只有一个type即_doc
Mappping即映射,对应chema
DSL即查询语言,对应SQL
借助关系型数据库理解
基本概念
GET kibana_sample_data_flights/_count
获取索引下文档总数
GET kibana_sample_data_flights
查看索引信息
默认只展示10条
POST kibana_sample_data_ecommerce/_search
GET _cat/indices/kibana_sample_data_ecommerce
索引信息
GET _cat/health
GET _cat/nodesGET _cat/shards
集群状态
GET _cat/count
集群下文档总数
GET /_cat/indices?v&health=green
查看状态为绿的索引
GET /_cat/indices?v&s=docs.count:desc
按条数排序索引
每条索引用了多少空间
基本API
结构化数据匹配
用来匹配数值 时间 等
全文本匹配
基本用在text上
match query
POST news/_search{ \"query\": { \"boosting\": { \"positive\": { \"match\": { \"content\": \"apple\
提供算分权重
pie提供负分 苹果公司信息优先
对某些搜索做特定性优化
boosting query
举例 把自己es那个拿过来
必须匹配
提供算分
must
是个数组
其中一个满足就可以
如果没有must 则必须满足一条should
should
不提供算分
必须不匹配
must_not
filter
bool query里面套的是term match query
should not 多个情况下 有一个不满足就可以
bool查询支持嵌套 bool下可以再嵌套bool
同一级的查询具有一个相同查询权重
再下一级合起来才和上一级的权重一样
bool query
PUT /blogs/_doc/1{ \"title\": \"Quick brown rabbits\
可以看到 每个字段搜索的是同一个字符串
用在单字符串多字段上的查询
dismaxquery的作用就是把多个查询中 分最大的那个返回
如果简单的用should match来匹配算分过程是这样的查询should语句中的两个查询加和两个查询的平台乘以匹配语句的总数除以所有语句的总数所以尽管fox没在文档1中出现但是文档1中出现了两次brown导致算分比文档2大但实际上文档2是我们的最相关的返回
dis maxquery介绍
POST blogs/_search{ \"query\": { \"dis_max\": { \"queries\": [ { \"match\": { \"title\": \"Quick pets\
这样查 按理来说是文档2最高最合适但是文档1 2的得分一样 是因为两个文档各取了一个最高分返回没能区分出来加入tie_breaker参数 能提升非最高分的权重
1、获得最佳匹配语句的score2、将其他语句的评分与该参数相乘3、对以上评分求和并规范化0-1之间的浮点数0代表用最佳匹配1代表所有语句同等重要
tie_breaker
dis max query
帮助优化算分 自定义算分实现更灵活的排序
该query在查询结束后,对每一个匹配的文档进行一系列重新算分,根据新生成的分数进行排序
提供了算分函数,可以进行不同方式的算分
为每一个文档设置一个简单而不被规范化的权重
Weight
使用该数值来修改_score,例如将热度和点赞数作为算分的参考因素
根据不同的投票数来算分
有多种平滑函数
即算分= 老算分*log(1+vote)
使用modifier平滑曲线
即算分=老算分*log(1+factor*vote)
使用factor调整平滑曲线
POST /blogs/_search{ \"query\": { \"function_score\": { \"query\": { \"multi_match\": { \"query\": \"popularity\
Field Value Factor
为每一个用户使用一个不同的随机算分的结果
Random Score
以某个字段的值为标准,距离某个值越近,得分越高
衰减函数
自定义脚本完全控制所需逻辑
Script Score
算分函数
即指定老算分与函数分的计算方式默认是multipy 即相乘
multiply
sum
min/max
replace
另:max boost可以想分数控制在一个最大值
boost mode
场景:每个用户访问广告,广告随机展示,每次排序对于用户都一样
POST /blogs/_search{ \"query\": { \"function_score\": { \"random_score\": { \"seed\": 911119 } } }}只要是seed值相同 那么就不会变
一致性随机函数
function score query
搜索提示/自动补全场景
POST /articles/_search{ \"size\
存在就不提供建议
missing
在检索到了查询的词条的前提下还寻找到了其他\"相似的\"词条,然后\"只\"返回那些在所有文档中词频比查询词条更高的词条
popular
如果term命中的比较多 是不会提供建议的 实践出来的
无论是否存在都提供建议
always
suggestion mode
POST /articles/_search{ \"suggest\": { \"term-suggestion\": { \"text\": \"lucen hocks\
前缀匹配 指的是term至少匹配几个前缀默认是1 指得是一般单词开头不会打错
prefix
POST /articles/_search{ \"suggest\": { \"my-suggestion\": { \"text\": \"lucne and elasticsear rock hello world \
最多可以拼错的term数
max_errors
The confidence level defines a factor applied to the input phrases score which is used as a threshold for other suggest candidates. Only candidates that score higher than the threshold will be included in the result. For instance a confidence level of 1.0 will only return suggestions that score higher than the input phrase. If set to 0.0 the top N candidates are returned. The default is 1.0.
可信度阈值
confidence
phrase
原理:将输入的文本分解为token 然后在索引字典中查找相似的term并返回
term&phrase suggester
completion suggester
利用FST算法实现对性能要求高
将analyze数据编码成FST和索引一起存放
只支持前缀查找
POST articles/_search?pretty{ \"size\
{ \"mappings\": { \"properties\": { \"title_completion\":{ \"type\": \"completion\" } } }}指定索引字段type是completion
POST comments/_search{ \"suggest\": { \"MY_SUGGESTION\": { \"prefix\": \"sta\
POST comments/_doc{ \"comment\":\"I love the star war movies\
PUT comments/_mapping{ \"properties\": { \"comment_autocomplete\":{ \"type\": \"completion\
任意字符串感知
category
基于地理位置
geo
基于上下文提供补全搜索
complete & context suggester
和dis max query相同匹配的时候返回在某一字段上分最高的结果可以用tie_breaker来提升其他字段匹配分的权重
POST blogs/_search{ \"query\": { \"multi_match\": { \"type\": \"best_fields\
best fields
在尽可能多的字段上匹配在越多的字段上匹配 分越高
通过匹配title 还原词根后匹配 能够尽可能多的搜索到相同词根的文档 提升了recall
通过匹配title.std 弥补了English分词造成的信息丢失的问题 提高了准确率
这里还可以给字段加权重title^10
PUT /titles{ \"mappings\": { \"properties\": { \"title\": { \"type\": \"text\
most fields
GET /_validate/query?explain{ \"query\": { \"multi_match\": { \"query\": \"peter smith\
对于某些实体 比如姓名 地址 单个字段必须作为整体的一部分来查询就可以用cross_fieldsand的作用不是让query的term出现在每个字段中 而是保证query的term能够都出现
cross fields
mulit match
将后台与搜索分离
GET _cluster/state/metadata?filter_path=*.stored_scripts
后台工程师只需要传DSL中的参数即可
对于DSL模板有更新时,直接传改了再post即可
POST _scripts/tmdb{ \"script\": { \"lang\": \"mustache\
search template
实现零停机运维
可以为索引创建别名,每个索引都可以创建多个别名,别名还可以带特定的搜索条件
如果每天一个新的索引,可以有一个定时任务,凌晨时执行,把别名刷新到新的索引上
问题:索引别名切换过程中,写入的数据是写到的旧索引还是新索引切换过程中还是会写到老索引上的(没找到具体答案 应该是很快的操作)https://elasticsearch.cn/question/4422
问题:一个别名对应多个索引 搜索的时候是什么情况
index alias
指定字段之后,就不算分了
支持多字段排序
会报错必须开启fielddata为true
一般对text排序没有意义
对text排序
索引的时候和倒排索引一起创建
docvalue
动态创建 搜索的时候创建
fielddata
何时创建
磁盘
JVM 堆
创建位置
节省内存空间
快
优点
降低索引速度占用磁盘空间
占用JVM内存空
缺点
2.X之后
1.X之前
缺省值
docvalue和fielddata比较
docvalue可以通过mapping关闭
docvalue重新打开需要重建索引
不需要排序和聚合就可以关了docvalue
from +size<=10000
可通过index_max_windows设置更改
基本分页
不支持页数 即from
只能往下翻
The _id field has a unique value per document but it is not recommended to use it as a tiebreaker directly. doc value are disabled on this field so sorting on it requires to load a lot of data in memory. Instead it is advised to duplicate (client side or with a set ingest processor) the content of the _id field in another field that has doc value enabled and to use this new field as the tiebreaker for the sort.
虽然id是唯一的但是它没有docvalue 排序会占用大量内存性能不好
还是业务端整个唯一ID
保证排序的值是唯一的 通过加上_id排序
通过唯一的排序值定位 每次在分片上取size个数据就可以
search after
创建快照 指定存活时间
缺点是快照创建后 新加入的和删除的数据无法被查到
适合导出全部数据
scroll api
分页
QUERY
create操作 只有id不存在时 才可以创建 id存在会报错
create
put
指定文档的id进行删除
delete
对于post请求,也属于index 属于先删除再索引
通过这种api 实现对原有字段的更新 或者新增字段 对原有字段的更新必须是相同字段类型
update
post
GET my_index/_doc/1
get
操作类型有index delete create update 通过指定index/id和requestBody实现对应操作 每个操作都有单独的响应 互不影响
bulk
批量获取文档 通过指定index和对应id
指定获取某索引中的数据
通过source选项来指定要哪些数据
mget
指定索引名和请求体来搜索所有的匹配到的数据
msearch
ES的POST、PUT请求可以按照http请求的“幂等性”来理解PUT方法要求是幂等的,PUT方法修改资源状态时,URL直接指示待修改资源。POST方式不是幂等的,POST方法修改资源状态时,URL指示的是该资源的父级资源,待修改资源的信息在请求体中携带所以,对于ES的PUT请求,URL上需要明确到document ID,即可以新增又可以更新整个文档(ES的更新都是get-有就delete-再创建),但无论如何都是这一个document由于PUT请求既可以新增又可以更新的特性,为了提供putIfAbsent特性,即没有时才新增,增加了op_type=create的选项(op_type只有create、index)而POST请求URL是不需要指定ID的,每次都会创建一个新的文档,就不是幂等的。(其实PUT请求执行的操作,把PUT换成POST也是可以的,但这个官方没有说,是实验出来的)上面是根据Http请求来区分,如果根据ES API来区分:index: 针对整个文档,既可以新增又可以更新;create:只是新增操作,已有报错,可以用PUT指定ID,或POST不指定ID;update:指的是部分更新,官方只是说用POST,请求body里用script或_doc里包含文档要更新的部分;delete和read:就是delete和get请求
不要一次发送过多文档,笼统建议是1000-5000之间,建议一次发5-15M,默认不能超过100M
批量操作
CURD操作
如果有全文搜索的需求。或者有统计分析的需求es作为存储,数据可以在数据库里保存一份,定期同步到es中。数据库和es同步考虑使用logstash的jdbc connector。只需要配置就可以实现增量同步。物理删除的记录同步es,在logstash中不支持。但可以通过为数据增加isDeleted字段,标记成删除状态,同步到es后 再用程序删除。
数据同步
date类型是包含时区信息的,如果我们没有在json代表日期的字符串中显式指定时区,对es来说没什么问题,但是如果通过kibana显示es里的数据时,就会出现问题,数据的时间会晚8个小时。因为kibana从es里读取的date类型数据,没有时区信息,kibana会默认当作0时区来解析,但是kibana在通过浏览器展示的时候,会通过js获取当前客户端机器所在的时区,也就是东八区,所以kibana会把从es得到的日期数据减去8小时。这里就会导致kibana经常遇到的“数据时间延迟8小时”的问题。所以最佳实践方案就是:我们在往es提交日期数据的时候,直接提交带有时区信息的日期字符串,如:“2016-07-15T12:58:17.136+0800”。##索引中定义的日期格式与提交数据的日期格式要一致,否则会报错。
时区问题
理解原理
多分析
多调整测试
测试相关性
不要过度调试相关度
监控搜索结果 监控用户点击最顶端结果的频次
度量用户行为
后台实现统计数据 比如用户查询和结果有多少被点击了
哪些搜索没有返回结果
将搜索提高到极高水平的途径
监控并且理解用户行为
如果没有大量的写入,count值基本还是准确的。但是万一集群的性能出现了一些问题,数据在持续不断的写入时,你就有可能碰到count数值忽大忽小到的情况。因为统计来自不同的分片,而分片上的数据还在同步,并没有完成达到一致
ES做精确去重计算总数会存在误差么
如果这些商品随意存储在不同分片上
如果直接通过某一类查询商品,比如我先在要查询手机类下的苹果,但是由于文档是分散在分片下的
每个分片中手机这一类的数据数量不一样 词频也不一样,
那么在不同分片中搜索手机:苹果 苹果出现的词频就不一样 那么算分就不一样
当算分结果返回协调节点汇总时,可能由于算分不是很均匀导致排序结果不是很精准
可以指定路由 将不同种类的商品分布到不同分片上 这样就解决了不同分片下算分问题
有一个商品索引,不同分类下都有苹果这一词条 比如水果有苹果 手机有苹果 电脑有苹果
PUT products/_doc/1?if_seq_no=1&if_primary_term=1{ \"title\":\"iphone\
指定seq no和term实现并发控制
如果有同步数据库和es中数据的场景,就可以用数据库的version或者last update时间戳来作为外部的version,实现冲突的检测。
PUT products/_doc/1?version=30000&version_type=external{ \"title\":\"iphone\
指定version version_type=external
es中通过乐观锁版本控制并发
重新获取文档再更新
版本冲突了
并发控制
将最新版提前4-6月
版本使用推荐
通过在索引中增加时间戳可以更加方便的帮助你对索引进行管理。有这样一些好处1)如果你想删除超过4个月的数据,delete整个索引的性能要比deleteByQuery要更加高效2)查询可以通过创建 alias 在多个索引上进行查询,所以并不需要把数据都放在一个索引上
具备时间序列特点的索引
Index Modules 》index shard allocation 〉Delaying allocation when node leave通过setting API 改成一个相对大的时间,例如5分钟
在集群中测试关闭一个节点后,分片很快会initialize和rebalance;如果集群间网络抖动,分片可能一直处于rebalance状态;有没有参数可以控制分片重新开始rebalance的时间
其他
高亮
日志
订单
文本搜索
商品推荐
推荐功能
安全监控
网站搜索/垂直搜索/代码搜索
日志管理与分析/安全指标监控/应用性能监控/Web抓取舆情分析
场景
分布式搜索引擎
大数据近实时分析
主要功能
高性能
近实时
易用易扩展
特点
广度优先学习
基本功能
底层原理
数据建模
容量规划
性能优化
问题诊断
滚动升级
方案落地
学习要点
什么是倒排索引
一个基本的倒排索引应该是什么样子的
倒排索引在Lucene中的实现
倒排索引相对于MySQL B+树的优点
链接:https://blog.justcoder.tech/2021/08/27/dao-pai-suo-yin/
倒排索引
7.0默认主分片为1
主分片将一份索引的数据分散在多个Data Node上实现水平扩展
主分片在索引创建的时候指定,后续默认不能修改,如果要修改,需要重建索引
所以数据量过大时,要重建索引,扩展节点
例如只有一个分片,如果索引数据增长很快,集群无法通过增加节点实现对这个索引的数据扩展(就一个分片咋扩展啊)
主分片过少
单个分片容量很小,导致一个节点上有过多分片,影响性能
主分片过多
如果不设置副本分片那可能丢失数据
副本分片的引入提高了数据可用性
请求会转发到不同节点 找副本分片或主分片 减低负载
还是要结合物理资源的 你不能说你一台机器搞那么多分片 那也不会提升
请求会广播到所有分片 合并数据
https://elasticsearch.cn/question/3028
https://www.elastic.co/guide/en/elasticsearch/guide/current/_query_phase.html
通过增加replica个数 一定程度可以提高读取的吞吐量
副本分片提升系统读取性能
7.0默认副本分片为0
副本分片过多:降低集群整体写入性能
无法水平扩展
数据重新分配耗时
单个分片数据量太大
分片过少
7.0 默认只有一个分片
提前做好容量规划
文档在每个分片上打好分汇总到一起的
影响搜索打分,统计准确性
浪费资源,影响性能
分片过多
部分副本分片没完全分配
部分副本分片不可用
黄
主分片没完全分配
部分主分片不可使用
红
状态
不同的集群通过不同的名字来区分 通过配置文件设定
在单集群情况下,水平扩展时,节点数不能无限增加当集群的meta信息过多导致更新压力变大单个active master会成为性能瓶颈导致整个集群无法正常工作
允许任何节点扮演federated节点以轻量的方式将搜索请求代理
不需要以client node的形式加入其他集群
5.3引入跨集群搜索功能 cross cluster search
跨集群搜索
节点本质就是一个java进程 生产上最好一台机器一个节点每一个节点都有名字 通过配置文件配置每个节点启动后会分配一个UID 保存在data目录下
处理创建删除索引请求/决定分片被分配到哪个节点/负责索引的创建与删除
维护并更新cluster state
非常重要 部署上要考虑解决单点问题
等着只承担master单一角色
唯一个集群设置多个master eligible 节点
默认是数据节点
保存分片的数据,起到了数据扩展的作用
master node决定了如何把分片分发到数据节点上
解决数据水平扩展和数据单点的问题
路由请求到正确节点 例如创建索引请求需要路由到master节点接收请求,分发请求,汇总结果
p cid=\"n345\" mdtype=\"paragraph\" class=\"md-end-block md-p\" style=\
所有节点信息
所有的索引和其相关的mapping与setting信息
分片的路由信息
每个节点上都保存了集群的状态信息
只有master节点才能修改集群的状态信息并负责同步给其他节点
互相ping对方 id的当选主节点
选主的过程应该很短,这个期间,如果有创建index或者分片reallocation有可能会出错
选主流程!!!!
集群隔开后重新选举了主节点
7.0开始无需配置
集群脑裂
集群可能会再次重新在节点上分配分片
通过增加删除节点
一个主分片不可用,只要设置了副本分片,其中一个副本分片立即会将自己提升为主分片。同时会将自己的数据分配到一个新的replica上
可以让这个reallocation延迟一段时间
避免无谓的数据拷贝
有时候,我们只是对集群中一台机器重启,没必要做故障转移
数据会根据文档id并结合相应的hash算法将数据分发到不同的分片,即不同的shard上的数据肯定是不一样的
数据量不大,p和r上的数据应该会很快一致,数据量很小,数据从p到r需要很久,需要检查集群是否存在性能问题
故障转移期间,如果只是黄色变绿,应该不影响读写,因为副本会提升为主分片。集群变红,代表有主分片丢失,这个时候会影响读写。
node如果丢失,没有落盘,有丢失的可能。如果节点重新回来,会从translog中恢复没有写入的数据
数据丢失
故障转移
文档如何均匀到分片上
shard= hash(_routing)%number_of_primary_shards
确保了文档均匀分散到分片中
默认routing是文档id
可以自己指定routing
所以这是主分片数量不能随意修改的根本原因
由于公式中主分片的数量对公式结果的影响
哈希路由算法
请求到协调节点
hash文档id寻找分片
路由到对应分片
先删后索引
成功后返回给协调节点
协调节点响应
副本分片也会同步数据
更新一个文档
类似
删除一个文档
1、如果索引分片都可用,并且写入主副本都成功了,才返回给客户端。在refresh后,主副本同时对外提供查询服务。这个同步时间很短,可以认为主副本的数据是一致的。如果副本同步时间较长,甚至超过1s,在同步的时间差内,可能造成数据不一致的情况,但是对外的数据最终是一致的,所以是分布式下的最终一致性。2、如果索引主分片不可用,将禁止写入,数据是强一致的;3、如果索引副本分片不可用,则有部分副本写入失败,整体写入认为成功。由于不可用的副本也不提供查询服务,所以对外数据仍然是一致的。
同步问题
简单的说就是一致性哈希算法 N/1数据移动就行
但是es里面Lucene索引数据占很大比例,文档数据才占5%
这就导致了数据移动时,删除重新索引特别耗费时间性能
所以不合适
但是如果你能保证你的索引是增量的,那么可以直接建新索引,用alias cover住旧索引和新索引
为什么不用一致性哈希算法
文档分布式存储
分布式特性
虽然简化了更新但是有时候读操作更多
减少不必要的更新
不过存储空间越来越便宜了
节省了存储空间
主要是越范式化就需要join越多的表
一个完全范式化设计的数据库经常会面临查询缓慢的问题
副作用
范式化设计
数据 flattening
不使用关联关系,在文档中保存冗余数据拷贝
es通过压缩_source字段减少磁盘空间开销
无需join操作读取性能好
一条数据改动,可能会引起很多数据的更新
不适合数据频繁更新
反范式化设计
反范式化好处就是读取快,无需表连接,无需行锁
关系型数据库一般考虑范式化多,而es就考虑反范式化
对象类型
嵌套对象 nested object
父子关联关系parent/child
应用端关联
es并不擅长处理关联关系,一般有4中方法
建模设计
# 写入一条电影信息POST my_movies/_doc/1{ \"title\":\"Speed\
对象数组被存储成上图格式 导致搜索时也能被搜到
包含对象数组的对象
允许对象数组中的对象被独立索引
这个两个Lucene文档指的是啥
在内部nested文档会被保存在两个Lucene文档中,在查询时做join处理
比如例子中的演员姓名或者出生日期这种
而经常需要修改的数据则适合使用parent child
nested对象的更新删除会重新索引整个文档(根对象和嵌套对象),所以nested适合不经常更新的对象
PUT my_movies{ \"mappings\" : { \"properties\" : { \"actors\" : { \"type\": \"nested\
存储时需要提前设置mapping
存储
POST my_movies/_search{ \"query\": { \"bool\": { \"must\": [ {\"match\": {\"title\": \"Speed\
搜索时有特定的搜索方式
POST my_movies/_search{ \"size\
聚合时有特定的聚合方式
nested数据类型
对象/nested对象
通过维护一种父子关系的文档关系,使得文档与文档之间实现分离
子文档更新删除不影响父文档和其他子文档父文档更新也无需重新索引子文档文档关系是独立的
设置mapping
索引父文档
父文档和子文档必须在相同的分片上,确保join的性能当指定子文档的时候,必须指定它的父文档ID利用routing参数保证分配到相同的分片上
索引子文档
https://blog.justcoder.tech/2021/09/23/wen-dang-de-fu-zi-guan-xi/
按需查询文档
parent child
对比
reindex
字段类型修改
update_by_query
分词器更新
字典更新
mapping发生变更
主分片数改变
setting变更
集群内和集群间数据迁移
创建场景
POST blogs/_update_by_query
在现有的索引上重建
新增加的文档 分词器会起作用
旧文档不会起作用
为mapping增加分词器
update by query
在其他索引上重建
建一个新索引
POST _reindex
跨集群reindex
GET _tasks?detailed=true&actions=*reindex
支持异步操作 POST _reindex?wait_for_completion=false
必须enable _source
reindex的时候可能会冲突 此时设置一个optype保证reindex只会创建不存在的文档否则会造成版本冲突
# Reindx API,version Type InternalPOST _reindex{ \"source\": { \"index\": \"blogs\
有时候dest index中有数据
reindex时可以继续搜索。建议为索引创建alias,当reindex完成后 通过alias切到新的index
如果有数据库同步到es进程,重建的时候看时间,可能要先把同步停了
elastic-dump第三方工具实现
span style=\
注意点
source的数据会直接覆盖到dest version基于的dest +1
internal
source的和的dest冲突会报版本冲突 停止reindex
external
忽略版本冲突的 继续处理 处理完返回产生冲突的数量
proceed
只reindex不存在的 有版本冲突会报错
optype create
reindex api
索引重建
每个节点都是ingest node
可拦截index或bulk api的请求
具有预处理数据的能力
为某个字段设置默认值
重命名某个字段的字段名
对字段进行split操作
对数据进行转换
模拟执行
ingest/pipeline/_simulate
增加pipeline保存到es中
内置processer
和logstash对比
ingest pipeline
对文档字段进行加工处理
更新或删除字段
...
通过脚本访问字段
painless script(没认真看)
根据数据量 写入 和查询的吞吐量 选择合适的部署方式
dedicated node
建议设置单一角色的节点
生产环境中
要会配置
负责集群状态管理
只用来维护集群信息不接收多少请求
使用低配置的CPU RAM和磁盘
master eligible nodes
重中之重
负责存储数据和处理客户端请求
使用高配置的CPU RAM和磁盘
dedicated data nodes
负责数据处理
不怎么存数据内存里存 CPU快速计算返回去
高配置CPU 中等RAM 低配置磁盘
dedicated ingest nodes
单一职责节点
高配CPU 中等配置RAM Low Disk
负载均衡 降低master和data nodes负载
负责搜索结果的gather/reduce
大量占用内存的结合操作一个深度聚合可能会引发OOM
有时候无法预知客户端发送怎样的请求
生产环境中 建议为一些大的集群配置Coordinating Only Nodes
Dedicate Coordinating Only Node
防止脑裂
一般生产环境中配置3台
负责分片管理 索引创建 集群管理
一个集群中只有1台活跃的主节点
data node相对会有比较大内存占用
coordinate节点有时可能会有开销很高的查询 导致OOM
影响master节点导致集群不稳定
要是不dedicate
dedicate master node
基本部署
前置一个load balance 应用和load balance 交互 lb也能帮助请求均衡地打到协调节点上
水平扩展
读一个lb一套协调节点 写一个lb一套ingest node用于处理数据在实际开发中,怎么确定写请求访问写的 读请求访问读的 可能是初始化两个客户端 一个读一个写
读写分离
集群中部署kibana
GTM Global Traffic Manager 一种负载均衡GTM主要来做数据的读取 对于异地多活的数据一致性 要么程序分别写入集群 要么写入一个集群 用es的跨集群复制数据保持一直
异地多活
常见的集群部署方式
比较新的 索引查询更改频繁的 放在hot 比较旧的查询更改很少的放在warm
索引对CPU和IO都有很高的要求
上SSD
hot用好配置
机械硬盘
warm用低配置
这样降低硬件成本
hot warm节点设置
sharding filtering
防止机架断电
rack awareness
hot&warm
最小的单元是分片,分片少了你是无法水平扩展的
shard rebalancing
当你扩展节点的时候,多的分片会自动的分配到新节点上
集群中有新的数据节点加入 分片就可以自动分配
分片在分配时不会有downtime
索引查询可以并行
数据写入可以分散到多个机器
多分片下
分片数大于节点数
设计分片数
2 * 180 = 360G 360个分片
案例1
案例2
每次搜索需要从每个分片上获取数据
分片信息有master维护过多会增加管理负担
每个分片是一个Lucene的索引会使用机器的资源过多分片导致额外性能开销
<50G
日志类
<20G
搜索类
提升update性能
merge时减少资源
丢失节点后 具备更快恢复速度 便于分片在集群内rebalancing
如何确定主分片数
防止数据丢失
提高系统可用性
但是要和主分片占用一样的资源
用处
有几份副本就会有几倍的CPU资源消耗在索引上
副本会降低数据索引速度
但是会消耗同样的内存资源
会减缓对主分片的查询压力
机器资源充分 提高副本数 可以提高整体查询的QPS
如何确定副本分片数
节点上最多几个分片
total shard per node
分片设计管理
一个集群多少节点?
一个索引几个分片?
机器的软硬配置
单条文档大小/文档总数据量/索引总数据量 time base数据保留的时间/副本分片数
文档是如何写入 bulk的大小
文档复杂度 文档如何进行读取的 查询和聚合
考虑因素
数据写入的吞吐量 每秒要求写入多少数据
单条查询可接收最大返回时间
数据吞吐及性能需求
数据格式和mapping
实际查询和聚合
数据细节
评估业务性能的需求
数据集大小固定
数据集增长相对比较缓慢
基于时间序列的数据
增长快
结合warm做数据老化处理
常见用例
数据节点尽可能使用SSD
配置内存和硬盘
1:10
搜索等性能要求 高的场景SSD
1:50
可以考虑使用机械硬盘存储
日志类和查询并发第的场景
最大不超5TB
单节点数据控制在2TB
JVM配机器内存的一般 不超32G
硬件配置
建议3台master
考虑高可用
建议设置corrdinating
有复杂查询和聚合
部署方式
根据地区进行拆分最后一点挺好用的!
搜索类型数据
hot warm
备份删除效率高 不像delete by query
通过特定规则URL转义之后获取对应索引的数据
有一个date math方法
time based索引
写程序定时去删
配置ILM定时删除
基于时间序列索引的删除
时间序列
拆分索引
解决CPU和内存开销问题
增加协调节点 ingest节点
解决存储容量的问题
为避免分布不均的问题 提前监控磁盘 提前清理数据或增加节点 70%
增加数据节点
集群扩容
集群容量规划
集群管理
Elasticsearch
收藏
0 条评论
回复 删除
下一页