es深入搜索之全文检索

es深入搜索之全文检索,第1张

  我们之前介绍过结构化搜索的简单使用,接下来,我们来看怎样在全文字段中搜索最相关的文档

  全文搜索包括两个最重要的方面:

  1. 查询与结果的相关性,并根据相关性对结果进行排名。

  2. 分析,将数据转化为有区别的、规范化的的过程。

  所有的查询都或多或少的会进行相关度计算,但不是所有的查询都会有分析阶段,文本查询可以分为两个部分:

  1. 基于词项的查询,如 term 或 fuzzy 这样的查询是没有分析阶段的。他们对单个词项进行 *** 作。

  2. 基于全文的查询,比如match, 它们会先了解字段映射的信息,判断字段是否被分词,是否是日期还是数字等, 再根据映射信息,构建要查询的词项列表,根据列表进行查询。

  匹配查询 match 是个核心查询。无论需要查询什么字段, match 查询都应该会是首选的查询方式。使用方式如下:

es执行上列步骤的过程如下:

  如果一次只能搜索一个词语,那么全文搜索会不太灵活,幸运的是 match 也支持多词查询 。

以上查询其实先后执行了两次 term 查询,使用 bool 进行包含,然后将结果进行合并返回。

  以上查询其实会导致出现不相关的结果,我们只想搜索包含words1 和 words2 的文档,而不是 or 的结果。match 查询还可以接受 operator *** 作符作为输入参数,默认情况下该 *** 作符是 or 。

这种 *** 作还是有些不妥,在 and 和 or 中间选择太过绝对,如果用户给出了5个词项,我们想只要满足其中4 个 就表示匹配,match 也提供了 minimum_should_match 参数,他是一个最小匹配参数,我们可以控制满足的词项超过改值则表示匹配,最好是使用百分比,因为你也不知道用户提供了多少个词项。该参数的设置非常灵活,完整的信息参考文档,请看 https://www.elastic.co/guide/en/elasticsearch/reference/5.6/query-dsl-minimum-should-match.html#query-dsl-minimum-should-match

如果我们使用 bool 查询黑色、大屏、手机,其中should 语句匹配得越多表示文档的相关度越高,但是我们想要手机所占的权重比较大,内容包括手机的文档排名靠前,可以使用 boost 设置相对权重,注意是相对权重,默认是1。

在说相关度被破坏的原因之前,我们先看看es对于相关度是如何计算的

es 的相似度算法被定义为检索词频率/反向文档频率, TF/IDF ,包括以下内容:

有时,我们索引了一些文档,然后检索发现有些相关度较低的返回排名靠前?

  出现上述原因的情况是因为es由于性能原因,不会计算所有败洞索引该文档的节点的IDF,比如我们索引了10个文档, 其中6个文档中包含 foo ,而由于es是分布式的,一个索渗团引会察喊枯被分为多个分片,有可能分片一包含的5 个文档,有 4 个包含foo, 而另外一个在分片二中,所以会导致结果有差异。

  在实际应用中,不会出现该问题,因为本局和全局的IDF差异会随着文档数量的增加逐渐降低。如果想要自己处理该问题,可以在搜索请求之后增加 ?search_type=dfs_query_then_fetch ,他会使得es先计算各个分片的 IDF, 然后在求出全局的 IDF, 生产环境中不要使用。因为只要有足够的数据就可以使得差异减少。

Segment(段):Lucene里面的一个数据集概念

提交点文件:有一个列表存放着所有已知的所有段

ES底层是基于Lucene,最核心的概念就是Segment(段),每个段本身就是一个倒排索引。

ES中的Index由多个段的集合和commit point(提交点)文件组成。

提交点文件中有一个列表存放着所有已知的段,下面是一个带有1个提交点和3个段的Index示意图:

Doc新增提交主要过程如下:

一、写入磁盘后可见:

1、Doc写入Buffer

Doc会先被搜集到内存中的Buffer内,这个时候还无法被搜索到,如下图所示:

(1)创建一个新段,作为一个追加的倒排索引,写入到磁盘(文件系统缓存)

(2)将新的包含新段的Commit Point(提交点)写入磁盘(文件系统缓存)

(3)磁盘进行颤没胡fsync,主要是将文件系统缓存中等待的写入 *** 作全部物理写入到磁盘,保证数据不会在发生错误时丢失

(4)这个新的段被开启, 使得段内文档对搜索可见

(5)将内存中buffer清除,又可以把新的Doc写入buffer了

下面展示了这个过程完成后的段和提交点的状态:

为了数据安全,每次的索引变更都最好要立刻刷盘, 所以 Commit *** 作意味着将Segment 合并并写入磁盘。保证内存数据尽量不丢。刷盘是很重的 IO *** 作, 所以为了机器性能和近实时搜索, 并不会刷盘那么及时。

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

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

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

1、refresh:

Lucene支持对新段写入和打开 - 可以使文档在没有完全刷入硬盘的状态下就能对搜索可见,而且是一个开销较小的 *** 作,可以频繁进行。

下面是一个已经将Docs刷入段但还没有完全提交的示意图:

2、translog

为了避免在两次commit *** 作间隔时间发生异常导致Doc丢失,ES中采用了一个事务日志记录每次对ES的 *** 作。加上translog后新增文档流程如下:

文档被添加到buffer同时追加到translog,如图:

下面示意图展示了这茄拦个状态:

4、flush

flush就是执行commit清空、干掉老translog的过程。默认每个分片30分钟或者是translog过于大的时候自动flush一次。可以通过flush API手动触发,但是只会在重启节点或关闭某个索引的时候这样做,因为这可以让未来ES恢复的速度更快(translog文件更小)。

三、 ES对Doc删除的处理

(1)删除一个ES文档不会察扮立即从磁盘上移除,它只是被标记成已删除。因为段是不可变的,所以文档既不能从旧的段中移除,旧的段也不能更新以反映文档最新的版本。

ES的做法是,每一个提交点包括一个.del文件(还包括新段),包含了段上已经被标记为删除状态的文档。所以,当一个文档被做删除 *** 作,实际上只是在.del文件中将该文档标记为删除,依然会在查询时被匹配到,只不过在最终返回结果之前会被从结果中删除。ES将会在用户之后添加更多索引的时候,在后台进行要删除内容的清理。

(2)Doc删除与段合并的关系

通过每秒自动刷新创建新的段,用不了多久段的数量就爆炸了,每个段消费大量文件句柄,内存,cpu资源。更重要的是,每次搜索请求都需要依次检查每个段。段越多,查询越慢。

ES通过后台合并段解决这个问题。ES利用段合并的时机来真正从文件系统删除那些version较老或者是被标记为删除的文档。被删除的文档(或者是version较老的)不会再被合并到新的更大的段中。

ES对一个不断有数据写入的索引处理流程如下:

索引过程中,refresh会不断创建新的段,并打开它们。

合并过程会在后台选择一些小的段合并成大的段,这个过程不会中断索引和搜索。合并过程如图:

两个已提交的段 和一个未提交的段合并为一个更大的段。从上图可以看到,段合并之前,旧有的Commit和没Commit的小段皆可被搜索。

(3)段合并后的 *** 作:

a、新的段flush到硬盘

b、编写一个包含新段的新提交点,并排除旧的较小段。

c、新的段打开供搜索

d、旧的段被删除

合并完成后新的段可被搜索,旧的段被删除,如下图所示:

注:

什么情况下要强制刷新:

1、reindex后,手动修改refresh,由-1(不刷新)改为想要的刷新值

2、在读多,写少时,可以强制不刷新,因为每写入一条数据就会产生一个新段,查询时就会查一次,降低效率

3、即时性要求高,:如广告立马需要被看到,需要手动强制刷新

ES官方提供了两中检索方式: 一种是通过 URL 参数进行搜索,另一种是通过 DSL(Domain Specified Language) 进行搜索 官方更推荐使用第二种方式第二种方式是基于传递JSON作为请求体(request body)格式与ES进行交互,这种方式更强大,更简洁

GET /ems/emp/_search?q= &sort=age:asc*

GET /ems/emp/_search?q=*&sort=age:desc&size=5&from=0&_source=name,age,bir

NOTE1: 通过使用term查询得知ES中默认使用分词器为标准分词器(StandardAnalyzer),标准分词器对于英文单词分词,对于中文单字分词

NOTE2: 通过使用term查询得知,在ES的Mapping Type 中 keyword , date ,integer, long , double , boolean or ip 这些类型不分词 只有text类型分词

索引区:name:[张:0:1,张:1:1]在0号文档中,出现1次,返销在1号文档中出现1次。漏斗游销嫌


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/tougao/8226646.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-14
下一篇2023-04-14

发表评论

登录后才能评论

评论列表(0条)

    保存