Elasticsearch HTML文件搜索性能提升实战
集群内存设置
Elasticsearch默认安装后设置的内存是1GB,对于任何一个现实业务来说,这个设置实在太小了,稍有大批量查询或者写入操作,集群很快就会出现问题。
ES在6.x版本后,通过修改安装路径elasticsearch/jvm.options文件来设置内存
-Xms10g
-Xmx10g
将内存设置为10g,重启服务后生效
systemctl restart elasticsearch.service
一个常见的问题是配置一个大内存,假设你有一个64G内存的机器,按照正常思维思考,你可能会认为把64G内存都给Elasticsearch比较好,但现实是这样吗, 越大越好?
当然,内存对于Elasticsearch来说绝对是重要的,用于更多的内存数据提供更快的操作,而且还有一个内存消耗大户-Lucene。
Lucene的设计目的是把底层OS里的数据缓存到内存中。Lucene的段是分别存储到单个文件中的,这些文件都是不会变化的,所以很利于缓存,同时操作系统也会把这些段文件缓存起来,以便更快的访问。
如果将所有的内存都分配给Elasticsearch,不留一点给Lucene,那全文检索性能会很差的。
所以标准的建议是把50%的内存给elasticsearch,剩下的50%也不会没有用处的,Lucene会很快吞噬剩下的这部分内存用于文件缓存。
推荐安装cerebro来查看ES集群的状态: cerebro.
副本和分片
分片(shard)
当有大量的文档时,由于内存的限制、磁盘处理能力不足、无法足够快的响应客户端的请求等,一个节点可能不够。这种情况下,数据可以分为较小的分片。每个分片放到不同的服务器上。
当你查询的索引分布在多个分片上时,ES会把查询发送给每个相关的分片,并将结果组合在一起,而应用程序并不知道分片的存在。
副本(replica)
为提高查询吞吐量或实现高可用性,可以使用分片副本。
副本是一个分片的精确复制,每个分片可以有零个或多个副本。ES中可以有许多相同的分片,其中之一被选择更改索引操作,这种特殊的分片称为主分片。当主分片不可用时,集群将副本提升为新的主分片。
ES默认是5个分片1个副本,设置方法:
curl -XPUT 'http://127.0.0.1:9200/_template/template_http_request_record'
-H 'Content-Type: application/json' -d
{
"index_patterns": [
"test"#index
],
"settings": {
"number_of_shards": 1,#分片
"number_of_replicas": 1#副本
}
}
索引分片如何设置合理?
在Elasticsearch中,每个查询在每个分片的单个线程中执行。然而,可以并行处理多个分片,并可以在相同分片上执行多个查询和聚合。
【小分片的利弊】这意味着,在不涉及高速缓存时,最小查询延迟将取决于数据、查询的类型、分片的大小。查询大量小分片将使得每个分片的处理速度更快,但是随着更多的任务需要按顺序排队和处理,它不一定要比查询较小数量的更大的分片更快。如果有多个并发查询,则有很多小碎片也会降低查询吞吐量。
ElasticSearch推荐的最大JVM堆空间是30~32G, 所以把分片最大容量限制为30GB, 然后再对分片数量做合理估算. 例如, 你的数据能达到200GB, 我们推荐你最多分配7到8个分片.
查询分页
size+from浅分页
当Elasticsearch响应请求时,它必须确定docs的顺序,排列响应结果。如果请求的页数较少(假设每页10个docs), Elasticsearch不会有什么问题,但是如果页数较大时,比如请求第100页,Elasticsearch不得不取出第1页到第100页的所有docs,再去除第1页到第99页的docs,得到第100页的docs。
scroll深分页
相对于from和size的分页来说,使用scroll可以模拟一个传统数据的游标,记录当前读取的文档信息位置。这个分页的用法,不是为了实时查询数据,而是为了一次性查询大量的数据(甚至是全部的数据)。
因为这个scroll相当于维护了一份当前索引段的快照信息,这个快照信息是你执行这个scroll查询时的快照。在这个查询后的任何新索引进来的数据,都不会在这个快照中查询到。但是它相对于from和size,不是查询所有数据然后剔除不要的部分,而是记录一个读取的位置,保证下一次快速继续读取。
from+size方式以及scroll方式优缺点对比:
1)对于from+size方式:当结果足够大的时候,查询页码越大,会大大加大内存和CPU的消耗。但该方式使用非常方便,可以任意跳页。所以这种分页方式需要做一些限制,比如只能查询前100页等
2)对于scroll方式: 当结果足够大的时候, scroll 性能要比from+size效率高很多。但是只能下一页 下一页的返回数据,不能跳页。类似微博或者新闻app往下滑刷新内容的应用场景还是非常不错的,但scroll的缓存时间设置不宜过长,占内存。
因为我的业务数据量左右,所以我用的scroll的方式,每次返回10条记录,使用者根据需求点击获取更多数据,效果还是非常不错的。
高亮对比
通过论坛中网友的建议来看,都推荐对于大文件高亮使用: fast-vector-highlighter。
Plain highlighter
ES默认的配置方式,官网明确说明该方式匹配慢,如果出现性能问题,请考虑其他高亮方式。
Postings highlighter
支持postings高亮方式,需要在mapping下添加如下信息:
"type": "text",
"index_options" : "offsets"
posting高亮方式的特点:
1)速度快,不需要对高亮的文档再分析。文档越大,获得越高 性能 。
2)比fvh高亮方式需要的磁盘空间少。
3)将text文件分割成语句并对其高亮处理。对于自然语言发挥作用明显,但对于html则不然。
4)将文档视为整个语料库,并 使用BM25算法 为该语料库中的文档打分。
PUT /example
{
"mappings": {
"doc" : {
"properties": {
"comment" : {
"type": "text",
"index_options" : "offsets"
}
}
}
}
}
Fast vector highlighter
如果在mapping中的text类型字段下添加了如下信息:
"type": "text","term_vector" : "with_positions_offsets"
fvh高亮方式的特点如下:
1)当文件>1MB(大文件)时候,尤其适合fvh高亮方式。
2)自定义为 boundary_scanner的扫描方式。
3) 设定了 term_vector to with_positions_offsets会增加索引的大小。
4)能联合多字段匹配返回一个结果,详见matched_fields。
5)对于不同的匹配类型分配不同的权重,如:pharse匹配比term匹配高。
因为我的业务场景是对HTML文件进行多词匹配,文件很多都是大于1M,用ES默认的Plain highlighter,所以平均搜索时间都在5秒以上,复杂的可能需要20S以上。
将services.banner字段修改为f’vh后,搜索效率大大提升,即使是复杂的搜索也在毫秒级。
{
"mappings": {
"doc": {
"properties": {
"services.banner": {
"type": "text",
"term_vector": "with_positions_offsets"
}
}
}
}
}
参考链接:
https://qbox.io/blog/optimizing-elasticsearch-how-many-shards-per-index.
http://doc.codingdict.com/elasticsearch/106/.
https://cloud.tencent.com/developer/article/1066368.