一、内存文件系统足够的缓存
Elasticsearch严重依赖于文件系统缓存,以加快搜索速度。通常,您应确保至少有一半的可用内存分配给文件系统缓存,以便Elasticsearch可以将索引的热区保留在物理内存中。
二、使用更快的硬件
如果搜索是受CPU限制的,那就加大CPU。ES对CPU的要求,使用多核CPU优于单核CPU。
如果搜索是在I/O上受限制的话,就需要提供更多的内存和更快的硬盘。SSD硬盘性能优于机械硬盘,本地硬盘性能优于远程虚拟硬盘。
三、文档建模设计
文档应该建模设计,是搜索尽可能的快。避免使用 nested(慢几倍)和父子关系(慢百倍),可以通过对文档进行非规范化的建模设计来达到相同的目的,解决问题。
四、搜索尽可能少的字段
query_string
或 multi_match
查询目标的字段越多,它的速度就越慢。
五、预索引数据
您应该利用查询中的模式来优化数据索引的方式。例如:你有一个类型的文档所有文档都包含一个字段 price
,并且你大多数查询的时候都是使用比较固定的大小范围查询或者聚合,此时如果把这个时间分为预索引到文档中,并且使用terms
聚合查询会更快。
例如,你有一类型的数据如下
PUT index/_doc/1
{
"designation": "spoon",
"price": 13
}
并且你搜索的时候经常使用以下范围查询
GET index/_search
{
"aggs": {
"price_ranges": {
"range": {
"field": "price",
"ranges": [
{ "to": 10 },
{ "from": 10, "to": 100 },
{ "from": 100 }
]
}
}
}
}
此时你就应该在文档索引时添加一个price_range
字段,并且映射成keyword类型的
PUT index
{
"mappings": {
"_doc": {
"properties": {
"price_range": {
"type": "keyword"
}
}
}
}
}
PUT index/_doc/1
{
"designation": "spoon",
"price": 13,
"price_range": "10-100"
}
然后查询、聚合的时候就使用这个新的字段来代替price
的range
聚合
GET index/_search
{
"aggs": {
"price_ranges": {
"terms": {
"field": "price_range"
}
}
}
}
六、将标识符映射为keyword类型
有些字段虽然是数字类型的,但是实际上并不是都要映射为数字类型。ES能够通过数字类型优化range
查询,但是terms
查询使用keyword
更适合。一般的像ISBN(国际标准书号)这样的标识符(ID)都是适合映射为keyword
而不是数字的。
七、避免使用脚本
通常,应避免使用脚本。如果绝对需要它们,则应首选painless和expressions引擎。
八、搜索舍入日期
对日期字段的查询now
通常是不可缓存的,因为匹配一直是在变化的。但是,就用户体验而言,切换到舍入日期通常是可以接受的,并且具有更好地利用查询缓存的好处。
例如下面的查询
PUT index/_doc/1
{
"my_date": "2016-05-11T16:30:55.328Z"
}
GET index/_search
{
"query": {
"constant_score": {
"filter": {
"range": {
"my_date": {
"gte": "now-1h",
"lte": "now"
}
}
}
}
}
}
可以使用下面的查询代替
GET index/_search
{
"query": {
"constant_score": {
"filter": {
"range": {
"my_date": {
"gte": "now-1h/m",
"lte": "now/m"
}
}
}
}
}
}
在这种情况下,我们四舍五入为分钟,因此,如果当前时间为16:31:29
,则范围查询将匹配my_date
字段值介于15:31:00
和16:31:59
之间的所有内容。而且,如果多个用户在同一分钟内运行包含此范围的查询,则查询缓存可以帮助加快速度。用于舍入的时间间隔越长,查询缓存可以提供的帮助越多,但是请注意,过于激进的舍入也会损害用户体验。
九、强制合并只读索引
只读的索引将从合并到单个段中受益 。对于基于时间的索引,通常是这种情况:只有当前时间范围的索引才能获取新文档,而较旧的索引则为只读。
提示
不要合并正在写入的索引。
十、预热全局序数词
全局序数词是一种数据结构,用于在keyword
字段上运行terms
聚合 。它们被延迟加载到内存中,因为Elasticsearch不知道terms
聚合中将使用哪些字段,而哪些字段则不会。您可以通过如下所述配置映射,让Elasticsearch在刷新时紧急加载全局序数词:
PUT index
{
"mappings": {
"_doc": {
"properties": {
"foo": {
"type": "keyword",
"eager_global_ordinals": true
}
}
}
}
}
十一、预热文件缓存系统
如果重新启动运行Elasticsearch的计算机,则文件系统缓存将为空,因此,操作系统需要一些时间才能将索引的热区加载到内存中,以便快速进行搜索操作。您可以使用该index.store.preload
设置明确告诉操作系统哪些文件应该急切地加载到内存中,具体取决于文件扩展名 。
十二、使用索引排序来加快连接的
索引排序可能有用,以便使连接更快,但以稍微慢一些的索引为代价。在索引排序文档中阅读有关它的更多信息。
十三、使用preference以优化缓存利用率
有多个可以帮助提高搜索性能的缓存,例如 文件系统缓存, 请求缓存或查询缓存。但是所有这些缓存都在节点级别维护,这意味着如果您连续两次运行相同的请求,具有一个或多个副本,并使用默认路由算法round-robin,则这两个请求将转到不同的分片副本,从而阻止了节点级缓存的帮助。
由于搜索应用程序的用户通常会依次运行类似的请求(例如为了分析索引的较窄子集),因此使用标识当前用户或会话的首选项值可以帮助优化缓存的使用。
十四、副本可能有助于提高吞吐量,但并非总是可以
除了提高弹性之外,副本还可以帮助提高吞吐量。例如,如果您有一个单碎片索引和三个节点,则需要将副本数设置为2,以便总共拥有3个碎片副本,以便利用所有节点。
现在,假设您有一个2碎片索引和两个节点。在一种情况下,副本数为0,这意味着每个节点都拥有一个分片。在第二种情况下,副本数为1,这意味着每个节点都有两个分片。哪种设置在搜索效果方面效果最好?通常,每个节点的分片总数较少的设置会更好地执行。这样做的原因是,它为每个分片提供了更多的可用文件系统缓存份额,并且文件系统缓存可能是Elasticsearch的第一性能因素。同时,请注意,在单节点故障的情况下,没有副本的安装会失败,因此在吞吐量和可用性之间要进行权衡。
那么正确的副本数是多少?如果您的集群中有num_nodes节点,则总共有 num_primaries主要分片,并且如果您希望max_failures一次最多能处理节点故障,那么适合您的副本数是 max(max_failures, ceil(num_nodes / num_primaries) - 1)。
十五、打开自适应副本选择
当存在多个数据副本时,elasticsearch可以使用一组称为自适应副本选择的条件来根据响应时间,服务时间和包含每个碎片副本的节点的队列大小来选择最佳数据副本。这可以提高查询吞吐量并减少大量搜索应用程序的延迟。