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