干货 | Elasticsearch通用优化建议
1、题记
Elasticsearch开发实战的后期会遇到性能问题,包括:创建索引性能、写入数据性能、检索性能等。网上有很多结合自己实际应用场景的相关优化建议,但“对症下药”才是关键。
实际,官网已经有非常明确的相关优化建议。如果没有实战场景,一些特性的理解可能不到位。为此,我特定将官网建议做了翻译,并加了结合实战开发的通俗理解注释。
此为第一篇:通用优化一般建议。
后续会跟进索引优化、写入优化、检索优化、性能优化篇。
2、认知前提
为更好的理解优化建议,特将文中多次提及的核心概念做了提炼:
2.1 doc values
相比于倒排索引(通过关键词查找文档),doc values可以直接理解为“正排索引”(通过文档,查找关键词)。
doc values应用场景:
1)针对某field的排序(sort);
2)针对某field的聚合(aggregation);
3)特定的过滤(举例:geo 过滤)
4)针对特定字段的script操作。
2.2 norms
norm是索引的评分因子。 如果您不关心评分,例如,如果您从未按分数对文档进行排序,则可以禁用在索引中存储这些评分因子并节省一些空间。
禁用方法:
PUT index
{
"mappings": {
"type": {
"properties": {
"foo": {
"type": "text",
"norms": false
}
}
}
}
}
3、建议1:不要返回大结果数据集
Elasticsearch被设计为搜索引擎,这使得它非常擅长获取与查询匹配的排名靠前的Top文档。 但是,它对于属于数据库域的工作负载来说并不好,例如检索与特定查询匹配的所有文档。 如果需要检索全部文档,请确保使用Scroll API。
【注解】
1)业务开发中,我们有时候需要返回分页查询数据,建议使用from+size分页实现;
2)如果需要返回全量数据,建议使用scroll实现。
4、建议2:避免使用大文件
鉴于默认的http.max_context_length设置为100MB,Elasticsearch将拒绝索引任何大于该文档的文档。您可能决定增加该特定设置,但Lucene仍然有大约2GB的限制。
即使不考虑硬性指标限制,大型文档通常也不实用。大型文档对网络,内存使用和磁盘施加更多压力,即使对于不请求_source的搜索请求也是如此,因为Elasticsearch需要在所有情况下获取文档的_id,并且对于大型文档而言,获取此字段的成本更高(归因于文件系统缓存工作)。
索引大文档将使用数倍于原始文档大小的内存,全文搜索(例如match_phrase短语查询)和高亮显示也变得更占据内存呢、更耗时,因为它们的成本直接取决于原始文档的大小。
有时候需要重新考虑信息单元什么时候是有用的。例如,您想要对图书做全文检索,并不一定意味着一个文档(document)对应一整本书。将章节甚至段落用作document可能是一个更好的主意,然后在这些文档中有一个属性来标识它们所属的书。
这不仅避免了大文档的问题,也使搜索体验更好。例如,如果用户搜索两个单词foo和bar,则不同章节之间的匹配可能非常差,而同一段落中的匹配可能很好。
【注解】
平时的业务场景可能遇不到单文档几百MB甚至几GB的场景,但是,在有些知识库全文检索的业务中,可能遇到《康熙字典》等类似大文档或其他网络采集大文档数据的检索。需要两点注意:
1)导入ES前,按照章节或者页码进行拆分;
2)设计ES Mapping的时候,采用fvh的高亮模式。
推荐阅读:Elasticsearch大文件检索性能提升20倍实践(干货)
5、建议3:避免稀疏性
Lucene背后的数据结构,也是Elasticsearch依赖的索引和存储数据,最适合密集数据。举例:当所有文件都有相同的字段时,对于启用了norms(默认情况下是text文本字段的情况)或启用了doc vlaue(默认情况下是数字,日期,IP和关键字的情况),尤其如此。
原因是Lucene在内部识别带有所谓docID的文档,这些docId是介于0和索引中的文档总数之间的整数。这些doc ids用于Lucene的内部API之间的通信:例如,对某个单元有matchquery的单元上搜索会生成一连串的doc ids,然后这些doc ids用于检索norm的值以便计算对于这些文档进行评分。
当前实现此norm查找的方式是为每个文档保留一个字节。然后,可以通过读取索引doc_id处的字节来检索给定doc id的标准值。虽然这非常有效并且有助于Lucene快速访问每个文档的标准值,但这样做的缺点是没有值的文档也需要一个字节的存储空间。
请注意,即使稀疏性最显着的影响是存储要求,它也会对索引速度和搜索速度产生影响,因为没有字段的文档的这些字节仍需要在索引时写入并在搜索时花费时间。
在索引中包含少数稀疏字段是完全没问题的。 但要注意,如果稀疏性成为规则而不是异常,那么索引将不会像它那样有效。
本节主要关注norms 和doc values,因为这些是受稀疏性影响最大的两个特征。 稀疏性也影响倒排索引(用于索引text/keyword字段)和维度点(用于索引geo_point和numerics类型)的效率,但程度较小。
以下是一些有助于避免稀疏性的建议:
5.1避免将不相关的数据放在同一个索引
您应该避免将具有完全不同结构的文档放入同一索引中以避免稀疏性。 将这些文档放入不同的索引通常会更好,您还可以考虑为这些较小的索引提供较少的分片,因为它们总体上包含的文档较少。
请注意,此建议不适用于您需要在文档之间使用父/子关系的情况,因为此功能仅在位于同一索引中的文档上受支持。
5.2规范化文档结构
即使你真的需要在同一个索引中放入不同类型的文档,也许有机会减少稀疏性。 例如,如果索引中的所有文档都有一个时间戳字段,但有些文档称之为timestamp,而其他文档称之为creation_date,则有助于重命名它,以便所有文档对同一数据具有相同的字段名称。
5.3避免使用多types
类型可能听起来像是在单个索引中存储多种类型数据(意译)的好方法。 其实它们不是!假设types将所有内容存储在单个索引中,基于上述稀疏性的讨论,在单个索引中具有不同字段的多个类型会有问题。
如果您的type没有非常相似的Mappings,您可能需要考虑将它们移动到专用索引。
5.4在稀疏字段上禁用norms和doc_values
如果上述建议均不适用于您的情况,您可能需要检查在稀疏字段中是否确实需要norms和doc_values。 如果在字段上不需要生成计算分数,则可以禁用norms,对于仅用于过滤的字段通常也是如此。 可以在既不用于排序也不用于聚合的字段上禁用doc_values。 请注意,不应轻易做出这个决定,因为这些参数不能在实时索引上更改,因此如果您意识到需要norms或doc_values,则必须重新reindex索引。
【注解】
1)6.X以后就不存在一个索引多个type了,一个索引下只有唯一的type了。所以:5.X版本之前的多type要变成多索引。2)创建索引的时候,Mapping的设计非常重要,各个字段的细分设计一方面决定了存储,另一方面:不同字段类型的设计会对性能产生非常重要的影响。
官网地址:http://t.cn/Rkc3uuw
6、小结
性能问题排查非一朝一夕之功,唯赖于:对核心细节问题点滴的深耕和死磕!
文章转载自公众号:铭毅天下Elasticsearch