ElasticSearch 主脉

全文检索:
		全文检索是指计算机索引程序通过扫描文章中的每一个词,对每一个词建立一个索引,指明该词在文章中出现的次数和位置,
	当用户查询时,检索程序就根据事先建立的索引进行查找,并将查找的结果反馈给用户的检索方式。
		全文检索的方法主要分为按字检索和按词检索两种。按字检索是指对于文章中的每一个字都建立索引,检索时将词分解为字的组合。
	对于各种不同的语言而言,字有不同的含义,比如英文中的字与词实际上是合一的,而中文中的字与词有很大分别。
	按词检索指对文章中的词,即语义单位建立索引,检索时按词检索,并且可以处理同义项等。
	英文等西方文字由于按照空白切分词,因此实现上与按字处理类似,添加同义处理也很容易。
	中文等东方文字则需要切分字词,以达到按词索引的目的,

倒排索引:
	正排索引:根据索引(id),找到文档。
	倒排索引:根据索引(拆分的文档内容),找到文档对应的id,再根据对应的id找到目标文档。

架构:
	1、需要检索的text -> 分词 -> 构建索引。
	2、用户输入 -> 分词 -> 根据1步构建的索引,查询符合条件的内容 -> rank(打分,业务相关) -> 显示结果。
系统划分:
	1、分词
	2、rank打分
	
技术选型:
	1、根据业务进行选型。
	2、java常用的全文索引框架有:Lucene(根本)、Solr、Elasticsearch
		2.1、Solr 实时性不强,大数据处理弱。
			参考博文: https://blog.csdn.net/u010510107/article/details/81051795
		2.2、Elasticsearch 实时性强,分布式,大数据处理。
			参考博文: https://blog.csdn.net/llwy1428/article/details/89714709
					   https://blog.csdn.net/JENREY/article/details/81290535#commentBox
		2.3、solr\Elasticsearch对比:https://www.jianshu.com/p/132b8f1b66a7	
		2.4、lucene: https://blog.csdn.net/JENREY/article/details/81004130	

Elasticsearch 

核心概念:
	1、Near Realtime 近实时
	2、cluster 集群,分布式	

是什么(what)
	基本概念:
		1、index (数据库,分片的对象)
		2、type  (表)
		3、Document (行,记录)
		4、Field (列)
	分片:一台服务器,无法存储大量的数据,ES把一个index里面的数据,分为多个shard,分布式的存储在各个服务器上面。
	副本:主从
	
	Field 类型:text 分词,keyword 不分词。 
	
	
	在 Elasticsearch 中,是master-slave架构。节点是对等的,节点间会通过自己的一些规则选取集群的 Master,
	Master 会负责集群状态信息的改变,并同步给其他节点。这样写入性能会不会很低???注意,只有建立索引和类型需要经过 Master,
	数据的写入有一个简单的 Routing 规则,可以 Route 到集群中的任意节点,所以数据写入压力是分散在整个集群的。
	
	评分机制:TF-IDF(词频-逆文档频率)
		词频:在文档中出现的频率越高,得分越高。
		逆文档频率:在所有的文档中,出现的频率越低,得分越高。(物以稀为贵)		
		

怎么用(how)
	1、业务需要,过滤朋友圈:(自定义过滤规则:https://www.jianshu.com/p/a0a168585e3d)	
	
	2、_mapping
	
	3、_search  https://www.elastic.co/guide/en/elasticsearch/reference/7.4/search-uri-request.html
		q	查询字符串(映射到query_string查询)  									_search?q=fieldname:value
		df	在查询中不指定字段是默认查询的字段,如果不指定字段,ES会查询所有字段  	_search?q=value&df=fieldname
		analyzer	分析查询字符串时要使用的分析器名称
		sort	排序,可以升序排序和降序排序     									_search?sort=fieldname:ase/desc
		timeout	指定超时时间,默认为无超时
		from	返回的索引匹配结果的开始值,默认为0
		size	要返回的搜索条数,默认为10
		default_operator	要使用的默认运算符可以是AND或 OR,默认为OR

	4、整合 springboot elasticsearch 
		4.1、多条件搜索:https://blog.csdn.net/Topdandan/article/details/81436141
		https://docs.spring.io/spring-data/elasticsearch/docs/3.1.3.RELEASE/reference/html/
		打印es dsl 语句:logging.level.org.springframework.data.elasticsearch.core = debug


为什么(why)
	重难点:
		集群内部原理、分布式文档存储、执行分布式检索、分片内部原理。
		
	1、集群的内部原理
		1、集群概览
			集群是由多个拥有相同 cluster.name 的节点组合而成的。
			master节点:负责管理集群范围内的所有变更,如:增加、删除索引;增加、删除节点等。
						主节点不涉及文档级别的变更何搜索等操作,所以主节点不会成为性能瓶颈。
			存数据时:客户端发送消息到集群中的任何节点,每个节点都知道任意文档所处的位置,并且能够将外面的请求直接转发到存储我们所需文档的节点中。
			取数据时:无论哪个节点,都能负责从各个包含我们所需文档的节点收集回数据,并将最终结果返回给客户端。
		
		2、集群健康:GET /_cluster/health
			green: 所有主副分片都正常运行。
			yellow:所有主分片正常运行,有些副分片不能正常运行。
			red:有些主分片不能正常运行。
		
		3、添加索引
			索引:保存相关数据,指向一个或者多个物理“分片”的逻辑命名空间。
			分片:保存全部数据中的一部分,一个分片就是一个Lucene实例,是一个完整的搜索引擎。我们的文档被存储和索引到分片内。程序直接对接索引。
			
			es将数据分配到分片中,分片是数据的容器,文档保存在分片内,分片又被分配到集群的各个节点中去。当集群扩大或缩小时,es自动在节点中迁移分片,使得数据仍然均匀分布在集群里。
			
			一个分片可以是 主分片 或者 副本分片 。副本分片:主分片的数据拷贝,冗余备份,并为搜索和返回文档等读操作提供服务。
			索引建立时,确定了主分片(不可更改),副分片可以随时更改。
		
		4、水平扩容
			主分片数决定了写入的性能。主分片数量=节点数,就是写入的最大性能点。
			副本分片数决定了读的性能。越多的副本分片,读性能越好。(但是副本的同步需要消耗资源)
			
		5、故障处理
			节点宕机后,如果宕机的节点内含主分片,失效的主分片将从别的节点中升级副本分片来替换。从而达到系统的高可用。
			如果节点是master节点,那么将从剩余可用节点中,选举新的Master节点。
	
	2、数据的输入和输出
		1、文档更新
			put 整体更新。
			es文档不能更新。更新的实现方式为:找到旧文档,替换对应的字段。再将新的结果插入,最后将旧的文档删除。
		2、并发控制
			_version 字段,乐观并发控制。
		3、部分更新
			POST 部分更新。
	
	3、分布式文档存储
		底层:如何存,如何取。
		1、路由一个文档到分片中
			shard = hash(routing) % number_of_primary_shards;
		2、主分片和副本分片的交互
			每个节点都知道集群中任一文档的位置。每个节点都有能力处理任意请求。
		3、新建、索引和删除文档
			新建、索引和删除文档都是写操作,必须再主分片上完成之后,才能被复制到副本分片中。
			
			步骤:客户端发起请求 -> node(协调节点) (确定分片位置) -> node(包含了具体分片的节点) -> 处理完成 -> 同步到副本节点 -> 返回node(协调节点) -> 客户端
		4、获取文档
			轮询副本的方式,达到负载均衡。
			根据id获取文档:根据id进行路由判断,直接定位到具体的分片,获取文档。
			搜索获取文档:将搜索的内容,用轮询节点的方式,发送到所有的副本节点中(不重复的副本),获取到结果后,再汇总到协调节点,协调节点往外吐结果。
			
	4、搜索
		1、概念
			Mapping(映射) : 描述字段如何存储。
			Analysis(分析): 全文是如何处理数据,使得数据可以被搜索到。
		2、分页
			需要进行集中排序,才能保证结果顺序是正确的。
			分布式系统中深度分页的问题:(禁止排序,或者限制分页深度。scroll游标的使用)
				1、前提条件:3个主分片。pageSize=10。page = 0。
				2、第一页:每个节点返回10条数据,排序完成后,取前10条返回。
				3、第二页:每个节点返回(page+1)*pageSize= 20。排完序后,取10~20的记录返回。
				4、第99页:每个节点返回990条记录……
			
	5、映射和分析
		1、指定分析器
		2、内部对象的处理
			1、数组:类型一致,无序。
			2、内部对象的索引:
				Lucene不理解内部对象,Lucene文档按照键值对处理的:user.age:valeu。
		
	6、执行分布式检索
		1、查询阶段
			各个分片返回对应的文档id和排序值给协调节点。
		2、取回阶段
			根据排序结果,获取对应的记录。通过文档id到对应的分片获取文档,组装返回。
		3、搜索选项
		4、游标查询Scroll
			scroll游标,解决深分页问题。
			游标查询会取某个时间点的快照数据,查询初始化之后索引上任何变化都会被他忽略。它通过保存旧的数据文件来实现这个特性,类似视图。
			游标查询用字段_doc来排序,让es仅仅从还有结果的分片返回下一批结果。
			scroll_id:游标的id(视图的id).
	
	7、索引管理(文档)
		1、创建索引
			默认情况下,系统会进行动态映射。
			如果需要关闭动态映射:config/elasticsearch.yml   action.auto_ceate_index: false
		2、删除索引
			delete /my_index
			delete /_all    所有索引。config/elaticsearch.yml action.destrutive_requires_name: true 禁止使用_all防止误删。
			delete /index_* 通配符
		3、索引设置
			number_of_shards: 主分片数量,默认是5。索引创建完成后,不能修改。
			number_of_replicas:副本分配数量,默认是1。可以随时更改。
		4、分析器
			分析器包含如下内容:
				字符过滤器:过滤掉某些字符
				分词器:将要索引的文本,拆分为索引的词元。
				单词过滤器:lowercase/stop等过滤器。
		5、类型和映射
			1、Lucene 如何处理文档
				1、没有类型(type)的概念,es通过type的过滤,来返回查询结果。
				2、没有映射(mapping)的概念,es通过将复杂的json映射成Lucene需要的的扁平化数据方式。(转换为key,value的形式)			
		6、根对象	
			1、属性
				type:字段的数据类型,String,date
				index:字段是否索引
					1、analyzed   拆分单词,索引
					2、not_analyzed  不拆分单词,索引。
					3、no  不索引。
			2、元数据    
				_source:存储文档的json字符串。
				_all: 所有字段的集合,禁用:"_all":{"enable":false}
				文档标识:
				_id
				_type
				_index
		7、动态映射
			dynamic:
				true(动态添加新字段)
				false(忽略新字段)
				strict(如果遇到新字段抛出异常)
			date_datection: false (日期动态监测映射)
		8、重新索引
			1、用新的设置创建新的索引并把文档从旧的索引复制到新的索引。
				用scroll从旧的索引中批量索引文档,再用bulk API把文档推送到新的索引中。(新版本:Reindex API)
			2、索引别名和零停机
				_alias
				应用中,使用别名。迁移的时候将实际索引迁移完成,再将别名指向新的索引。
			
	8、分片内部原理
		1、解答的问题:
			1、为什么搜索是近实时的?
			2、为什么文档的CRUD操作是实时的?
			3、Elasticsearch是怎样保证更新被持久化在断电时也不丢失数据?
			4、为什么删除文档不会立即释放空间?
			5、refresh,flush,optimize API都做了什么,什么情况下应该使用它们?		
		2、使文本可被搜索
			1、倒排索引:包含每个词项出现过文档的列表;包含词项出现过的文档总数;在对应文档中出现的总次数;每个文档的长度……等更多的文档信息。
			2、不变性
				优点:
					1、不需要锁。
					2、可以常驻内存,加速搜索。					
				缺点:
					1、删除数据不及时,更新数据是删除和添加,浪费硬盘空间。
					2、不变性导致段的数量太多,对服务器的句柄自由消耗非常大。
					3、删除的不及时,查询出来的结果需要经过.del文件的过滤,消耗性能。		
		3、动态更新索引
			1、通过增加新的索引来实现动态更新索引。
			2、es基于Lucene,Lucene按段搜索,每个段就是一个倒排索引。
				1、Lucene段
					1、重点:段不可变。
					2、Lucene索引包含:提交点,段
					3、新增
						1、为了提升写性能:采用延迟写策略,积累到一定量的数据(缓存中),才写入到硬盘。
						2、为新增的数据新建对应的段。(因为段是不可变的,所以只能新增)
						3、写入硬盘,更新提交点。
					4、查询的时候:
						1、遍历对应的段。(缓存的数据不可用,这就是es是近实时搜索的原因。默认1秒自动写一次段)
						2、过滤结果数据。						
			3、删除和更新
				1、段是不可变的,删除是把删除的文档记录到.del文件中;更新的是:删除+添加。
				2、查询的时候,先查询结果,再从.del文件中过滤结果。			
			4、refresh_interval 设置刷盘间隔时间。
				优点:提升性能。
				缺点:丢失数据。
		4、持久化变更
			1、es增加translog(事务日志),类似redis aof。
			2、安全性
				"index.translog.durability": "async", //异步刷新。(request实时刷新)
				"index.translog.sync_interval": "5s"  //异步刷新间隔
			3、每次新增的段写入到磁盘,translog会清空。
		5、段合并
			1、段合并过程
				1、合并线程选择大小相似的段,在后台将它们合并到更大的段当中去。不会中断索引和搜索。
				2、合并的过程,将删除那些失效的文档。

  

posted @ 2020-03-28 16:42  陈标  阅读(253)  评论(0编辑  收藏  举报