博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
es修改排序_Elasticsearch 中的索引排序
阅读量:4318 次
发布时间:2019-06-06

本文共 2556 字,大约阅读时间需要 8 分钟。

在Elasticsearch6.0中,引入了一个新的特征,叫Index Sorting(索引排序)。用户可以将索引数据按照指定的顺序存储在硬盘上,这样在搜索排序取前N条时,不需要访问所有的匹配中的记录再进行排序,只需要访问前N条记录即可。

Lucene中的Index Sorting

很多年以前,Lucene引入了一个工具叫做IndexSorter。这个工具的作用是从一个已有的索引中取数,然后按照指定的字段排序输出到另一个索引中。当然,这个排好序的索引是不允许用户进行数据修改的,所以用户每次修改了源索引,必须要重新构建生成目标索引。IndexSorter是Lucene第一次尝试在索引阶段,直接将数据排序存储到硬盘上。

有了索引排序的概念以后,另一个“early termination(早期中断)”概念也被引入。假设你要搜索按照日期排序的前N条记录时,如果索引在硬盘上已经按照日期排好序了,那么我们只需访问匹配搜索条件的前N条记录,就可以中断请求。这就是早期中断的概念。很明显,早期中断带来了巨大的性能提升,不需要访问所有的匹配中的记录,不需要再搜索时排序。但是,IndexSorter也有问题,不能适应频繁更新的索引。这又引入了一个新的想法,在在索引Merge阶段进行排序。

Lucene的提升

Lucene会定期的刷新产生一个新的段(Segment),这个新的段包含了自从上次刷新以后新到达的所有数据。一旦刷新产生了段,数据就可以被搜索展示了。因为刷新频繁的发生,Elasticsearch 1s刷新一次,所以会产生大量的段文件,为了限制段文件的数量,Lucene会在后台定期的合并(merge)这些段文件。合并其实就是将多个小文件合并成一个大文件,为了能在merge阶段对文档重新排序,Lucene引入了一种新的merge策略。这种新的设计使得用户可以不使用IndexSorter这种静态工具就能在索引阶段对数据进行排序。由于一些段已经排序,而新刷新的段则没有排序,所以,merge的时候首先对没排序的段排序,然后与已排好序的段进行合并。

当然,在merge阶段排序,会带来索引吞吐量的降低。下面的测评显示了merge阶段的排序将总共的吞吐量降低了一倍。

性能降低的原因也很简单:merge阶段需要先对未排序的段进行排序,然后再合并。

为了减少对多个段的再排序花费,Lucene决定在索引阶段(flush)就对数据进行排序。现在,因为所有的段文件都是排好序的,merge过程更加快速了。这个在刷新阶段就排序的特性在Lucene6.5被引入,带来了65%的性能提升。

借助于Lucene的努力,Elasticsearch6.0引入了Index Sorting的概念,大大提升了搜索的速度。

搜索时的早期中断

很常见的一种搜索,按照某个字段进行排序,返回前N条记录。虽然只是获取前N条记录,Elasticsearch需要遍历所有匹配的文档,排序,然后返回前N条。尽管Doc values使得排序更加的有效,但是当匹配的数据集较大时,这个过程仍然会耗费较大的资源。

有了index sorting,我们可以提前指定文档的存储顺序,这样在搜索时,只需要访问前N条记录,就可以中断。

例如下面的图示,5.x需要访问所有的文档,排序计算前3条记录。而6.x因为提前按照顺序存储了文档,在搜索时只需访问前3条即可。

如何指定索引顺序

PUT scores

{

"settings": {

"index": {

"sort.field": "points",

"sort.order": "desc"

}

},

"mappings": {

"score": {

"properties": {

"points": {

"type": "long"

},

"playerid": {

"type": "keyword"

},

"game": {

"type": "keyword"

}

}

}

}

}

将相似的文档聚合在了一起

按照顺序存储文档,可以将相似的文档存储到一起,能够带来更好的压缩(例如差值压缩),以及更快的查询速度(不是绝对,查询速度取决于你的查询类型和查询语句)。

更加有效的And交集查询

例如下面的查询

GET players/player/_search

{

"size": 3,

"track_total_hits": false,

"query": {

"bool": {

"filter": [

{

"term": {

"region": "eu"

}

},

{

"term": {

"game": "dragons-lair"

}

},

{

"term": {

"skill-rating": 9

}

},

{

"term": {

"map": "castle"

}

}

]

}

}

}

Elasticsearch会按照下面的方式获取结果返回给用户:

如果我们在存储时指定了顺序:

PUT players

{

"settings": {

"index": {

"sort.field": [

"region",

"game",

"skill-rating",

"map"

],

"sort.order": [

"asc",

"asc",

"asc",

"asc"

]

}

},

"mappings": {

"player": {

"properties": {

"playerid": {

"type": "keyword"

},

"region": {

"type": "keyword"

},

"skill-rating": {

"type": "integer"

},

"game": {

"type": "keyword"

},

"map": {

"type": "keyword"

}

}

}

}

}

现在文档被存放在了一起:

查询获取到的数据集中在了一起,减少了随机寻址。

什么时候不建议使用索引排序

前面已经说过,在索引阶段排序会降低写入的吞吐量,如果你的应用对于写入的性能要求高,那么索引排序并不是一个好的选择。用户需要平衡查询速率和写入速率,实际测试以后做出自己的选择。

转载地址:http://lerzs.baihongyu.com/

你可能感兴趣的文章
IOS开发关于测试的好的网址资源
查看>>
ArcGIS影像配准与空间配准
查看>>
考研日记第一篇
查看>>
个人简介
查看>>
Lucky Conversion(找规律)
查看>>
自定义一个处理图片的HttpHandler
查看>>
2、函数及常用模块
查看>>
Oracle按周统计数据的几种方法
查看>>
FileStream随机文件访问(访问文件中间某点的数据)
查看>>
bootstrap table单元格样式,行样式以及分页显示全部的设置
查看>>
洛谷P1106 删数问题
查看>>
数据库的自增字段代码生成器——解决不同数据库自增字段的差异机制
查看>>
从哲学角度分析“唯有真正了解一个人,才能真的做到爱他”
查看>>
【LeetCode】抽样 sampling(共4题)
查看>>
js清空页面控件值
查看>>
02-linux-换源-ui方式
查看>>
07-C#笔记-运算符
查看>>
分布式锁的类型
查看>>
ZOJ 3780 Paint the Grid Again(隐式图拓扑排序)
查看>>
react-native页面之间的相互传值
查看>>