ElasticSearch
2022-08-28 15:20:09 3 举报
AI智能生成
ElasticSearch架构、语法、原理
作者其他创作
大纲/内容
管理
节点类型
主节点
决定分片被分配到哪个节点
负责索引的创建与删除
维护并且更新cluster state
数据节点
查询节点
部落节点
预处理节点,Ingest node
pipeline
append
给字段增加属性
covnert
对字段类型进行转换
grok
将字段解析成一个标准文档的格式
date_index_name
将文档分配到符合指定时间格式的索引中
gsub
对字段值进行正则匹配替换
join
将原本一个数组类型的字段值,分解成以指定分隔符分割的一个字符串
json
将字符串格式的字段转换成一个标准的 JSON 格式
kv
用来 K,V 字符串格式的处理器,比如 K=V, K:V,K->V 等格式的解析
lowercase
对字段值转换为小写
uppercase
对字段值转换为大写
remove
删除原文档中的某些字段值的
rename
修改某个文档的字段的名称
split
用于将一个以指定分隔分开的字符串转换成一个数组类型的字段
sort
将某个数组类型的字段中的元素按照升序或降序来对原元素进行排序
定义pipeline
PUT _ingest/pipeline/管道处理名称{ "processors": [ { 处理器定义 } ]}
应用pipeline
PUT 索引名称/_doc/1?pipeline=管道处理名称
cat API
/_cat/nodes
节点
/_cat/shards
分片
/_cat/indices
索引
/_cat/segments
段
GET _cat/nodes?v&h=id,ip,port,r,ramPercent,ramCurrent,heapMax,heapCurrent,fielddataMemory,queryCacheMemory,requestCacheMemory,segmentsMemory
refresh
索引可见
默认1秒发生一次
flush
索引落盘持久化
默认30分钟调用一次
备份、恢复
_snapshot/backup
_snapshot/backup/_restore
选举
master选举,只有候选主节点(master:true)的节点才能成为主节点
最小主节点数(min_master_nodes)的目的是防止脑裂
若两节点都为候选主节点,则 id 小的值会主节点
乐观并发控制
内部版本控制
if_seq_no + if_primary_term
外部版本控制
version + version_type=external
断路器
Indices Circuit Breaker
indices.breaker.total.limit
所有breaker使用的内存值,默认值为 JVM 堆内存的70%,当内存达到最高值时会触发内存回收
Fielddata circuit breaker
indices.breaker.fielddata.limit
field数据使用内存限制,默认为JVM 堆的60%
indices.breaker.fielddata.overhead
elasticsearch使用这个常数乘以所有fielddata的实际值作field的估算值。默认为 1.03
Request circuit breaker
indices.breaker.request.limit
request数量使用内存限制,默认为JVM堆的40%
indices.breaker.request.overhead
elasticsearch使用这个常数乘以所有request占用内存的实际值作为最后的估算值。默认为 1
存储结构
逻辑存储
cluster state
所有的节点信息
所有的索引和其相关的mapping、setting信息
分片的路由信息
每个节点上都保存了集群的状态信息
只有master节点可以修改集群状态信息
index
生命周期
hot
warm
cold
delete
生命周期策略与索引模板的rollover
别名
索引别名可以指向一个或多个索引
字段别名
open、close
shrink、split、rollover
索引存储类型(index.store.type)
mmapfs:index映射到内存
niofs :并发多线程以NIO的方式读取index文件
hybridfs:混合 mmafs和niofs ,根据读取模式选择最佳的文件系统,term、norms、doc values使用的是mmapfs
type
7.0版本后已废弃,默认只有_doc
document
代表一条数据
field
数据类型
字符型:text, keyword
数字型:long, integer, short, byte, double, float,half_float,scaled_float
日期型:date
布尔型:boolean
二进制型:binary
范围型:integer_range,long_range,float_range,double_range,date_range,ip_range
数组类型:没有专门的数组类型, 直接使用[]定义即可
对象类型: object
嵌套类型: nested
地理坐标类型: geo_point
地理形状类型: geo_shape
IPl类型:ip
计数数据类型: token_count
mappings
字段属性
enabled:仅存储、不做搜索和聚合分析
index
analyzed:字段被索引,会做分词,可搜索
not_analyzed:字段值不分词,会被原样写入索引
no:字段不写入索引,当然也就不能搜索
index_option:存储倒排索引的哪些信息
docs:索引文档号
freqs:文档号+词频
positions:文档号+词频+位置,通常用来距离查询
offsets:文档号+词频+位置+偏移量,通常被使用在高亮字段
分词字段默认是positions,其他默认时docs
normalizer
字段标准化规则;如把所有字符转为小写
norms:用来计算文档/字段得分(Score)的"调节因子"、如果字段仅用于过滤和聚合分析、可关闭
doc_value
用于字段的排序或者聚合
支持大部分字段类型,但是text 字段类型不支持
占用磁盘空间
fielddata:是否为text类型启动fielddata,实现排序和聚合分析
store:是否从_source字段中分离,只能搜索,不能获取值,占用内存空间
coerce:是否开启自动数据类型转换功能
multifields:灵活使用多字段解决多样的业务需求
dynamic:控制mapping的自动更新
data_detection:是否自动识别日期类型
analyzer:指定分词器
boost:字段级别的分数加权
fields:可以对一个字段提供多种索引模式
ignore_above:超过设置个数字符的文本,将会被忽略,不被索引
null_value:设置一些缺失字段的初始化,只有string可以使用,分词字段的null值也会被分词
similarity:默认时TF/IDF算法,指定一个字段评分策略,仅仅对字符串型和分词类型有效
copy_to
指定某几个字段拼接成自定义
通用属性
_source
默认会存储一份_source字段作为原始文档
settings
number_of_shards 分片数
number_of_replicas 副本数
mappings 结构化数据设置 下面的一级属性 是自定义的类型
properties 类型的属性设置节点,下面都是属性
epoch_millis 表示时间戳
物理存储
节点
分片
路由
shard_num = hash(_routing) % num_primary_shards
routing默认是文档ID
偏好
_primary:只查询主shard,也就是说不管你有多少个副本,只对主shard进行检索,这种场景可以用在所有副本不可用的时候,强制读取主shard数据。
_primary_first:优先读取主shard,如果主shard无效或者失败,则会读取其他shard
_replica:只查询replia
_replica_first:优先查询replia,如果replia无效就查询其他的shard
_local:尽可能在本地执行查询,不跨网络
_prefer_nodes:abc,xyz 在指定的节点id上执行查询
_shards:2,3查询指定分片上的数据,此外这种写法还可以和前面的用法组合,如:_shards:2,3|_primary ,查询分片2和3且在主节点上的数据
_only_nodes :限制在特定的node上执行操作
副本
段
合并策略
tiered(默认)
log_byete_size
log_doc
Lucene文件存储
segments.gen、segments_N
段文件,存储提交点信息
write.lock
锁文件,用来阻止多个indexWriter向同一个文件写数据
.si
段信息,存储段的元数据信息
.cfs , .cfe
复合文件,一个可选的虚拟文件,包括所有其他索引文件系统频繁用完的文件句柄
.fnm
字段信息,存储字段的信息
.fdx
字段索引,包含指向字段值的指针
.fdt
字段数据,存储文档里面的字段信息
.tim
词典,存储词信息
包含每个字段中的术语列表,以及每个术语的统计信息(比如docfreq),以及指向.doc、.pos和.pay文件中的频率、位置、有效负载和跳过数据的指针
.tip
词索引,指向词典的索引
为每个字段都包含一个独立的FST。FST可以将一个term前缀映射到磁盘块上。这个磁盘块保存了以这个前缀开始的所有term
.doc
频率信息,包含那些含有每一个词的频率的文档列表
.pos
位置信息,存储词在索引中出现的位置信息
.pay
额外存储每个位置的元数据信息,如字符偏移和用户负载
.nvd , .nvm
文档和字段的length和boost系数的编码
.dvd , .dvm
额外的得分系数或者每个文档的值信息编码
.tvx
词向量索引,存储文档的偏移数据文件
.tvd
词向量文件,包含有词向量的文档信息
.tvf
词向量字段,关于词向量的字段级信息
.del
删除文档,关于什么文件被删除的信息
内存
common space
包括了indexing buffer和其他ES运行需要的class。indexing buffer由indices.memory.index_buffer_size参数控制, 默认最大占用10%,当full up后,该部分数据被刷入磁盘对应的Segments中。这部分空间是可以被回收反复利用的
queryCache
是node级别的filter过滤器结果缓存,大小由indices.queries.cache.size 参数控制,默认10%。使用LRU淘汰策略
requestCache
是shard级别的query result缓存,通常 only requests of size 0 such as aggregations, counts and suggestions will be cached。使用LRU淘汰策略。通过indices.requests.cache.size参数控制,默认1%
fieldDataCache
针对text字段,没有docValues属性(相当于列存储),当对text类型字段进行sort,agg时,需要将对应的字段内容全部加载到内存,这部分数据就放在fieldDataCache。通过indices.fielddata.cache.size 参数限制大小,默认不限制
segmentsMemory
缓存段信息,包括FST,Dimensional points for numeric range filters,Deleted documents bitset ,Doc values and stored fields codec formats等数据。这部分缓存是必须的,不能进行大小设置,通常跟index息息相关,close index、force merge均会释放部分空间
搜索
分词器
ik_max_word
ik_smart
query_string
字符串查询
name: acchu nagesh:查询name包含acchu和nagesh其中的任意一个
book.\*:(quick OR brown):book的任何子字段比如book.title和book.content,包含quick或者brown
_exists_: title:title字段包含非null值
name: acch*:通配符,匹配任何acch开头的字段
name:/joh?n(ath[oa]n)/:正则表达式,需要把内容放到两个斜杠/中间
name: acch~:模糊匹配,默认编辑距离为2,不过80%的情况编辑距离为1就能解决问题name: acch~1
count:[1 TO 5]:范围查询,或者count: >10
simple_query_string
+表示AND操作
|表示OR操作
-表示否定
"用于圈定一个短语
*放在token的后面表示前缀匹配
()表示优先级
~N放在token后面表示模糊查询的最大编辑距离fuzziness
~N放在phrase后面表示模糊匹配短语的slop值
term
关键字查询
match
数据类型自动转换
字段是keyword,查询时不会对查询条件进行分词
字段可以分词,查询时条件会进行分词
match_all
match
multi_match
ids
id匹配
prefix
前缀匹配
fuzzy
纠错模糊查询
wildcard
通配符查询
range
数值类型范围查询
regexp
正则查询
nested
嵌套查询,数据属性是数组的可以单独建立索引匹配
分页查询
from size
search after
记录最后的排序边界值,根据边界值进行后续分页查询
GET /索引库名称/_search
{
"size": 10,
"query": {"match_all": {}},
"sort": [
{"_id": "asc"}
],
"search_after": ["00000f78f59644b1967783986c35496c"]
}
scroll
缓存所有记录,不支持实时分页查询
GET /索引库名称/_search?scroll=保存时长&scroll_id=xxx
highlight
pre_tags
post_tags
fragment_size
复合查询
bool查询
must
must not
should
minimum_should_match
filter
不会计算评分,效率更高
bitset机制缓存数据
boosting查询
positive
negative
negative_boost
查询类型
GET /索引库名称/_search
{
"query": {
"查询类型": {}
},
"highlight":{
"pre_tags":[""],
"post_tags":[""],
"fields":{
"content":{
"type":"plain"
}
}
},
"aggs":{
"聚合名称":{
"聚合查询类型":{}
}
},
"管道聚合名称": {
"管道聚合类型": {
"buckets_path": "聚合计算的权值对象"
}
}
"sort":{
"字段名称": {"order":"desc|asc"}
},
"from":"", "size":""
}
"match_all": {}
"match": { "字段名称": "字段值"}
"multi_match": { "query": "字段值", "fields": [ "字段名称1", "字段名称2" ] }
"match_phrase": { "字段名称": "字段值"}
"term": { "字段名称": "字段值"}
"terms": { "字段名称": ["字段值1","字段值2"] }
"range": { "字段名称": { "gt": 字段边界值,"lte": 字段边界值} }
"exists": {"field":"字段名称"}
"bool": { "must": {}, "must_not": {} , "should": { } }
"wildcard": { "字段名称":"通配符表达式" }
"regexp": { "字段名称":"正则表达式" }
"query_string": {"query": "query_string查询语法", "fields": ["字段名称"] }
"prefix": { "字段名称": "字段值"}
"fuzzy": { "字段名称": "字段值"}
"ids":{ "values":[ id1,id2 ] }
聚合查询类型
"avg" : { "field" : "字段名称" }
"max" : { "field" : "字段名称" }
"min" : { "field" : "字段名称" }
"sum" : { "field" : "字段名称" }
"stats" : { "field" : "字段名称" }
"cardinality" : { "field" : "字段名称" }
"value_count" : { "field" : "字段名称" }
"percentiles" : { "field" : "字段名称" }
"percentile_ranks": { "field": "字段名称", "values": [ 字段值1, 字段值2 ]
"terms" : { "field" : "字段名称", "size" : 返回文档个数, "order" : { "_count| _key " : "asc | desc" }, "include" : "包含过滤值", "exclude" : "排除过滤值", "missing": "缺失值" }
"range":{ "field": "字段名称","ranges": [ {"from":"","to":"" }, { } ]
"date_range":{ "field": "字段名称","format": "日期格式","ranges": [ {"from":"","to":"" }, { } ]
"histogram" : {"field" : "字段名称", "interval" : 值间隔 }
"date_histogram":{"field":"字段名称","interval":"时间间隔","format":"日期格式","order":{ "字段名称":"asc | desc"}
管道聚合类型
"avg_bucket" : { "buckets_path": "聚合计算的权值对象" }
"max_bucket" : { "buckets_path": "聚合计算的权值对象"}
"min_bucket" : { "buckets_path": "聚合计算的权值对象" }
"sum_bucket" : { "buckets_path": "聚合计算的权值对象" }
"stats_bucket" : { "buckets_path": "聚合计算的权值对象"}
处理流程
搜索被执行成一个两阶段过程,我们称之为 Query Then Fetch
在初始查询阶段时,查询会广播到索引中每一个分片拷贝(主分片或者副本分片)
每个分片在本地执行搜索并构建一个匹配文档的大小为 from + size 的优先队列,每个分片返回各自优先队列中所有文档的 ID 和排序值给协调节点
协调节点合并这些值到自己的优先队列中来产生一个全局排序后的结果列表
接下来就是取回阶段,协调节点辨别出哪些文档需要被取回并向相关的分片提交多个 GET 请求。每个分片加载并丰富文档,如果有需要的话,接着返回文档给协调节点。一旦所有的文档都被取回了,协调节点返回结果给客户端
搜索的时候是会查询Filesystem Cache的,但是有部分数据还在Memory Buffer,所以搜索是近实时的。
倒排查询
分词产生多个term,然后在.tip文件中查找对应field的FST(Finite State Transducer)
根据FST查找到的信息去.tim文件中查找具体的term信息TermStats,TermMetadata
从TermStats中拿到当前term的DF值(即出现了该term的文档数量)
从TermMetadata中拿到对应的指向.doc中的跳跃表,docIdList的指针,指向.pos .pay的指针等
聚合
metric
avg/sum/min/max/stats
统计聚合查询
percentiles
数值以内的所占百分比
extend_stats
扩展统计聚合查询
cardinality
去重计数查询
bucket
range
范围统计查询
histogram
直方图聚合查询
terms
基于索引内字段值动态聚合查询
pipeline
parent
结果内嵌到现有的聚合分析结果中
sibling
结果与现有聚合分析结果同级
FAQ
索引分片数的设计和扩容
分片数一般根据节点数设置
索引分片数初始化后不能修改,扩容的话需要通过reindex进行索引重建
相同索引别名的物理索引有 一致的Mapping和数据结构,以提升检索效率
reindex性能优化
批量大小值可能太小。需要结合堆内存、线程池调整大小好的起点是每批处理5-15 MB,默认一批处理1000条
借助scroll的slices提升写入效率针对单索引,slices大小=分片数;针对多索引,slices=分片的最小值
目标索引副本数设置为0
目标索引增加refresh间隔
性能优化
不需要评分,字段的norms设置为false
不要默认string类型映射,会同时生成text和keyword类型,浪费空间
动态索引基于模板+时间+rollover api 滚动创建索引,冷热数据分离,定期forcemerge和shrink压缩操作
java heap通常设置为32G以下,否则Zero-Based Compressed Ordinary Object Pointers (oops)不会被启用,将会导致更多的内存消耗
关闭不需要字段的doc values
关闭不需要查询字段的_source功能,不将此存储在ES中以节省磁盘空间
关于排序:我们增加一个long字段,它用于存储时间和ID的组合(通过移位即可),正排与倒排性能相差不明显
尽量使用keyword替代一些long或者int之类,term查询总比range查询好,主要是采用了KD-Tree
关于CPU消耗,检索时如果需要做排序则需要字段对比,消耗CPU比较大,如果有可能尽量分配16cores以上的CPU,具体看业务压力
关于合并被标记删除的记录,设置为0表示在合并时一定删除被标记记录,默认应大于10%才删除:"merge.policy.expunge_deletes_allowed":"0"
数据量级达到TB+甚至更高之后,wildcard在多字段组合的情况下很容易出现卡死
方案一:针对精确度要求高的方案:两套分词器结合,standard和ik结合,使用match_phrase检索。
方案二:针对精确度要求不高的替代方案:建议ik分词,通过match_phrase和slop结合查询
禁用swapping,设置bootstrap.memory_lock:true,锁定内存
fielddata内存大小默认没有限制,可能导致频繁的OOM。建议修改配置项indices.fielddata.cache.size: 10%控制大小,避免堆内存不够GC压力过大
index.merge.scheduler.max_thread_count配置用于segments merge的最大线程数目,如果只有一块硬盘且非SSD,则应该设置为1,因为旋转存储介质每次需要寻址,无法实现并发写,多个线程导致竞争,写入速度更慢
预热文件系统缓存,index.store.preload设置,指定将哪些扩展名的文件加载到内存中
开启ARS,利用自适应副本选择机制,智能的选择将请求转发给负载较低的分片所在节点
关于段合并,合并在后台定期执行,比较大的segment需要很长时间才能完成,为了减少对其他操作的影响,elasticsearch进行阈值限制,默认是20MB/s,可配置参数:"indices.store.throttle.max_bytes_per_sec" : "200mb"(根据磁盘性能调整),合并线程数默认是:Math.max(1, Math.min(4, Runtime.getRuntime().availableProcessors()/2)),若是机械磁盘,可设置为1:index.merge.scheduler.max_thread_count: 1,在我们的案例中使用SSD,配置了6个合并线程
使用游标查询,scroll context超过限制
增加scroll context的配置数量,这个消耗内存,根据机器配置设置一个合理值,一个数据分片会占用一个context
游标查询结束后及时清理,释放context,避免并发大时context超出最大限制
索引分片数限制
分片有最大数的限制,默认是单个节点有1000个分片,总共允许的分片数=单节点最大分片数*节点数
查询的短语数限制,默认值的1024,如果bool查询短语超过限制会报错
绝大部分堆内存主要被 FST( Finite State Transducer )占用了
慢查询模板
PUT /_template/{TEMPLATE_NAME}
{
"template":"{INDEX_PATTERN}",
"settings" : {
"index.indexing.slowlog.level": "INFO",
"index.indexing.slowlog.threshold.index.warn": "10s",
"index.indexing.slowlog.threshold.index.info": "5s",
"index.indexing.slowlog.threshold.index.debug": "2s",
"index.indexing.slowlog.threshold.index.trace": "500ms",
"index.indexing.slowlog.source": "1000",
"index.search.slowlog.level": "INFO",
"index.search.slowlog.threshold.query.warn": "10s",
"index.search.slowlog.threshold.query.info": "5s",
"index.search.slowlog.threshold.query.debug": "2s",
"index.search.slowlog.threshold.query.trace": "500ms",
"index.search.slowlog.threshold.fetch.warn": "1s",
"index.search.slowlog.threshold.fetch.info": "800ms",
"index.search.slowlog.threshold.fetch.debug": "500ms",
"index.search.slowlog.threshold.fetch.trace": "200ms"
},
"version" : 1
}
高阶API
查询API-RestHighLevelClient.search()
SearchRequest
source
SearchSourceBuilder
query
AbstractQueryBuilder
使用QueryBuilders创建
aggregation
ValuesSourceAggregationBuilder
使用AggregationBuilders创建
from
size
scroll
SearchScrollRequest
scroll
ClearScrollRequest
SearchResponse
创建索引API-RestHighLevelClient.indices().create()
CreateIndexRequest
删除索引API-RestHighLevelClient.indices().delete()
DeleteIndexRequest
新增或更新文档API-RestHighLevelClient.index()
IndexRequest
删除文档API-RestHighLevelClient.delete()
DeleteRequest
批量操作文档API-RestHighLevelClient.bulk()
BulkRequest
插件
开发
自定义rest接口服务
ActionPlugin
BaseRestHandler
自定义pipeline processor
IngestPlugin
AbstractProcessor
maven依赖包引入
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>${elasticsearch.version}</version>
<scope>provided</scope>
</dependency>
第三方插件
opendistro_sql
基于sql查询数据
SELECT [ COUNT | AVG | SUM | MIN | MAX | STATS | EXTENDED_STATS ]
FROM INDEX_NAME
GROUP BY [DATE_HISTOGRAM | RANGE | DATE_RANGE | TERMS ]
语法限制
1、where语句不支持数学运算表达式
2、不支持子查询里有GROUP BY or ORDER BY
3、join只支持两个索引进行join操作,join的索引必须使用别名
4、join 的on条件参数只支持and拼接
5、不支持对join的结果做聚合,join不支持group by
6、只支持基本查询的分页,不支持join查询的分页
7、支持指定分片语法 SELECT /*! ROUTINGS(DT) */ * from book-index
扩展sql样例
select * from workitem group by range(age, 20,25,30,35,40) //基于区间范围做桶聚合
select * from workitem group by date_histogram('field'='insert_time','interval'='4d','alias'='days') //基于时间直方图做桶聚合
select * from workitem group by date_range(field='insert_time','format'='yyyy-MM-dd' ,'2014-08-18','2014-08-17','now-8d','now-7d','now-6d','now') //基于时间范围做桶聚合
select * from workitem group by terms('field'='user') //基于字段值做桶聚合
SELECT * FROM account where match_phrase(gender, 'F')
SELECT * FROM account where age = TERM(4)
SELECT * FROM account where name = IN_TERMS(hattie,alis)
SELECT * from workitem where user= wildcardQuery('*1024*')
SELECT * FROM dog where dog_name = REGEXP_QUERY('sn.*', 'INTERSECTION|COMPLEMENT|EMPTY', 10000)
SELECT address FROM bank where q=query('address:880 Holmes Lane')
SELECT * FROM account where _id = IDS_QUERY(account,1,2,5)
0 条评论
下一页