提高Index速度

  1. 写入的DOC体积不要太大,阈值上限是100M
  2. 被删除的数据,还没有进行merge时,仅仅是在内存中有个标识,此时这些在segment里的数据会影响评分,他们是分母的一部分
    所以如果一个请求多次路由向不同的副本,可能会导致数据的评分不同,也就是从分片获取的数据在最终协调后不一致
  3. 小数据多批次情形下建议使用bulk请求,每个bulk请求体多大可以通过压测得出,一般建议不要超过5M。当bulk请求较多时要降低频率,避免对服务器造成太大压力
  4. 太多线程同时发送请求时,如果ES服务端返回429,表示Server忙不过来了, 拒绝请求,等一会儿再发送
  5. 加载大量数据时,可以将刷新间隔设置为-1,以及将副本数设置为0。虽然说这样在你加大数据的过程中,可能会导致数据丢失,
    但是会加快你加载数据的速度。在加载完之后,可以重新调整刷新频率以及副本数
  6. 禁止使用swapping。
  7. 至少要将机器的一半内存给文件缓存。
  8. 尽量使用自增id因为如果不使用自增的话,es需要先去判断这个id是否存在。如果使用自增,就会跳过这个过程,能够加快你Index速度。
  9. 尽量使用存储效率更高的磁盘,比如ssd 或者是raid 。
  10. 当有繁重的索引任务时,请调高index buffer size 的大小,默认是10%,这个值至少需要512兆

提高Search速度

  1. ES重度依赖文件系统缓存,至少确保一半的内存给系统缓存,使ES将热点数据始终缓存在物理内存中
  2. 使用更快的磁盘,比如SSD;尽量使用本地存储,避免使用远程存储比如NFS,SMB;如果你的搜索是一个CPU亲和形式,那么可以考虑购买性能更好的CPU
  3. 文档建模,joins必须禁止;nested会导致查询时速度慢好几倍; parent-child关系会导致查询慢上百倍
  4. 当检索的field比较多时,可以考虑使用copy to把它们合成一个大的属性,然后检索这个属性就可以了。这样能提高你的检索效率。
  5. 尽量避免使用脚本,如果真要使用则用painless脚本
  6. 当filter里有时间类型的字段时,如果用now的话,因为当前时间是不断变化的,所以结果不会放入filter,后续相同时间查询时filter不会生效,通过将now转换成分钟制,也就是分钟,抹去秒
“my_date”: {
 “gte”: “now-1h/m”,
 “lte”: “now/m”
 }

  1. 假设 now = 16:31:29,这样得到的字段实际是 between 15:31:00 and 16:31:59 就能使用filter特性
  2. 强制merge只读索引,将其segments 合并为1,通常用在基于时间滚动生成的索引
  3. 预热全局顺序,“eager_global_ordinals”: true, 全局顺序是什么可以参考:
  4. filesystem cache预热, 当集群重启时系统缓存不存在,可通过index.store.preload预先缓存,提高后续操作效率
  5. 使用Index sorting加快排序检索
  6. 数字类型数据不一定要定义成numeric,比如integer,long,数字类型在range query 时效率高,但terms时效率没有keyword高,
    所以如果数据不需要range query,则不要定义成integer,long等numeric类型
  7. 每个索引的分片上有filesystem cache, request cache, query cache 等缓存,如果同一次查询路由向一个shard的不同replica,
    则这些缓存都不会发生作用,也就是说同一份数据会占用多个node的内存空间,且查询会变慢,所以建议同一个查询条件使用相同的preference ,确保他们路由向相同的replica
  8. 多replica很多时候能够提高吞吐量,但不是一定的。当node数固定,index和replica越多,每个shard的filesystem cache 就越少,
    而这个是制约es高性能的最重要的因素,没有之一,所以当node数固定时,针对index数量设置合适的replica数量很重要。
    replica_num = max(max_failures, ceil(num_nodes / num_primaries) - 1). max_failures表示能同一时间接受的最大宕机node的数量,
    num_nodes表示节点数,num_primaries表示分片数
  9. 使用 index_prefixes 来对term的前缀查询做快速支持
  10. 不要返回大量的数据,如果数据量大,使用scroll形式分页

优化磁盘使用

  1. 如果field不被检索,那么可以设置"index": false;
  2. 如果text类型的字段不需要打分,那么可以设置"norms": false;
  3. text类型字段默认存储doc,frequencies ,positions , 如果此field没有pharse query, 那么可以设置"index_options": “freqs”, 忽略positions
  4. 不要使用默认的dynamic string mappings,就是新字段的索引规则,可以使用 dynamic_templates 定义,比如以
  5. 关注每个Index 的 Shard大小,如果Shard占用的内存空间太小,那么可以使用Shrink API 适当调低分片数量,因为大分片对存储数据更有效
  6. 禁用_source, 也就是禁用原始的JSON Body, JSON Body是多个Field之间关联的纽带,比如可以通过Field A 的倒排索引,定位doc_id,然后通过doc_id 查询到_source,body里含有其他的Field。如果我们仅仅需要检索的Field,而不需要其他的Filed, 那么禁用_source能降低系统缓存占用
  7. Force Merge 只读索引的Segments, 设置 max_num_segments=1, 这样能降低系统存储
  8. 使用最小化的数值类型,如果是整数,定义顺序:byte, short, integer or long, 如果是浮点数,定义顺序:half_float,float,double
  9. 使用Index Sorting 对document做排序,有序document下他们可能具有相似的数据结构,fields和values,这样Lucene在存储时能提高压缩比例