Elasticsearch 7.11.X 笔记
1.1 新部署启动前需设置部分属性参数如文件句柄数进程数等,可通过启动日志WARN字段进行对应修改。
设计优势:
1.采用补充索引以及分段思路解决倒排索引不变性导致的改变的多次IO以及索引重建的消耗;
2.删除操作采用逻辑删除。采用合并机制解决索引积压多以及逻辑删除。
3.准实时原因:主分片延时+副本并行写入延时,需从性能与数据安全角度考虑延时思路
4.通过Translog 进行双写缓冲设计,与Mysql不同的是先入内存再入log,原因是入内存计算复杂,出错的可能性较大,避免log记录出错记录消耗资源。
5.Disk与ES内存中间设计OSCache,将缓存进行二次缓存,提高实时性。
水平扩容:
数据重分配原则:
1.主分片及副本不同机;
2.平衡优先。
3.数据重分配采用Allocation Decider组件进行以下是相关参数:
cluster.routing.allocation.enable: 控制分配器是否允许分配。
cluster.routing.allocation.cluster_concurrent_rebalance: 控制集群并发重分配的分片数。
cluster.routing.allocation.node_concurrent_recoveries: 控制每个节点并发恢复(数据移动)的分片数。
cluster.routing.allocation.node_initial_primaries_recoveries: 控制初始化恢复过程中的主分片并发恢复数。
cluster.routing.allocation.balance.shard: 控制分片平衡的权重。
cluster.routing.allocation.balance.index: 控制索引平衡的权重。
cluster.routing.allocation.balance.threshold: 控制平衡阈值。
故障处理
1.选举算法
ES会在集群中选取一个节点成为主节点,只有Master节点有资格维护全局的集群状态,在有节点加入或者退出集群的时候,它会重新分配分片,并将集群最新状态发送给集群中其它节点,主节点会以周期性ping的方式以验证其它节点是否存活。Elasticsearch的选举算法基于Bully选举算法,简单的说,在bully算法中,每个节点都有一个编号,只有编号最大的存活节点才能成为master节点。
- 选举时间点
选举的时间点有两个
某个新节点加入了集群或者某个节点从宕机中恢复
集群中的某个节点检测到leader崩溃 - 选举流程
节点node向所有比自己大的节点发送选举消息(选举为election消息)
如果节点node得不到任何回复(回复为alive消息),那么节点node成为master,并向所有的其它节点宣布自己是master(宣布为Victory消息)
如果node得到了任何回复,node节点就一定不是master,同时等待Victory消息,如果等待Victory超时那么重新发起选举
3.Elasticsearch编号比较的判断依据有两个,首先是ClusterState版本号的比较,版本号越大优先级越高,然后是节点id的比较,id越小优先级越高。ClusterState是Master向集群中各个节点发送的集群状态,这个状态有一个版本号码,如果集群状态发生了变化,比如集群新增了节点成员或者有节点成员退出了,那么这个版本号就会加一,比对这个版本号的目的是让拥有最新状态的节点成为Master的优先级最高。
问题:
1.Master假死。解决思路是通知其余成员通报Master状态,如过半鉴定存活即等待,避免重新选举。
2.脑裂可能,通过参数discovery.zen.minimum_master_nodes 调整数量为过半节点数量。
数据保存及查询设计
1.保存数据需保存至主分片,因此需要进行路由,其路由算法是通过hash(id)%分片数
2.查询路由因有副本,获取主分片及所有副本的机子进行查询负载均衡算法为轮询算法
3.路径:生产者——》任一节点——》转发至协调节点进行路由计算——》转发至对应主分片节点——》主分片节点保存后通知其余副本节点进行保存—》一路回馈至生产者
4.查询者——》任一节点——》计算分片及副本位置——》轮询计算路由——》选择查询区域——》回馈
5.存储参数:consistency参数:all 全保存成功确保强一致性 one只需主分片保存成功确保高可用 quorm过半成功
ES操作
ES严格遵守RESTFul规范设计接口
1.构建客户端
JAVA | SpringData | 备注 |
---|---|---|
RestHighLevelClient(RestClient.builder) | RestHighLevelClient(RestClient.builder) | SpringData需通过ESTemplate注解注入使用 |
2.索引模块
功能 | 方式 | 参数 | URL | API实现 |
---|---|---|---|---|
创建索引 | PUT | {“settings”:{“number_of_shards”:3,“number_of_replicas”:1}} | ${ES_URL}/${indexName} | CreateIndexResponse=RestHighLevelClient#indices#create(CreateIndexRequest(${indexname},RequestOptions.DEFAULT)) |
查询 | GET | URL传参 | ${ES_URL}/${indexName} | GetIndexResponse=RestHighLevelClient#indices#get(GetIndexRequest(${indexname},RequestOptions.DEFAULT)) |
查询所有索引 | GET | Url传参 | ${ES_URL}/_cat/indices? | 未研究,具体参数细节待研究 |
删除索引库 | DELETE | Url传参 | ${ES_URL}/${indexName} | AcknowledgedIndexResponse=RestHighLevelClient#indices#delete(DeleteIndexRequest(${indexname},RequestOptions.DEFAULT)) |
3.文档模块
功能 | 方式 | 参数 | URL | API实现 | 批量操作 | 备注 |
---|---|---|---|---|---|---|
添加 | POST | {${Field}:${INFO},${Field}:${INFO}} | ${ES_URL}/${indexName}/_doc/${id} | IndexRequest(${indexname}).id(${id}).source(ObjectMapper#writeValueAsString(${data}),XContentType.JSON)IndexResponse=RestHighLevelClient#Index(IndexRequest,RequestOptions.DEFAULT) | BulkRequest()#add(IndexRequest[])BulkResponse=RestHighLevelClient#bulk(BulkRequest,RequestOptions.DEFAULT) | _doc后衔接为Id值,如不衔接则自动生成 |
主键查询 | GET | URL传参 | ${ES_URL}/${indexName}/_doc/${id} | GetRequest(${indexname}).id(${id})GetResponse=RestHighLevelClient#get(GetRequest,RequestOptions.DEFAULT) | ||
全量查询 | GET | URL传参 | ${ES_URL}/${indexName}/_search | SearchRequest.indices(${indexname})SearchSourceBuilder.query(QueryBuilders.matchAllQuery) SearchResponse=RestHighLevelClient#search(SearchRequest,RequestOptions.DEFAULT) |
3.条件查询:
(1)URL传参查询:GET请求方式 `${ES_URL}/${indexName}/_search?q=${field}:newinfo`
(2)请求体传参:GET请求方式 `${ES_URL}/${indexName}/_search` 数据格式于请求体 JSON格式为:
{
"query": {
"match${method}" :{
"${field}": "${newInfo}"
}
},
"from":${startNum},
"size":${size},
"_source":[*]
"sort":{
${field}:{
"order":asc/desc
}
},
"highlight":{
"fields":{
${field}:{}
}
}
}
注:${method}=_all->全量查询,[字段选择] ,${method}=_phrase->全匹配不采用分词,highlight设置高亮
(3)条件查询:GET请求方式${ES_URL}/${indexName}/_search 数据格式于请求体 JSON格式为:
{
"query": {
"bool":{
"must/should":[
"match" :{
"${field}": "${newInfo}"
}
],
"filter":{
"range":{
${field}:{
"gt/lt":${number}
}
}
}
}
},
"from":${startNum},
"size":${size},
"_source":[*]
"sort":{
${field}:{
"order":asc/desc
}
}
}
注:bool:{} 条件查询 must:[] AND should:[] OR
(4)聚合操作:GET请求方式${ES_URL}/${indexName}/_search 数据格式于请求体 JSON格式为:
{
"aggs":{
${aggsName}:{
"terms(count)/avg(avg)""{
"field":${field}
}
}
},
"size":0//取消原始数据
}
SearchRequest.indices(${indexname})
QueryBuilders.termQuery()//字段查询
HightLightQueryBuilder.hightLight().preTages().postTags().field;//高亮查询
QueryBuilders.BoolQuery//条件查询 内部must等方法 QueryBuilder.matchQuery()
QueryBuilder.RangeQuery(${field})//范围查询
QueryBuilder.fuzzyQuery(${field},"").fuzziness()//模糊查询 及误差范围
SearchSourceBuilder.query().from().size().sort(${field},asc/desc).fetchSource();//分页,排序,过滤字段
SearchResponse=RestHighLevelClient#search(SearchRequest,RequestOptions.DEFAULT)
AggregationBuilders.${METHOD}.field(${field})//聚合查询
AggregationBuilders.terms()//分组
更新操作:
1.全量修改:PUT 请求方式 ${ES_URL}/${indexName}/_doc/${id} 数据存储于请求体JSON格式
2.局部修改:POST 请求方式 ${ES_URL}/${indexName}/_update/${id} 数据格式于请求体 JSON格式为 { "doc" :{"${field}": "${newInfo}" } }
API:
UpdateRequest(${indexname}).id(${id}).doc(XContentType.JSON,${field},${newInfo})
UpdateResponse=RestHighLevelClient#update(UpdateRequest,RequestOptions.DEFAULT)
备注:通过MVCC机制进行并发解决(携带,if_seq_no && if_primary_term)
3.删除:DELETE 请求方式 ${ES_URL}/${indexName}/_doc/${id}
DeleteRequest(${indexname}).id(${id})
DeleteResponse=RestHighLevelClient#delete(DeleteRequest,RequestOptions.DEFAULT)
BatchCreate:
BulkRequest()#add(DeleteRequest[])
BulkResponse=RestHighLevelClient#bulk(BulkRequest,RequestOptions.DEFAULT)
mappingDoc:
1. 设置字段结构 PUT 请求方式 ${ES_URL}/${indexName}/_mapping 数据存储于请求体JSON格式
{ "properties":{
${filed}:{
"type":"text/keyword",(text可分词查询keyword不可分词查询)
"index":"true/false"(是否可根据字段查询)
}
}
}
分词模块
GET 请求方式${ES_URL}/_analyze 分词
{"type":"",text:}
扩展词典
IK/config/custom.dic
IKAnalyzer.cfg.xml 配置 <entry key="ext_dict">custom.dic </entry>
自定义分词器:
{
"settings":{
"analysis":{
"char_filter":{ //后文中括号内容
"&_to_and":{
"type":"mapping",
"mapping":["&=>and"] //字符修改
}
}
},
"filter":{
"my_stopwords":{//后文中括号内容
"type":"stop",
"stopwords":["",""] //过滤词汇
}
},
"analyzer":{
"${analyzerName}":{
type:"custom",//自定义 custom
char_filter:["html_strip","&_to_and"],
tokenizer:"standard",//标准
filter:["lowercase","my_stopwords"]
}
}
}
}
KIBANA集成配置
配置文件:kibana.yml
server.port:对外暴露端口
elasticsearch.hosts:["http://localhost:9200"] //ES服务器地址
kibana.index:索引名
i18.locale:"zh-CN"
集成框架SpringData
1.配置 AbstractElasticserachConfiguration 继承子类 返回JAVA API一致的客户端类
2.Dao层继承ElasticserachRepository接口
3.索引entity @Document @Id @Field
4.字段搜索
QueryBuilders.termQuery()//字段查询
HightLightQueryBuilder.hightLight().preTages().postTags().field;//高亮查询
QueryBuilders.BoolQuery//条件查询 内部must等方法 QueryBuilder.matchQuery()
QueryBuilder.RangeQuery(${field})//范围查询
QueryBuilder.fuzzyQuery(${field},"").fuzziness()//模糊查询 及误差范围
ES优化部分:
1.1.使用SSD
1.2使用RAID硬盘阵列
1.3多硬盘多path.data
2.1多分片降低匹配度消耗资源
2.2 分片不超过最大JVM设置
2.3 分片不超过节点数3倍
2.4 节点数>=主分片数(副本+1)
3.1推迟分片分配 避免出现瞬时中断导致的无效重分配行为 /_all/_settings { settings:{index.unassigned.node_left.delayed_timeout:5m}}
4.1 路由计算
1.无ID查询 先分发再聚合
2.有ID可分片查询
5.1 加大TranslogFlush 降低Iops、Writeblock。 index.translog.flush_threshold_size
5.2增加IndexRefresh 减少 SegmentMerge 次数
5.3 调整Bulk线程池队列
6.1 Bulk批量插入
6.2大批量数量写如今 先关闭副本 写入完成后修改副本 index.numbers_of_replcate
7.1 JVM 内存不超过50% 尽量不超过32G
8.1
transport.tcp.compress 压缩传输数据
discovery.zen.minimum_master_nodes 最小候选Master节点 默认可能出现脑裂
评分机制
9.1 查询评分详情:GET请求方式 ${ES_URL}/${indexName}/_search?explain=true
数据格式于请求体 JSON格式为:
{
"query": {
"match${method}" :{
"${field}": "${newInfo}"
}
}
9.1.2 评分公式 score=boosttfidf
9.2 TF公式 :词频,词条在文本中出现次数
tf=freq/(freq+k1*(1-b+b * dl/avgdl))=freq/(freq+1.2*(1-0.75+0.75*dl/avgdl))
freq:关键词在当前文档中出现次数
k1:默认 1.2
b:默认0.75
dl:分词个数
avgdl:总字段数/文档数
9.3 IDF公式:逆文档频率,词条在所有文档中出现多少次,出现的越多越不相关得分比较底。(普遍性越高越低分)
idf=log(1+(N-n+0.5)/(n+0.5))
n:关键词在所有文档出现总数(${newInfo})
N:字段在所有文档出现的文档数量(${field})
9.4 boost:权重值默认2.2
-修改权重 ${“query”:“newInfo”,“boost”:“boostNum”}
10 8.xAPI变动
10.1 需要处理证书
10.2 ClientConnect:
10.2.1
CredentialsProvider credentialsProvider=new BasicCredentialsProvider()
=》CredentialsProvider.setCredentials(AuthScope.ANY,new UsernamePasswordCreedentials("ESUSERNAME","USERPASSWORD"))
=》Path credentialsProviderPath=Paths.get("证书路径")
=》CertificateFactory factory= CertificateFactory.getInstance(证书算法);
=》Certificate certificate =factory.generateCertificate(Files.newInputStream(credentialsProviderPath=Paths.get));
=》KeyStore trustStore=KeyStore.getInstance(证书算法)
=》trustStore.load
=》trustStore.setCertificateEntry("ca",certificate );
=》SSLContextBuilder sslContextBuilder =SSLContexts.custom().loadTrustMaterial(trustStore);
=》SSLContext sslContext=sslContextBuilder.build();
=》证书装载结束
=》RestClientBuilder builder=RestClient.builder(new HttpHost(hostName,port,"https")).setHTTPClientConfigCallback( HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpAsyncClientBuilder ){return httpAsyncClientBuilder.setSSLContext(sslContext).setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE).setDefaultCredentialsProvider( credentialsProvider) })
=》RestClient restClient=builder.build();
=》ElasticsearchTransport tp=new RestClientTransport(restClient,new JacksonJsonpMapper())
=》ElasticsearchClient=new ElasticsearchClient(tp)
10.3 增查删 INDEX
10.3.1 获取针对索引客户端
=》ElasticsearchIndicesClient=client.indices();
=》各类Request转为构建器模式,不细写
10.4 增改删 DOCUMENT
10.4.1 普通客户端
=》各类Request转为构建器模式,不细写 Entity需实现序列化
=》bulkRequest.operations(List) 批量操作
=》Operation.Builder .build() 批量操作的Entity构建
10.5 查 Document
10.5.1 普通客户端
=》查询条件在构建器链中处理
=》如 Query query=new Query.Builder().match(new MatchQuery.Builder().field().query().build()).build();
10.6 异步客户端
10.6.1 XXX.thenApply() 后续处理
10.6.2 XXX.whenComplete() 回调方法
11 EQL
11.1 地址 GET ${ES_URL}/${indexName}/_eql/search
11.2 EQL是基于事件机制
11.3 EQL 搜索必须拥有 @timestamp event:{category:"${info}"} 两个字段
query : any where XXX==XX (any 时间无关)
query: sequence by XXX [${category} where zzz==yyy] sequence 统计XXX字段相同并将字段相同的统计在一起
12 SQL
12.1 POST ${ES_URL}/_sql?format=${type}
{"query":"""${SQL} """,
${DSL}
}
type:
1.txt:文本格式与命令行查询MySql显示相似
2.csv:逗号分隔数据
3.json:JSON格式
4.tsv:tab分割数据
5.yaml:yaml格式
SQL:与MySql语法风格相似 举特殊例子
1.类型转换 "info"::type 类似 CAST(INFO AS TYPE)
2.RLike: 采用正则
3.first():第一个
4.last():最后一个
5.kuriosis():量化峰值分布
6MAD()
DSL:可与DSL组合使用
.../_sql/translate =>修改为DSL风格
cursor: json风格 存在cursor游标. 在下次查询的时候使用将获取到下一个元素 使用完成后需关闭
{"cursor":"${cursor}"}
12.2 可通过DataGrid 操作图形化界面(注意版本是否支持)
13 NLP对接
13.1下载对应插件"elasticsearch-ingest-opennlp" 该插件需版本一致
13.2 elasticsearch.yml配置模型
1.ingest.opennlp.model.file.XX:XX.bin
2.ingest.opennlp.model.file.YY:YY.bin
3.ingest.opennlp.model.file.ZZ:ZZ.bin
...
13.3 创建支持NLP的预处理管道
13.3.1 PUT ${ES_URL}/pipeline/${pipelineName} { "description":"XXXx","processors":[{ "opennlp":{"filed":"
${field}"} }]}
13.3.2 新增数据使用指定管道 PUT ${ES_URL}/${indexName}/_doc/${id}?pipeline=${pipelineName} {XXXXXXX}