ElaticSearch学习笔记

ElaticSearch:分布式开源搜索和分析引擎

ES简介:

近实时存储、检索数据,集群可达百台,可处理PB级的数据,使用java并使用lucene做为基础,使用restAPI的形式来简化lucene的复杂.

功能:

分布式搜索引擎;全文检索;数据分析引擎(分组聚合);对海量数据进行实时更新;

特点:

安装方便;JSON格式;RestAPI操作;分布式,加入节点自动均衡;多租户,不同用户可建立不同索引;实时处理PB级数据;

使用场景:

搜索类:大网站搜索;
日志分析:ELK组合,ES、logstash、Kibana,日志存储分析;
数据预警平台和数据分析场景:电商类网站的价格机制、热点数据的嗅探
商业BI系统:大型销售系统的数据的分析与展示.

案例:

各种百科,全文检索
stack overflow:全文检索
git hub:管理那么多代码
ELK日志分析系统:很成熟的日志框架

与主流搜索进行对比:

lucene:一个jar包型得框架
solr也是基于lucene开发的http接口的查询服务器,用zookeeper做分布式的管理;官方提供的功能完整;
ES更专注于核心的功能-搜索,其他一些功能都由第三方提供,而且ES自带分布式管理功能,无需zookeeper等注册中心.
在传统搜索中Solr更合适,实时搜索的话ES更胜一筹;
在选型方面,ES还是更被推荐.
ES版本介绍:
主流版本为5、6、7;
7.x版本的变化:
	TransportClinet被弃用,使用新的restClient,实现为high-level rest Client
	数据存储结构变化:简化了Type,索引不再有类型之分,6中规定索引只能有一个类型,7中将类型统一边成了_doc型,8可能会彻底删除索引的type,随之带来的API请求将会受到影响:get index/_doc/id,这其中的_doc原来是索引类型,现在就是固定了
	7之后默认打包了JDK,不用单独安装JDK了.
	默认节点为主机名,默认分片数为1
	底层的lucene升级为lucene,在查询品种算法上进行了优化, top N的查询
	间隔查询,对intervals query允许在查询时进行精确控制查询词在文档中出现的先后关系,实现了对terms顺序、terms之间的距离以及他们之间的包含关系灵活控制;
	引入了新的集群协调子系统,删除minimum_master_nodes参数,ES可以选择仲裁的节点
	不再会有OOM的情况,JVM有了新的熔断机制,查询或聚合的数据量超出单机处理最大内存限制会被熔断,indices.breaker.fielddata.limit默认从60%降低到40%
	分片搜索空闲时间挑过refresh刷新,原来是每秒都要refresh
单节点部署流程:
7.3不支持CentOS 8,7是兼容性比较好的;
官方下载ES,解压安装;
https://www.elastic.co/cn/elasticsearch/ ES官网
ES不使用root启动,所以服务器如果自带了JDK,那么环境变量是针对root用户的,所以要注意一下,手动安装一下就可避免这个问题;
安装JDK后配置环境变量;
配置ES中的config的elasticsearch.yml
	node.name: node1
	network.host
	http.port: 9200
	cluster.initial_master_nodes: [node1]
配置config的jvm.options的jvm参数,服务器不行,改小点 512MB 不能再小了;
添加es专用账户;
给es目录授权给新建账户;
修改linux系统配置 /etc/sysctl.conf,添加 vm.max.map_count=655360,sysctl -p生效;
修改/etc/security/limit.conf,添加
	soft nofile 65536
	hard nofile 65536
	soft nproc  4096
	hard nproc 4096
切换到新建账户
运行bin下的执行文件;
ES入门:
索引:
	一个索引代表一个库
类型type:
	类似于表的概念,7.x只有doc后期就会没
映射mapping:
	类似与表结构的概念,对数据的约束;
API:
REST风格;
客户端API: java high level rest client
图形化插件:
kibana来管理ES,图形化,基于node.js的.
安装流程:
把kibana的权限授权给新建用户
设置权限给kibana目录
修改配置文件:kibana.yml
	server.port:5601
	server.host:
	es.host:
启动kibana 可用root 加--allow-root
Kibana和IK分词器的集成
IK3.0 60万/秒处理能力,多子处理器,个人词条优化存储,支持拓展词典,优化查询分析器;
安装流程:
	下载IK
插件安装流程:
	在plugins新建ik的目录,然后解压进去,重启es和kibana
分词模式:ik_max_word和smart模式,详细解析和简单模式
拓展词库添加:
	在es目录/config/analysis-ik/中添加dic字典库
	配置ik的配置文件ikanalyzer.cfg.xml
停用词库添加:
	在es目录/config/analysis-ik/中添加停词dic字典库
	配置ik的配置文件ikanalyzer.cfg.xml
同义词词典:
	在es目录/config/analysis-ik/中创建同义词词典dic
	格式为:liuzhiwei,刘治炜  表示这两个词是相同含义;
索引基本操作:
操作都是一次http请求
PUT /indexName 添加
HEAD /indexName  检查
GET /indexName,... 查找  _all全部索引  _cat/indices?v 健康状态
POST /indexName/_close 关闭索引
POST /indexName/_open 开启索引
DELETE /indexName,... 删除索引
映射操作:
添加约束,对字段的类型和其他属性进行设置;
index 是否索引;
store 是否存储;
analyzer 指定分词器;
映射关系查看: GET /indexName/_mapping
查看所有映射: GET _mapping、GET _all/_mapping
添加索引同时添加mapping
	PUT /indexName
	{
		"settings" :{},
		"mappings":{file约束}
	}
文档的操作:
POST /index/_doc/{id} id不写就是自动生成
{
	json数据
}
GET /index/_doc/{id} 查看文档
GET /index/_search
{
	"query":{
		查询条件,如:
		"match_all":{}
	}
}
GET /index/_doc/{id}?_source 查看并设置返回结果
PUT /index/_doc/{id}
{
	修改的json数据,全量更新,不写别的值会被干掉;
}
POST /index/_update/{id}
{
	"doc":{
		json数据,增量更新不会干掉没更新的字段
	}
}
DELETE /index/_doc/{id} 删除文档
DELETE /index/_delete_by_query
{
	"query":{
		条件
		"match_all":{=全删}
	}
}
PUT /index/_doc/{id}/_create {json} 强制创建 如果ID存在,那么报错
PUT /index/?refresh=true 增加文档后立即刷新索引,对新文档进行分词啦

ES高级

地理坐标点
和redis的geohash还有mongo的geo差不多;
表达坐标的三种形式:
	字符串:"location":"纬度,经度";
	属性格式:"lat":纬度, "lon":经度
	数组形式:"location":[经度,纬度]
坐标过滤器:
	geo_bounding_box:方框中的点
	geo_distance:指定位置指定距离的圆形内覆盖的点;
	geo_distance_range两个同心圆的边距距离
过滤器的使用:
	json在query中添加filter对象
动态映射
针对于mapping初始化未设置的字段处理
mapping的dynamic属性:
	true:动态处理
	false:忽略
	strict:报错
自定义动态映射:
日期检测的问题:mappings中date_detection属性设置为false,表示value不做日期检测,不把它转换为日期类型;
日期格式检测:mappings中dynamic_date_formats:"时间格式",只要符合设置的格式,那么才转为日期格式;
动态模板:
dynamic_templates属性来控制,
根据match规则设置哪些字段,设置分词器、字段属性等mapping属性

DSL:

查询的基础语法:
	query:{
		查询的类型:match、match_all
	}
全文查询的语法:
	query:{
		match:{
			字段:{
				query:"value"
				operator:"逻辑关系 and 或者 or,基础查询默认给的是or"
			}
		}
	}
短语查询语法:
	query:{
		match_phrase:{
			字段:{
				query:"value",
				slop:"跨度(中间最大间隔多少个单词,至少为1)"
			}
		}
	}
Query_String查询语法:
	query:{
		query_string:{ 不指定字段,那就所有字段查询,
			query:"value" 可逻辑查询和模糊查询,
			default_field:"设置默认字段,等同于普通查询了",
			fields:[设置查询的多个字段]
		}
	}
multi match查询多字段搜索:
	与query_String的多字段一样,支持字段模糊匹配

词条级搜索:

精确的搜索
词条搜索基础语法:
	query:{
		term:{
			字段:value
		}
	}
词条集合搜索:
	query:{
		terms:{
			字段:[value1,value2,...]
		}
	}
范围查询:
	query:{
		range:{
			字段:{
				"gte" : value, 为>=
				"lte" : value 为<=
				"gt" : 为 >
				"lt" : 为 <
				boots: 1.0 查询权重 
			}
		}
	}
不为null的查询:
	query:{
		exists:{
			指定字段是否存在
			field:"字段名"
		}
	}
前缀查询:
	query:{
		prefix:{
			字段:"value"
		}
	}
模糊查询:
	query:{
		wildcard:{
			字段:"可使用通配符的value, 区分大小写",也可写成对象型,字段再被设置为一个对象
		}
	};
	query:{
		fuzzy:{
			字段:{
				value:
				boots:
				fuzziness: 允许模糊字符的数量,纠错数量,中文可能就是字儿
			}
		}
	}
正则搜索:
	注意使用,正则较为复杂会影响性能
	query:{
		regexp:{
			字段:"正则表达式"
		}
	}
ids查询:
	query:{
		ids:{
			type:"_doc" 后期取消,可不写
			values: [value1,value2]
		}
	}
复合查询:
评分相同查询:
	query:{
		constant_score:{
			filter:{真正的查询,filter不会产生分数,所以才会有相同评分},
			boots:"设置的分数"
		}
	}
布尔查询:
	query:{
		must:{必须满足的条件},
		filter:{必须满足的条件,无评分},
		should:{or的条件},
		minimum_should_match:should最少满足条件的数量
		must_not:{必须不满足的条件}
	}
排序:
默认按文档相关性得分进行排序,默认降序排序
设置排序规则:
	sort:{
		_score:{
			order:asc/desc
		}
	}
分页:
from:"从哪开始",
size:"每次取多少条"
高亮:
与match的字段绑定,match哪些字段才会高亮哪些字段,可使用query_string的查询就可多个字段高亮
highlight:{
	pre_tags:开始标签
	post_tags:结束标签
	fields:[{字段:{属性},...}]
}
文档批量操作:
_mget 多索引组合查询 
	_docs :[ 索引1:{字段:value},索引2:{字段:value}]
_bulk 批量增删改 
	{"动作" :{_index:索引, _id:value}}
Fileter过滤器:
不会计算相关度得分,会缓存的内存中,相同查询再次查时就会非常快;
一种特殊的查询;
查询语法检测:
	GET /index/_validate/query?explain{
		可能出现错误的查询
	}
聚合分析:
	聚合:metric
	聚合+group by:分桶 bucketing
	聚合方法语法:
		aggs:{
			聚合命名:{
				max/min/sum/avg:{
					field:字段name
				}
			}
		}
	查询条数:
		1:GET /index/_count{ 条件 }
		2:value_count:{
			field:字段name
		}
	去重:
		cardinality
	全部聚合展示:
		count、max、min、avg、sum
		stats:{
			field:字段name
		}
	高级全部聚合展示:
		平方差等,比普通全部展示多了四个
		extended_stats:{
			field:字段name
		}
	百分比统计:
		字段值在最大值中的位置百分比
		percentiles:{
			field:字段name
		}
	指定百分比显示:
		percentiles:{
			field:字段name,
			percents:[百分比]
		}
	分组+聚合:
		aggs:
		{
			分组的语句,
			aggs:{
				分组后的聚合语句
			}
		}
	ES的having效果:
		aggs:
		{
			分组的语句,
			aggs:{
				分组后的聚合语句
				having:{
					bucket_selector:{
						buckets_path:{
							parName:对应的聚合名称
						},
						script:{
							"source":"条件语句,例如params.parName = 1,params必填"
						}
					}
				}
			}
		}
ES零停机索引重建:
方案1:外部数据导入
MQ发送消息;
消费者消费消息 重新导入ES索引
从DB获取数据 并发送给MQ
另外消费者从MQ获取信息 存入到ES中
特点:
	批次可控、并发效率高
缺点:
	DB压力高、带宽占用较多、重建时间长
方案2:scroll+bulk+索引别名
	利用ES自带工具功能,利用java客户端做scroll查询、bulk命令封装;不依赖DB
	java客户端使用别名来指向索引;
	新建索引,设置settings
	使用scroll api 批量查询数据
	滚动查询 
	GET /index/_search?scroll=1m 会返回一个scroll ID
	用 bulk api将scorll的数据插入到新索引中
	GET /index/_search/scroll{
		"scroll":1m,
		"scroll_id":"返回的scroll_id"
		"size":"拿多少条"
	}
	就可一直拿取下一页的数据
	用 bulk api将scorll的数据插入到新索引中
	特点:不依赖DB,使用java客户端即可;
方案3:reindex API
	对scroll、bulk进行了封装,不需要java客户端了都
	POST _reindex{
		conflicts:"proceed" 忽略已存在文档的报错
		"source":{
			index:"index",
			可添加query:{}
			可添加sort:{}
		},
		"dest":{
			index:"new index"
			"version_type":
				"internal"覆盖操作
				"external":乐观锁更新操作,数据存在更新version,不会覆盖
			"op_type":
				create 如果文档ID已存在那么报错
		}
	} 记得要对新索引设置settings

智能搜索建议:

智能联想、补全、纠错等功能,也增加一些相同的相同意义的单词
Suggester API将输入的文本分解为token,然后去索引里查找相似的term. 根据使用场景,有四种不同实现:
	Term Suggester  单词的
	Phrase Suggester  短语的
	Completion Suggester
	Context Suggester 段落的
单词智能支持 Term Suggester:
	分词的URL POST _analyzer(使用默认simple分词器){
		text:[文本]
	}
	搜索建议:
	POST /index/_search{
		suggest:{
			selectName:{
				text:"input的text",
				term:{
					suggest_mode:
						missing错过,只有错误的才会被建议
						popular流行,将一些同义词或者更高词频的也给建议出来
						always一直,与流行一样了.原来是一直建议的意思;
					field:字段
				}
			}
		}
	}
	term的相似性是根据两个单词之间字符变动的数量来判断的,但中文相似性就无法使用这样的算法进行比较,中文较为复杂
Phrase Suggest 短语智能搜索:
	POST /index/_search{
		suggest:{
			selectName:{
				text:"input的text",
				phrase:{
					field:字段
					highlight:{
						高亮选项
						pre_tag:开始标签
						post_tag:结束标签
					}
				}
			}
		}
	}
Completion Suggest  实时查询:
应用于auto completion场景,用户每输入一个字符就会进行匹配查询并返回匹配项,用户如果输入过快可能会影响到后端响应速度;
不采用倒排索引的数据结构,将分词后的数据编码成FST和索引一起存放,如果open的索引,FST会被整体装载到内存,这样正排索引速度就会很快,但也仅仅只能正序查询了,智能建议同义词什么的,就木有了;
在创建索引时,就需要设置字段类型为completion:
	"mappings":{
		"properties":{
			"body":{
				"type":"completion"
			}
		}
	}
查询:
POST /indexname/_search/pretty
	"suggest":{
		"查询name":{
			"prefix":"查询词",
			"completion":{
				"field":"字段名称"
			}
		}
	}
针对于不同的分词器,会影响到该智能搜索的结果,所以要考虑好分词器的选择;
mappings其他可能影响搜索结果的配置:
	preserve_separators
	preserve_position_increments 
	这些模糊查询的配置 都会影响completion搜索的结果
场景选择:
	开始输入时,使用前缀completion查询,80%做到命中;
	输入结束,completion查询 无法查询到结果, 那么开始使用短语和单词查询来进行错误词和相似词的建议查询并返回;
	精准度由粗到精准为:
		粗Completion->phrase->term精准
	相关的一些指标:
		公式解释:
			查询到的相关文档为A
			查询到的不相关文档为B
			没有查询到的相关文档为C
			没有查询到的不相关文档为D
		召回率:检索到的相关文件 / 系统相关文件总数   R=A/ (A+C)
		准确率:检测到的相关文件/ 查询到的系统文件总数  P= A/ (A+B)
Context suggester 相关性查询:
	根据上下文相关性提供查询建议,但这个是不是得配啊? 有个专门的上下文配置或者在新增文档的时候就需要考虑这个上下文的问题? 类似于"猜你想搜"?

ES的 Java Client:

1:TransportClient ES 为传统客户端 8.0将删除
2:RestClient ,分为low level 和high level
使用流程:
	导入依赖包 elasticsearch-rest-high-level-client, groupId=org.elasticsearch.clinet
	排除 elasticserach,该包中ES版本可能较低(5.6.8), 单独再导入ES依赖
	导入依赖包 elasticsearch
	yml配置文件的编写:
		esconfigName:
			elasticsearch:
				hostlist: ip:9200
	配置类:
		创建bean,返回为RestHighLevelClient,解析hostlist,new RestHighLevelClient时需要使用;
	CreateIndexRequest("indexName") 创建索引,
	CreateIndexRequest.mapping(json数据)
	拼装JSON 可使用alibaba的fastJSON,还有很多Json拼接
	IndicesClient in = client.indices();
	CreateIndexResponse cir = indicesClinet.create();

ES索引库管理:

删除索引库:
	DeleteIndexRequest对象负责删除
	IndicesClient对象负责实例化客户端
	AcknowLedgedResponse对象接收客户端执行后的响应
添加文档:
	IndexRequest对象 初始化请求体Json
	IndexRequest.source(json数据);
	IndexResponse对象负责接收执行后的响应
查询文档:
	GetRequest对象负责去查询文档;
	GetRequest.source(json条件);
	client.get(GetRequest);
	GetResponse负责接收响应

API高级查询的代码实现:

SearchRequest对象负责query类查询;
SearchSourceBuilder对象添加条件数据
SearchSourceBuilder.query(QueryBuilders.查询类型)
SearchSourceBuilder.fetchSource(包含的数组,排除的数组);
SearchRequest.source(SearchSourceBuilder);
SearchResponse对象获取响应
SearchHits hits = SearchResponse.getHits();获取命中的结果对象

API高级查询的其他代码实现:

termQuery:
	SearchSourceBuilder.query(QueryBuilders.查询类型)改为termQuery(查询条件添加)
分页Query:
	SearchSourceBuilder.from(开始获取位置)
	SearchSourceBuilder.size(获取数量)
	SearchSourceBuilder.sort(排序语法
)

ES高可用:

node节点配置:
	node.master 是否可成为主节点
	node.data: 是否可存储数据
分片:
	索引可有多个分片,存储不同的数据,可分为主分片和复制分片,复制分片就是主分片的复制版本,不会与主分片在一个分区
副本:
	主分片的复制,可随时代替主分片;

分布式架构:

高扩展性、高可用性、实时性;
新节点无需过多配置即可被发现

分层结构:

贴图

gateway层:
	中间缓存类存储,保证故障可用的索引数据
Lucene支持层:
	lucene的底层支持
中间模组层:
	索引、查询、mapping、river
决策和脚本层:
	Zen负责节点的选举、发现、添加与健康检查;
	执行js、python等脚本
	第三方插件的集成
转换层:
	http协议为默认传输层
	Thrift协议、Memcached协议
	JMX组件
API层:
	rest api,基于netty框架
透明隐藏特性:
	隐藏分片的机制,减少大文件存储和IO;隐藏分片的副本可以快速上主,提供高可用;
	集群发现机制:
		自动发现新加入的节点,Zen的作用
	负载均衡:
		自动负载节点;
	扩容机制:
		垂直扩容:替换服务器
		水平扩容:新增节点
	主节点:
		master,负责创建索引和管理,他的健康程度影响分布式整体效率
	节点对等:
		每个节点都能接收请求并路由到相关节点

集群环境搭建:

单机伪集群:一个节点最低要保证1G的内存;
配置文件es.yml:
	cluster.name集群名称
	node.name节点名称
	node.master是否可称为master
	node.data是否存储数据
	path.data索引数据存放路径
	path.logs日志存放路径
	bootstrap.memory_lock:是否需要锁住物理内存,就是直接占上,不是不够了再申请
	network.host:地址
	http.port:端口默认9200
	transport.port:节点选举端口 默认9300
	discovery.seed_hosts:7.x之后的配置,写入候选主节点的设备地址,在开启服务后可以被选为主节点
	cluster.initial_master_nodes:初始化一个新的集群时需要该配置来选举master
	http.cors.enabled:是否支持跨域,在使用head插件时需要配置
	http.cors.allow-orgin "*" 表示支持所有域名
集群健康验证:
	http://host:port/_cat/health?v

集群工具head插件:

图形化集群管理工具,搜索接口可查询原始JSON,提供输入窗口调用Rest API
安装流程:
	基于node.js的,所以需要先安装node.js;
	设置软连接来达到环境变量的目的,ln -s /执行目录  /usr/local/bin/
	安装phantomjs
	下载后是 bz2的压缩包,我们要yum install -y bzip2
	tar -jxvf phantomjs
	配置环境变量:
		export PATH=$PATH:/phantomjs目录
	source生效一下
	npm安装一下grunt的相关工具
		贴文档
	git下载head
	在head目录下指定一下npm源为淘宝的npm源地址;
	启动:npm run start 

集群规划:

考虑方面:数据量规模、机器的配置
ES JVM heap 最大32G
大型服务器可跑多个ES实例
应用场景:
	业务搜索 几千万-十亿 2-4台节点
	ELK 需要的就多了
角色分配:
	协调节点,只负责路由的节点,不选举、不存数据
集群脑裂:
	旧版本过半机制来防止脑裂
	discovery.zen.minimum_master_nodes 来设置
	7.x 后更改了一些配置
	防止脑裂做法
		主节点与数据节点分离,设置基数主节点
		延长心跳检测的等待时间
分片数量考虑:
	30-32G的JVM限制 分片容量最大限制为 30GB,根据数据规模 /30G +1个分片
	根据索引类型设置分片;
	分片是无法动态扩容的,只能重置索引,这就导致该索引暂时不可用
分片副本数量考虑:
	副本大多为2则可, 如果并发请求大, 那么可以增加副本,可以动态扩容

分布式集群的调优策略:

写调优:
	首次写入数据 副本设0, 写入完成再调成 正常副本数量 直接拷贝即可;
	合理设置mappings,分词的字段要设置好,或者不建立索引,针对有些类型分词没有意义浪费效率
	减少内容长度,有些内容没必要建索引那就没必要写到ES中
	使用不同的分词器,合适搭配
	_source字段调整, includes和excludes 过滤
	评分相关度关闭,有些查询无需计算相关度,可关闭减少性能消耗;
	调整索引刷新间隔;
	批处理来新增文档,一次请求处理;
	文档的路由处理,针对于请求进行路由,使其减少线程的开启,设置一个routing来让put时 变成为一个批处理,减少线程数,但会对于单次请求来讲,请求时间加长了,要注意;
读的调优:
	对索引进行分组, 业务控制分组去读
	filter去替代query减少相关度评分计算,filter+bool的查询是可以做到相关度评分的查询效果,业务进行组装;
	ID优化为keyword,ES可优化并加快搜索速度;
	限制用户输入无效字符,减少ES的无效查询或慢速查询

ES的数据模型:

现实世界与计算机语言的映射
事物实体:具体的物或人
概念实体:对事物归类的实体,如一个公司,一个队伍
实体属性:实体的特征

数据建模:

概念建模:
	搞个大概雏形
逻辑建模
	添加细节、关系、对应;
	便于各岗位沟通交流,明确需求,不依赖具体的实现,可选型、技术栈选择
物理建模
	具体落实到数据库产品选择.对逻辑建模进行具体的执行和建立,数据的具体类型,表关系的设计,索引建立等具体的工作;
建模的意义:贴图

ES数据建模的Mapping设置:

es的网址可以具体查看mapping属性,官网:

在这里插入图片描述

设置流程

在这里插入图片描述

关联关系处理:
	application-side joins 像表连接一样的关联查询,对独立的索引进行组合的查询
	查时 将term中设置联查的索引的id 作为value 查询
	data denormalization非规范化查询,针对少量的关联关系处理
	添加文档时,将关联的关系进行存储在各个索引中,提供给后期查询用
	使用match条件查询
	嵌套关联关系, 将数据进行嵌套组装,查询时对数据进行直接查询即可,但数据添加相对复杂
	使用 naste参数设置查询条件
	父子文档关联关系 牺牲查询性能来换取索引性能,查询性能比嵌套查询慢5-10倍,消耗内存和CPU,需要特定的has_parent和has_child过滤器查询语法,不能同时返回父子文档,父子的文档都在一个索引上,父子必须存储在同一分片上,通过routing进行关联存储

ES的搜索实战:

数据在DB中,存储到ES中,再给用户进行查询.通过点击后查询数据库进行查看详细页面;
一些细节:
	注意将elasticsearch-rest-high-level-client中的es包进行排除,该包中的es版本较低;
	IndexRequest().source()多态方法中 Object..数组并不能处理实体类.
	使用成型的插件可以避免一些问题的出现

ES深度应用剖析:

贴图

ES基本存储单元为shard,每个shard中存储了若干个segment;
commits:
	 Commit 操作意味着将 Segment 合并,并写入磁盘。保证内存数据尽量不丢。但刷盘是很重的 IO 操作, 所以为了机器性能和近实时搜索, 并不会刷盘那么及时。

在这里插入图片描述

Translog:
	新文档被索引意味着文档会被首先写入内存 buffer 和 translog 文件。每个 shard 都对应一个 translog文件

在这里插入图片描述

refresh:
	在 Elasticsearch 中, _refresh 操作默认每秒执行一次, 意味着将内存 buffer 的数据写入到一个新的 Segment 中,这个时候索引变成了可被检索的。写入新Segment后 会清空内存buffer。

在这里插入图片描述

flush:
	Flush 操作意味着将内存 buffer 的数据全都写入新的 Segments 中, 并将内存中所有的 Segments全部刷盘, 并且清空 translog 日志的过程。

近实时搜索的原理:

不会立即同步,暂时移除刷盘机制,先把新增的文档写入内存中,再提交到文件系统的buffer,立刻提供查询功能;但不会刷盘到磁盘文件.在后期进行定时的异步刷盘操作,写盘为不连续的随机写入,不像rocket的刷盘机制,是顺序写入的;

整体流程的贴图
在这里插入图片描述

refresh的API:
	默认每秒自动刷新一次,可通过API进行手动刷新,对单个索引、单个文档进行刷新;
	针对那种不是特别多的新增索引,可以把刷新间隔设置长一点;
	settings:{
		refresh_interval:30s
	}
	如果后期需要可以再设置回1秒一刷新

持久化变更:

与近实时搜索的原理相同,在持久化时提供两个缓存的空间,内存buffer和transLog缓存,当refresh时,清空内存buffer写入文件交换系统buffer,当flush时将translog的数据进行刷盘并清空transLog,这样最大程度保证了数据的持久性,不会因为ES挂机而导致数据丢失;
flush API:
	默认每30分钟自动flush一次,
	可手动flush: /_flush
	可设置同步flush:/_flush?wait_for_ongoin 等待刷盘全部完成返回结果
transLog的安全性:
	transLog默认是5S刷盘一次,所以因为机器重启可能会丢失几秒内的数据,这是无法避免的,避免频繁IO提高速度就要丢失数据一致性,这是必然的;
	设置异步刷盘的属性:
	settings:{
		"index.translog.durability":"async",默认是同步的 request
		"index.translog.sync_interval":"5s"
	}
	可针对索引单独设置
索引文档的段合并机制:

在这里插入图片描述

段合并机制:索引创建和搜索时会自动进行,对一些segment进行合并,方便刷盘,但是这个操作会有IO消耗,所以要控制segment合并的磁盘读取速度,默认情况下归并限速配置是indices.store.throttle.max_bytes_per_sec:20MB,我们可以根据自己服务器的磁盘配置相应调高一些,如ELK这种日志系统就可以调成100MB或者更高.也可以设置归并的线程数来限制IO的数量,index.merge.scheduler.max_thread_count为CPU核心的数的一半.但也要配合硬盘的处理能力来决定.别硬盘5400转的,贼慢,搞8个线程去搞那玩意,浪费;
归并策略:根据一定的规则进行挑选segment进行合并
index.merge.policy.floor_segment 优先合并的segment最小设置,小于该值大小的segment会被优先合并,默认为2MB
index.merge.policy.max_merge_at_once 设置单次合并segment的数量. 默认为10个
index.merge.policy.max_merge_at_once_explicit 强制合并时,单次合并segment的数量,默认为30个
index.merge.policy.max_merged_segment 当一个segment超过该值设定大小后,将不会被合并,但不影响强制合并的功能.默认为5GB
optiomize API 强制合并:通过设置强制合并,将一些固定大小的数据segment进行强制合并,这些数据产能稳定,数据大小固定,通过设置max_num_segments参数来设置强制合并的segment个数,主要是为了提升搜索性能,将数据都扔一堆里肯定查询更快;
API:_optimize?max_num_segments=1
对应JDK API:forceMergeRequest.maxNumSegments(1)

并发处理机制:

并发减库存的问题;ABA的问题;
悲观锁的解决方案:
	直接锁数据,简单.方便;
乐观锁的解决方案:
	版本控制来解决并发问题,不会阻塞,自己维护了一个version版本,不用自己搞,同过if_seq_no和if_primary_term参数来进行乐观锁更新,如果不一致将会报错,seq_no会针对整个索引的,version是针对文档修改的,修改时只要原来的version号大就可.新增文档seq_no来更新,单个文档version来搞

ES的分布式一致性:

一致性检测
5.0之前: one、all、quorum;
	一个主节点活跃即可;
	全部节点活跃;
	计算后的节点数量活跃,公式
	(主的总数 + 每个主的副本数) /2 +1
timeout机制:
	一段时间内检测节点活跃
5.0之后:wait_for_active_shards 设置需要活跃的节点数量,也是根据quorum公式计算

Query文档搜索机制:

搜索类型:
query nad fetch:
	向所有分片发出查询请求,但浪费资源,会有重复记录,会多返回数据,为size的n倍
QUERY_THEN_FETCH
	查询前先将分片的词频率和文档频率收集,提供更精准评分相关度的查询,性能低,也会返回size N倍的数据;
QUERY_THEN_FETCH
	先向shard发送请求,然后根据返回的数据相关度再拿出size个数据,性能较低、准确度较为不错,详细流程:
	1.发送查询到每个shard 
	2.找到所有匹配的文档,并使用本地的Term/Document Frequency信息进行打分 
	3.对结果构建一个优先队列(排序,标页等) 
	4.返回关于结果的元数据到请求节点。注意,实际文档还没有发送,只是分数 
	5.来自所有shard的分数合并起来,并在请求节点上进行排序,文档被按照查询要求进行选择 
	6.最终,实际文档从他们各自所在的独立的shard上检索出来 
	7.结果被返回给用户
DFS_QUERY_THEN_FETCH
	比上面多了个词频率文档频率进行收集和统计;
	1.预查询每个shard,询问Term和Document frequency
	2.发送查询到每个shard
	3.找到所有匹配的文档,并使用全局的Term/Document Frequency信息进行打分
	4.对结果构建一个优先队列(排序,标页等)
	5.返回关于结果的元数据到请求节点。注意,实际文档还没有发送,只是分数
	6.来自所有shard的分数合并起来,并在请求节点上进行排序,文档被按照查询要求进行选择
	7.最终,实际文档从他们各自所在的独立的shard上检索出来
	8.结果被返回给用户
文档写入流程:
(1)客户端首先会选择一个节点node发送请求过去,这个节点node可能是协调节点coordinatingnode
(2)协调节点coordinating node会对document数据进行路由,将请求转发给对应的node(含有primary shard)
(3)实际上node的primary shard会处理请求,然后将数据同步到对应的含有replica shard的node
(4)协调节点coordinating node如果发现含有primary shard的node和所有的含有replica shard的node符合要求的数量之后,就会返回响应结果给客户端
文档查询流程:
1、客户端首先会选择一个节点node发送请求过去,这个节点node可能是协调节点coordinating node
2、协调节点将搜索请求转发到所有的shard对应的primary shard 或 replica shard ,都可以。
3、query phase:每个shard将自己的搜索结果的元数据到请求节点(其实就是一些doc id和 打分信息等返回给协调节点),由协调节点进行数据的合并、排序、分页等操作,产出最终结果。
4、fetch phase:接着由协调节点根据doc id去各个节点上拉取实际的document数据,最终返回客户端。
相关性评分算法BM25:
设置BM25的K值和B值:
	settings:{
		similarity:{
			bmname:{
				type:BM25,
				b:0.1,
				k1:0.3
			}
		}
	},
	mappings:{
		properties:{
			title:{
				type:text,
				similarity:bmname
			}
		}
	}
DocValues机制:
倒排索引查询很快,但排序没有很好的解决,docValue属性来完善排序的机制,通过设置该值来决定是否排序,设置false后,不可被排序,不可被统计分组;
概念:
	一个正排索引,文档里有哪些词,占用空间,但提供了排序和统计;
底层:
	与倒排索引一样,也有segment和刷盘机制,但没有buffer这一步,直接入库;
压缩:
	根据值进行压缩,利用最大公约数的机制来进行同比压缩;
禁用doc values:
	text无法使用docvalue排序,因为要分词;
Filter:
 在倒排索引中查找搜索串,获取document list
 Filter为每个在倒排索引中搜索到的结果,构建一个bitset,[0, 0, 0, 1, 0, 1](非常重要)
 多个过滤条件时,遍历每个过滤条件对应的bitset,优先从最稀疏的开始搜索,查找满足所有条件的document
 caching bitset,跟踪query,在最近256个query中超过一定次数的过滤条件,缓存其bitset。对于小segment(<1000,或<3%),不缓存bitset
 如果document有新增或修改,那么cached bitset会被自动更新
 filter大部分情况下,在query之前执行,先尽量过滤尽可能多的数据
ES控制搜索精度:
自定义函数:
	自定义一个函数,配合boots权重值来进行自定义的评分计算规则;
	几个影响评分的函数
	field_value_factory:分数影响函数,可设置一些公式,然后与设置的source进行一些计算,如
	field_value_factory:{
		filed:"需要计算的字段",
		factor:"因子数",
		modifier:"sqrt" 计算的公式,这个是平方根
	}
	modifier取值列表:

	产生的分值必须为正数,否则会报错.所以在计算分数时要注意写公式不要出现负数;
	Decay functions:递减函数,类似于范围查询,计算查出的数字与设置的原点的距离,进行返回展示;
	规则公式:
	高斯、线性、指数,这三个规则所呈现的递减幅度不同而已.高斯为一个平滑的凸起弧面,指数为了一凹进的弧面,线性则为锋利的切面;
	公式属性:
	origin设置原点,与scale进行计算
	scale:设置衰减距离,范围查询的主要参数,用来计算相关度评分的主要参数,可日期、数字,也可写上单位
	offset:偏移量,对value进行附加
	decay:衰减参数,按照设置的比例给文档进行评分,相当于一个影响因素.如果不定义,那么默认就给每个查出的文档+0.5分
bulk操作API:
基本的格式:
	{"action":{"metadata(_index)"}}
	{"data"}
	不需要将JSON转换为标准对象,节省内存占用
深度分页:
基础方式:from+size,请求量大时,ES会对分页进行限制,idnex.max_result_window,如果超出了该数,那么ES会拒绝返回结果,但有的需求确实需要深度分页查询到所有数据;
scroll遍历方式:
	不适合实时搜索,利用快照机制锁定某一时刻数据,进行分页查询,不会被更新数据影响,适合批处理任务;
search after方式:
	满足实时获取,根据上一页最后一条数据的位置获取下一页数据,数据将需要唯一的字段value,如_id或者唯一编号等.利用唯一字段value进行排序,然后通过seach_after填入上一页最后一条数据的唯一value;只能点击下一页来操作,不能直接选择页码;
三种方式对比
from 简单、深度分页有问题、数据量小时,简单分页
scroll 解决深度分页,数据不是实时的,快照,需要使用srcoll_id,适合批次处理的海量数据
seach_after 最强性能,分页实时性、速度都可以,但无法通过选择页码进行翻页,适合大量数据的分页;
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
elasticsearch 学习笔记包括以下内容: 一、Elasticsearch概述: - Elasticsearch是一种开源的分布式搜索和分析引擎,可以用于快速搜索、分析和存储大量的结构化和非结构化数据。 - Elasticsearch与Solr相比有一些区别,包括用户、开发和贡献者社区的规模和成熟度等方面。 二、Elasticsearch安装: 1. 下载Elasticsearch,可以从官方网站或华为云镜像下载。 2. 安装Elasticsearch。 三、安装head插件: - head插件是一个可视化的管理界面,可以方便地管理和监控Elasticsearch集群。 四、安装Kibana: 1. Kibana是一个开源的数据可视化工具,用于展示和分析Elasticsearch中的数据。 2. 下载Kibana并安装。 3. 启动Kibana并进行访问测试。 4. 可选的汉化操作。 五、ES核心概念理解: - 学习ES的核心概念,包括索引、文档、映射、查询等。 以上是elasticsearch学习笔记的主要内容,希望对你有帮助。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Elasticsearch 学习笔记(上)](https://blog.csdn.net/m0_52691962/article/details/127064350)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值