通用建议
- 不要返回太大的结果集。Es 作为一个搜索引擎,非常擅长返回一定条件下的 Top N 条文档,而不太擅长返回所有文档,如果需要返回所有文档,请使用 scroll api 方式。
- 避免存储太大的文档。Es 默认最大的文档大小是 100MB,最大可设置为大约 2GB。即使不考虑这个硬性限制,也不应该存储太大的文档,过大的文档会给网络,内存,磁盘造成更大的压力,同时过大的文档对搜索,高亮等操作都会变得更昂贵。所以,应该在数据建模时要有更严谨的思考,例如对书籍进行搜索的场景,并不需要持久化整本书的内容,而只需要章节和某些段落就可以满足需求了。
提高索引效率
- 使用多进程或多线程发送数据到Elasticsearch。为了更好地利用集群的资源,应该使用多线程或多进程来发送数据(bulk请求),提升数据处理效率。可以逐步增加线程数量直至到集群中的机器Load或CPU饱和。
建议使用“nodes stats”接口查看节点中的cpu和load状态,您可以通过“os.cpu.percent”、“os.cpu.load_average.1m”、“os.cpu.load_average.5m”和“os.cpu.load_average.15m”参数信息了解详细信息。“nodes stats”接口的使用指导和参数解释请参见:www.elastic.co/guide/en/el…
- 增加refresh_interval刷新的间隔时间。默认情况下,每个分片每秒自动刷新一次。如果不需要近实时搜索,可以通过设置降低每个索引的刷新频率。
PUT /my_logs
{
"settings": {
"refresh_interval": "30s"
}
}
- 在初始化索引时,可以禁用refresh和replicas数量。如果需要一次导入较大数据量的数据进index里面时,可以先禁用refresh,把“refresh_interval”设置成为“-1”,把“number_of_replicas”设置成“0”。当数据导入完成后,将refresh_interval和number_of_replicas设置回原来的值。
选择合适的分片数和副本数
默认分片数为5,副本数为1。
分片数,与检索速度非常相关的的指标,如果分片数过少或过多都会导致检索比较慢。分片数过多会导致检索时打开比较多的文件,且会导致多台服务器之间通讯慢。而分片数过少会导致单个分片索引过大,所以检索速度慢。
根据机器数、磁盘数、索引大小等设置分片数,建议单个分片不要超过30GB。总数据量除以分片数,则为分片的大小。
提高查询效率
- 避免不同的type放在同一个index,7.0版本以后弃用type。
- 按照时间范围创建索引的场景,按年、月、天来创建索引
- 扩容的时候根据当前数据量选择合适的shard和Replica,从而可以避免在一开始设置一个很大的shard来考虑扩容的情况。
- 利用alias机制可以在索引间灵活切换。
- 针对不再更新的索引,如上周或者上月的索引,进行索引优化以提高查询效率。将索引下多个小segment合并成一个大的分片,以提高查询效率。
- 分词字段(text类型)的聚合统计不是一种常见的需求。在Elasticsearch对于分词字段的聚合统计需要用到fielddata,默认是禁用的,开启fielddata会带来较大的内存负担。建议的做法是分词字符串进行多字段映射,映射为一个text字段用于全文检索,和一个keyword字段用于聚合统计。
- 用过滤提高查询效率。过滤器的执行速度非常快,不会计算相关度(直接跳过了整个评分阶段),而且很容易被缓存。所以我们会使用constant_score查询以非评分模式来执行term查询并以一作为统一评分。
GET /my_store/products/_search
{
"query" : {
"constant_score" : {
"filter" : {
"term" : {
"city" : "London"
}
}
}
}
}
-
避免深度翻页,推荐采用scroll查询返回大量数据。
-
分配更多的内存到文件系统缓存。为了提高查询效率,Elasticsearch深度依赖文件系统缓存,一般情况下,保证至少有一半的可用内存分配到文件系统缓存,以便 Elasticsearch 可以将索引的热点区域保留在内存里。
-
使用更好的硬件。
-
文档建模。正确的模型可以减少搜索时间,尽量避免 join ,nested 会使查询效率降低几倍,parent-child 会使查询效率降低几百倍。
-
提前索引数据。比如说,文档里有一个 price 字段,而该字段经常用在固定区间的 range 聚合,那么可以在索引阶段增加一个keyword类型字段 price_range ,用于表示固定区间,改使用 terms 聚合,可以提高聚合效率。
-
考虑映射标识符类型为keyword。range聚合对数值类型字段更优,而 terms 聚合对 keyword 类型字段更优。当字段值为数值,但基本不使用range聚合(例如一些数字标识符比如 ISBN)时,可以考虑使用 keyword 而不是 integer 或 long。
-
避免使用脚本。如果实在需要使用 scripts,应该使用 painless 或 expressions 引擎。
-
使用日期时间进行搜索时尽量不要使用 now ,因为这种查询方式是不会被缓存的。而应该 rounded date,这种查询方式可以更好地利用到查询缓存。具体示例:www.elastic.co/guide/en/el…
-
合并只读索引的segment。更多关于合并的操作可以查看:www.elastic.co/guide/en/el…
-
预热 Global ordinals。Global ordinals是对keyword类型字段进行terms聚合时使用的一种数据结构。默认情况下是延迟加载到内存里的,我们可以在mapping里设置在refresh-time时提前加载。
PUT index
{
"mappings": {
"_doc": {
"properties": {
"foo": {
"type": "keyword",
"eager_global_ordinals": true
}
}
}
}
}
- 预热文件系统缓存。www.elastic.co/guide/en/el…
- 使用 index sorting 来提高获取 Top N 场景的效率。Segment 里的文档可以指定按照某个字段排序,此时写数据时会有轻微的性能影响,默认没有排序。当获取 Top N 文档时,可以提前终止搜索来调高查询效率。详情:www.elastic.co/guide/en/el…
- 使用 preference 来提高缓存的利用率。es使用了多钟缓存来提高查询性能,例如文件系统缓存,查询缓存等。然而这些缓存都是保存到节点本地而已,所以当相同的请求多次请求时,由于默认的路由策略是轮询,导致这些请求不一定会在同一节点处理,从而不能很好的利用到缓存。比如说某些场景下,同一用户的多次请求是相似的,这时可以就可以使用 preference 来帮助优化缓存的利用率了。www.elastic.co/guide/en/el…
- 打开 adaptive replica selection。轮询路由策略外的另一种路由策略,该策略会基于一系列的标准来挑选副本,例如响应时间,服务时间,队列长度。www.elastic.co/guide/en/el…
PUT /_cluster/settings
{
"transient": {
"cluster.routing.use_adaptive_replica_selection": true
}
}
- 优化副本分片数。副本可以增大吞吐量,但是不是越多越好,因为一个节点上多个分片(通常一个节点会同时存在主分片和副分片)之间会竞争资源,例如文件系统缓存,反而会影响性能,但是为了保证可用性,必须设置副本。为了权衡可用性和吞吐量,假设共有 num_nodes 节点数,num_primaries 主分片数,最多允许 max_failures 宕机节点同时宕机,这时推荐的副本数为 max(max_failures, ceil(num_nodes / num_primaries) - 1)
- 使用路由机制,将同一索引内的具有相同特征(比如具有相同的userid)的文档全部存储于一个节点上,这样我们之后的查询都可以直接定位到这个节点上,而不用将查询广播到所有的节点上。