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