Elasticsearch优化手段

ES 的默认配置已经提供了良好的开箱即用的体验,但是仍有一些优化手段去继续提升它的使用性能。

General recommendations

通用建议。

01

Don't return large result sets

不要返回大量的结果集。ES 是一个搜索引擎,擅长于返回匹配度较高的几个文档(默认 10 个,取决于 size 参数),而不擅长于数据库领域的工作,例如返回一个查询条件匹配的所有文档,如果你一定要实现这个功能,建议使用 scroll API。

这个问题其实是与深度分页相关联的,ES 中的配置项 index.max_result_window 默认是 10000 ,这就是说最多只支持返回前一万条数据,如果想返回更多的数据,一方面可以增大此配置项,另一方面就是使用 scroll API ,scroll API 的原理就是记录上一次的结果标记,基于此标记再继续往下查询。

02

Avoid large documents

避免大文档。配置项 http.max_content_length 默认是 100 MB,ES 将会拒绝索引超过此大小的文档,你也可以提高这项配置,但是最大不得超过 2 GB,因为 Lucene 的限制为 2 GB。

大文档会给网络、内存、磁盘、文件系统缓存等带来更大的压力。

为了解决这个问题,我们需要重新考虑信息的基本单元,例如想要去索引一本书的内容,这并不意味着我们要把整本书都塞进一个文档中去,按照章节或者段落去划分文档显然是更好的选择。

Recipes

解决一些常见问题的方式。

01

Mixing exact search with stemming

精确搜索混合词干搜索。

在英文场景下,词干搜索如 skiing 将会匹配包含有 ski 或 skis 的文档,但是如果用户想要实现 skiing 的精确匹配呢?最典型的解决方法就是将同样的内容索引为 multi-field 多个不同的字段,这样就能在不同的字段上分别使用词干搜索和精确搜索了。

除此之外,query_string 和 simple_query_string 的 quote_field_suffix 也可以解决这种问题。

02

Getting consistent scoring

1、Scores are not reproducible

即使同样的查询同时执行两次,文档的匹配分数也并不一致。这是因为副本存在的原因,副本的配置项是 index.number_of_replicas ,ES 进行查询时会以 round-robin 的方式轮询到不同的 shard 分片,而删除或更新文档时(在 ES 中,更新分为两步,第一步标记旧文档为删除,第二步写入新文档),旧文档并不会立刻被删除,而是等待下一个 refresh 周期此文档从属的 segment (shard 分片会被分割为多个 segment)被合并,有时候主分片刚刚完成合并操作并移除了大量标记为删除的文档,而从分片还未来得及同步此项操作,这就导致了主从索引统计信息的不同,也就影响到了匹配分数的不同。

解决方法是在查询时使用 preference 参数,此参数决定了将查询路由到哪个分片中去执行,只要 preference 一致则一定会使用相同的分片。例如你可以使用用户ID 或者 session id 作为 preference ,这样就能保证同一个用户或者同一个会话查询的一致性。

2、Relevancy looks wrong

如果你注意到两个相同内容文档的分数不同或者精确匹配的未排序在第一位,这也可能与分片有关。默认情况下,每个分片各自评分,文档也会被均匀的路由到不同的分片中,分片中的索引统计信息也会是相似的,评分将按照预期工作,但是如果你进行了下列操作之一,那么很有可能搜索请求涉及到的分片没有类似的索引统计信息,相关性可能很差:

  • use routing at index time (索引时自定义路由规则导致分片不均匀)
  • query multiple indices (查询跨越了多个索引)
  • have too little data in your index (数据量少得可怜)

如果你的数据集很小,那么最简单的方法就是只使用一个分片( index.number_of_shards : 1 )。

其余情况建议的方式是使用 dfs_query_then_fetch 搜索类型,这种方式将会查询所有关联分片的索引统计信息然后合并,这样评分时使用的就是全局的索引统计信息而不是某个分片的,显然这样增加了额外的成本,然而大多数情况下,这些额外成本是很低廉的,但是如果查询中包含有大量的 fields/terms 或 fuzzy 模糊查询,增加的额外成本可能并不低。

Tune for indexing speed

加速构建索引。

01

Use bulk requests

尽量使用 bulk 请求。

02

Use multiple workers/threads to send data to ES

其实就是提高客户端的并发数。

03

Increase the refresh interval

配置项 index.refresh_interval 默认是 1s ,这个时间指的是创建新 segment 合并旧 segment 的周期,增加此间隔时间有助于减轻 segment 合并的压力。

04

Disable refresh and replicas for initial loads

禁用 refresh 和备份可以提升不少的索引构建速度,但是正常情况下 refresh 和备份都是必须的,所以一般只在初始化导入数据如重建索引等特殊情况才使用。配置项为 index.refresh_interval : -1 和 index_number_of_repicas : 0 。

05

Disable swapping

禁用宿主机操作系统的 swap 。

06

Give memory to the filesystem cache

将宿主机至少一半的内存分配给 filesystem cache 文件系统缓存。

07

Use auto-generated ids

使用用户自定义的文档 id ,ES 将会检查其是否冲突,而使用 ES 自动生成的 id 则会跳过此步骤。

08

Use faster hardware

使用更好的硬件。

09

Indexing buffer size

确保 indices.memory.index_buffer_size 足够大,能为每个分片提供最大 512 MB 的索引缓冲区,超过这个值也不会有更高的性能。默认是 10%,即 JVM 有 10 GB 内存,那么 1 GB 将会用于索引缓存。

10

Disable _field_names

在 mapping 设置中禁用 _field_names ,但会导致 exists 查询无法使用。

11

Additional optimizations

其余一些额外的优化项与下文中的 Tune for disk usage 优化磁盘使用相关联。

Tune for search speed

加速搜索。

01

Give memory to the filesystem cache

给 filesystem cache 分配更多内存。

02

Use faster hardware

使用更好的硬件。

03

Document modeling

文档模块化,避免 join 操作,nested 和 parent-child 关联查询都会比较慢。

04

Search as few fields as possible

在 query_string 和 multi-match 查询中,fields 越多查询越慢。你可以新增一个联合字段,在 mapping 中设置 copy_to 将多个 fields 字段自动复制到这个联合 field 字段中,这样就能把多字段查询变为单字段查询。

05

Pre-index data

预索引数据。在进行 range aggregation 范围聚合查询时,我们可以新增一个字段以在索引时标记其范围,这样 range aggregation 就变成了 term aggregation 。例如,要查询 price 在 10-100 范围内的文档数据,那么可以在构建索引时新增一个 price_range 字段标记此文档为 10-100 ,这样就可以直接根据 price_range 进行查询了。

06

Consider mapping identifiers as keyword

数字不一定要映射为数字类型字段,也可以是 keyword ,索引数字类型对于 range 查询进行了优化,而 keyword 在 term 查询时更有利。

07

Avoid scripts

避免使用 scripts,如果一定要用,优先使用 painless 和 expressions 引擎。

08

Search rounded dates

放宽日期类型的精度,由于 now 是实时变动的,因此无法缓存,而如果使用诸如 now-1h/m ,这是可以进行缓存的,相应的精度也就成了一分钟。

09

Force-merge read-only indices

强制合并只读索引为单一的 segment 更有利于搜索。使用场景常常是例如基于时间的索引,历史日期的数据不再改变,因此是只读的,而对于存在写入操作的索引不得进行此项操作。

10

Warm up global ordinals

Global ordinals 是一种数据结构,用于 keyword 字段上进行 terms aggregations,可以在 mapping 中设置 eager_global_ordinals : true 提前告诉 ES 这个字段将会用于聚合查询。

11

Warm up the filesystem cache

ES 重启后,filesystem cache 是空的,可以通过 index.store.preload 提前导入指定文件到内存中进行预热,但是如果文件系统缓存不够大,将会导致所有数据被 hold 住,一定要小心使用。

12

Use index sorting to speed up conjunctions

使用 index sorting 索引排序可以使连接更快(组织 Lucene 文档 id,使连接如 a AND b AND ... 更高效),但代价是构建索引将变慢。

13

Use preference to optimize cache utilization

缓存包括 filesystem cache、request cache、query cache 等都是基于 node 节点的,使用 preference 更够将同样的请求路由到同样的分片也就是同一个节点上,这样能够更好的利用缓存。

14

replicas might help with throughput, but not always

备份也会参与查询,这有助于提高吞吐量,但并非总是如此。

如何设置备份的数量?假设集群中有 num_nodes 个节点,num_primaries 个主分片,一次最多允许 max_failures 个节点故障,那么备份的数量应该设置为

max( max_failures, ceil( num_nodes/num_primaries ) - 1 )

15

Turn on adaptive replica selection

开启动态副本选择,ES 将会基于副本的状态动态选择以处理请求。

Tune for disk usage

优化磁盘使用。

01

Disable the features you do not need

不需要构建倒排索引的字段不建索引,index: false。

text 类型字段不需要评分的可以不写入 norms,norms: false (norms 是评分因子)。text 类型字段默认也会存储频率和位置信息,频率计算分数,位置用于短语查询,不需要短语查询可以不存储位置信息,index_options: freqs ,不关心评分可以设置 index_options: freqs 的同时设置 norms: false 。

02

Don't use default dynamic string mappings

默认的动态字符串映射会将 string 字段同时索引为 text 和 keyword ,这造成了空间的浪费,明确使用其中一个即可。

03

Watch your shard size

shard 分片越大,则存储数据越高效,缺点就是恢复需要的时间更久。

04

Disable _all

禁用 _all ,此字段索引了所有的字段, v6.0.0 版本已经将其移除。

05

Disable _source

禁用 _source ,此字段存储了原始的 json 文档数据,虽然禁用可以节省磁盘空间,但是我个人并不建议这么做,因为禁用后将无法获取到此字段的内容,如 update 和 reindex 等 API 都将无法使用。

06

Use best_compression

通过 index.codec 设置压缩方式为 best_compression 。

07

Force merge

每个 shard 分片有多个 segments,segment 越大存储数据越高效。可以通过 _forcemerge API 减少每个分片的 segments 数量,通过 max_num_segments = 1 即可设置每个分片一个 segment 。

08

Shrink index

可以通过 shrink API 减少 shard 分片的数量,可以与 _forcemerge API 一起使用。

09

Use the smallest numeric type that is sufficient

使用合适的数字类型,数字类型越小占用磁盘空间越少。

10

Use index sorting to colocate similar documents

默认情况下,文档按照添加到索引的顺序进行压缩,如果启用了 index sorting 则按照索引排序顺序进行压缩,对具有相似结构、字段和值的文档进行排序可以提高压缩效率。

11

Put fields in the same order in documents

压缩是将多个文档压缩成块,如果字段始终以相同的顺序出现,则更有可能在这些 _source 文档中找到更长的重复字符串,从而压缩效率更高。

其实从实际情况来看,磁盘的成本往往是比较低廉的,我们常常更关注的是搜索和索引性能的提升。了解优化相关的部分内容有助于我们更好的理解和使用 ES

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/701616.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

1.柔性数组

1.柔性数组 我们先来介绍一下什么是柔性数组: 在C语言中,柔性数组(Flexible Array)并不是一个标准的术语,但它通常指的是结构体中最后一个元素是一个没有指定大小的数组。这种结构体设计允许在运行时动态分配数组的大…

ES6之正则扩展

正则表达式扩展 u修饰符(Unicode模式)y修饰符(Sticky或粘连模式)s修饰符(dotAll模式)Unicode属性转义正则实例的flags属性字符串方法与正则表达式的整合 javascript的常用的正则表达式 验证数字邮箱验证手机…

Linux 第三十一章

🐶博主主页:ᰔᩚ. 一怀明月ꦿ ❤️‍🔥专栏系列:线性代数,C初学者入门训练,题解C,C的使用文章,「初学」C,linux 🔥座右铭:“不要等到什么都没有了…

TortoiseGit的安装

TortoiseSvn和TortoiseGit都是针对代码进行版本管理的工具,又俗称小乌龟,简洁而可视化的操作界面,免去繁琐的命令行输入。只需要记住常用的几个操作步骤就能快速上手。 TortoiseGit安装 1、TortoiseGit作为git的版本管理工具 ,但…

零基础10 天入门 Web3之第3天

10 天入门 Web3之第3天 什么是以太坊,以太坊能做什么?Web3 是互联网的下一代,它将使人们拥有自己的数据并控制自己的在线体验。Web3 基于区块链技术,该技术为安全、透明和可信的交易提供支持。我准备做一个 10 天的学习计划&…

粮油码垛机:自动化与智能化仓储的关键角色

在快速发展的现代化仓储物流领域,粮油码垛机正逐渐成为自动化与智能化仓储的关键角色。它以其高效、精准、节省人力的特点,赢得了众多粮油生产企业的青睐,成为仓储管理升级换代的明星产品。 一、粮油码垛机的技术革新 随着科技的发展&#…

【C语言】4.C语言数组(2)

文章目录 6. 二维数组的创建6.1 ⼆维数组的概念6.2 ⼆维数组的创建 7. 二维数组的初始化7.1 不完全初始化7.2 完全初始化7.3 按照⾏初始化7.4 初始化时省略⾏,但是不能省略列 8. 二维数组的使用8.1 ⼆维数组的下标8.2 ⼆维数组的输⼊和输出 9. 二维数组在内存中的存…

string功能介绍(普及版)

目录 1。初始化(好几种方式),npos和string的使用说明 2。string的拷贝,隐式类型转换,[],size,iterator,begin,end,reverse,reverse_iterator&am…

网络安全快速入门(十二)(下) 目录结构相关命令补充

12.4 补充命令 我们已经了解了linux的目录结构,接下来我们大概看一下针对目录及文件的一些相关命令, 我们本章只讲三个目录及文件相关的命令,分别是tree,find及校验文件命令,我们一个一个来看这些命令。 12.4.1 tree命…

Leetcode2105. 给植物浇水 II

Every day a Leetcode 题目来源:2105. 给植物浇水 II 解法1:双指针 设 Alice 当前下标为 i,初始化为 0,水量为 a,初始化为 capacityA;Bob 当前下标为 j,初始化为 n-1,水量为 b&am…

【AI】DeepStream(03):deepstream_test1_app

1、简介 deepstream-test1:演示各种 DeepStream 插件构建 GStreamer 管道。从文件中获取视频、解码、批处理,然后进行对象检测,最后在屏幕上渲染框。 源码路径:/opt/nvidia/deepstream/deepstream/sources/apps/sample_apps/deepstream-test1 先看下效果 2、编译 1)…

Pytorch读取自己的数据集

数据集 流程图 导包设置tfs创建datasets.ImageFolder创建torch.utils.data.DataLoader() import time import os from tqdm import tqdm import pandas as pd import numpy as np import torch import torchvision import torch.nn as nn import torch.nn.functional as F im…