[翻译]Elasticsearch重要文章之五:预加载fielddata
Elasticsearch 是默认延迟加载fielddata到内存里的。当elasticsearch第一次遇到一个查询需要一个指定field的fielddata的时候,就会把索引的每个段中整个field加载到内存。对于小段,这是个可以忽略不计的时间,但是如果你有一些5G大小的段并且需要加载10GB的fielddata到内存里,这个过程需要数十秒,习惯于秒内响应时间的用户会被网突如其来的迟钝所打击。 有三种方法应对这种延迟尖峰: Eagerly load fielddata(饿汉式(预)加载fielddata) Eagerly load global ordinals(饿汉式(预)加载全局序数) Prepopulate caches with warmers (使用warmer提前加载缓存)。 所有这些都是一个意思:预先加载fielddata到内存里,这样当用户需要执行一个搜索的时候就感受不到延迟了。 饿汉式(预)加载fielddata 首先是预先加载(而不是默认的延迟加载),当一个新的段形成时(无乱是刷新,写入或者是合并),可以预先加载的field会提前把段的fielddata加载到内存里,在这段可以用于搜索之前。 这意味着当你第一次查询的时候,如果碰到在这个段上,你不需要再触发加载fielddata的操作,它们已经在内存中了,这会防止你的用户遇到一些冷到缓存而发生延迟尖峰。 预先加载是基于每个field的,所以你可以控制哪些field进行预加载。 PUT /music/_mapping/_song { "price_usd": { "type": "integer", "fielddata": { "loading" : "eager" } } } 备注: 通过设置fielddata.loading: eager,告诉elasticsearch预先加载这个field的内容到内存里。 fielddata的加载可以设置成饿汉模式(预先加载)还是懒惰模式(延迟加载),使用update-mapping的api。 预先加载是简单对fielddata加载的开销的转移,从查询时间转义到刷新时刻。 大段的刷新时间会比小段的时间长,通常大段的产生都是由哪些已经可搜素的小段合并而来的,所以慢一点的刷新时间不是那么重要(译者注:意思是大段的刷新时间长不影响你的搜索,在大段合并成前的小段可以用于搜索)。 全局序数 其中一项用于减少string类型的fielddata占用内存的技术叫做序数。 假设我们有十亿条文档,每个文档都有一个status的field,只有三个值:status_pending, status_published, status_deleted,如果我们把所有的status加载到内存里,每个文档需要14-16byte,也就是说15GB 相反,我们可以确认这三个特殊的字符串,对他们排序,依次编号0,1,2 Ordinal | Term ------------------- 0 | status_deleted 1 | status_pending 2 | status_published 序号对应的字符串值要在序号列表中存储一次,每个文档只要使用他们的编号来表示他们所包含的值就可以了。 Doc | Ordinal ------------------------- 0 | 1 # pending 1 | 1 # pending 2 | 2 # published 3 | 0 # deleted 这个可以把15GB的内存占用减少到小于1GB ...