Elasticsearch:调整搜索速度

在我之前的文章 “Elasticsearch:如何提高查询性能” 及 “Elasticsearch:提升 Elasticsearch 性能” 里,我详细描述了如何提高搜索的性能。在今天的文章里,我从另外一个视角来描述如何调整搜索的速度。希望对大家有所帮助!

为文件系统缓存提供内存

Elasticsearch 严重依赖文件系统缓存来提高搜索速度。 一般来说,你应该确保至少一半的可用内存用于文件系统缓存,以便 Elasticsearch 可以将索引的热区域保留在物理内存中。

在 Linux 上使用适度的预读值来避免页面缓存抖动

搜索可能会导致大量随机读取 I/O。 当底层块设备具有较高的预读值时,可能会执行大量不必要的读取 I/O,特别是当使用内存映射访问文件时(请参阅存储类型)。

大多数 Linux 发行版对单个普通设备使用 128KiB 的合理预读值,但是,当使用软件 raid、LVM 或 dm-crypt 时,生成的块设备(支持 Elasticsearch path.data)最终可能会具有非常大的预读值(在 几个 MiB 的范围)。 这通常会导致严重的页面(文件系统)缓存抖动,从而对搜索(或更新)性能产生不利影响。

你可以使用 lsblk -o NAME,RA,MOUNTPOINT,TYPE,SIZE 检查当前值(以 KiB 为单位)。 有关如何更改此值的信息,请参阅发行版的文档(例如,使用 udev 规则在重新启动后保持不变,或通过 blockdev --setra 作为瞬态设置)。 我们建议预读值为 128KiB。

警告blockdev 期望值以 512 字节扇区为单位,而 lsblk 报告值以 KiB 为单位。 例如,要将 /dev/nvme0n1 的预读临时设置为 128KiB,请指定 blockdev --setra 256 /dev/nvme0n1。

使用更快的硬件

如果你的搜索受 I/O 限制,请考虑增加文件系统缓存的大小(见上文)或使用更快的存储。 每次搜索都涉及跨多个文件的顺序和随机读取的混合,并且每个分片上可能同时运行许多搜索,因此 SSD 驱动器的性能往往比旋转磁盘更好。

直连(本地)存储通常比远程存储性能更好,因为它更易于配置并避免通信开销。 通过仔细调整,有时使用远程存储也可以获得可接受的性能。 使用实际工作负载对你的系统进行基准测试,以确定任何调整参数的效果。 如果你无法达到预期的性能,请与存储系统的供应商合作找出问题。

如果你的搜索受 CPU 限制,请考虑使用更多更快的 CPU。

文档建模

应该对文档进行建模,以便尽可能减少搜索时间操作。

特别是应该避免 joins。 nested 可以使查询慢几倍,而父子关系可以使查询慢数百倍。 因此,如果可以通过非规范化文档来回答相同的问题,而无需 joins,则可以预期显着的加速。

搜索尽可能少的字段

query_string 或 multi_match 查询的目标字段越多,速度就越慢。 提高多个字段搜索速度的常用技术是在索引时将它们的值复制到单个字段中,然后在搜索时使用该字段。 这可以通过映射的 copy_to 指令来自动化,而无需更改文档的源。 下面是一个包含电影的索引示例,该索引通过将两个值索引到 name_and_plot 字段来优化搜索电影名称和情节的查询。

PUT movies
{
  "mappings": {
    "properties": {
      "name_and_plot": {
        "type": "text"
      },
      "name": {
        "type": "text",
        "copy_to": "name_and_plot"
      },
      "plot": {
        "type": "text",
        "copy_to": "name_and_plot"
      }
    }
  }
}

索引前数据

你应该利用查询中的模式来优化数据索引方式。 例如,如果你的所有文档都有 price 字段,并且大多数查询在固定的范围列表上运行 range 聚合,则可以通过将range 预先索引到索引中并使用 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": {
    "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"
      }
    }
  }
}

考虑将映射标识符作为关键字

并非所有数值数据都应映射为 numeric 字段数据类型。 Elasticsearch 优化 range 查询的数字字段,例如 integer 或 long。 但是,keyword 字段更适合 term 和其他term-level查询。

ISBN 或产品 ID 等标识符很少在 range 查询中使用。 然而,它们通常是使用 term-level 级查询来检索的。

如果出现以下情况,请考虑将数字标识符映射为 keyword:

  • 你不打算使用 range 查询来搜索标识符数据。
  • 快速检索很重要。 keyword 字段上的 term 查询搜索通常比数字字段上的术语搜索更快。

如果你不确定使用哪个,可以使用 multi-field 将数据映射为 keyword 和数字数据类型。

避免脚本

如果可能,请避免使用基于脚本的排序、聚合中的脚本和 script_score 查询。 请参阅 Scripts、caching 和 search speed。

搜索四舍五入的日期

对使用 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 之间的所有内容。 如果多个用户在同一分钟内运行包含此范围的查询,则查询缓存可以帮助加快速度。 用于舍入的间隔越长,查询缓存的帮助就越大,但请注意,过于激进的舍入也可能会损害用户体验。

注意:为了能够利用查询缓存,将范围分割为大的可缓存部分和较小的不可缓存部分可能很诱人,如下所示:

GET index/_search
{
  "query": {
    "constant_score": {
      "filter": {
        "bool": {
          "should": [
            {
              "range": {
                "my_date": {
                  "gte": "now-1h",
                  "lte": "now-1h/m"
                }
              }
            },
            {
              "range": {
                "my_date": {
                  "gt": "now-1h/m",
                  "lt": "now/m"
                }
              }
            },
            {
              "range": {
                "my_date": {
                  "gte": "now/m",
                  "lte": "now"
                }
              }
            }
          ]
        }
      }
    }
  }
}

然而,这种做法在某些情况下可能会使查询运行速度变慢,因为 bool 查询引入的开销可能会抵消更好地利用查询缓存所节省的成本。

强制合并只读索引

只读索引可能会受益于合并到单个段。 基于时间的索引通常就是这种情况:只有当前时间范围的索引正在获取新文档,而旧索引是只读的。 已强制合并为单个分段的分片可以使用更简单、更高效的数据结构来执行搜索。

重要:不要强制合并你仍在写入或将来将再次写入的索引。 相反,依靠自动后台合并进程根据需要执行合并,以保持索引平稳运行。 如果你继续写入强制合并索引,那么它的性能可能会变得更糟。

热身全局序数

全局序数(global ordinals)是一种用于优化聚合性能的数据结构。 它们是惰性计算的,并作为字段数据缓存的一部分存储在 JVM 堆中。 对于大量用于分桶聚合的字段,你可以告诉 Elasticsearch 在收到请求之前构建并缓存全局序号。 应该谨慎执行此操作,因为它会增加堆使用量并使刷新时间更长。 通过设置 eager global ordinals 映射参数,可以在现有映射上动态更新该选项:

PUT index
{
  "mappings": {
    "properties": {
      "foo": {
        "type": "keyword",
        "eager_global_ordinals": true
      }
    }
  }
}

预热文件系统缓存

如果运行 Elasticsearch 的机器重新启动,文件系统缓存将为空,因此操作系统需要一些时间才能将索引的热区域加载到内存中,以便搜索操作快速。 你可以使用 index.store.preload 设置显式告诉操作系统哪些文件应根据文件扩展名立即加载到内存中。

警告:如果文件系统缓存不够大,无法容纳所有数据,则在太多索引或太多文件上急切地将数据加载到文件系统缓存中将使搜索速度变慢。 谨慎使用。

使用索引排序来加速连词

索引排序(index sorting)很有用,可以使连接 (conjunctions) 速度更快,但代价是索引速度稍慢。 请在索引排序文档中相关信息。

使用 preference 项来优化缓存利用率

有多种缓存可以帮助提高搜索性能,例如文件系统缓存、请求缓存或查询缓存。 然而,所有这些缓存都是在节点级别维护的,这意味着如果你连续两次运行相同的请求,有 1 个或更多副本并使用默认路由算法 round-robin,那么这两个请求将转到不同的分片副本 ,阻止节点级缓存发挥作用。

由于搜索应用程序的用户通常会相继运行类似的请求,例如为了分析索引的较小子集,因此使用标识当前用户或会话的 preference 项值可以帮助优化缓存的使用。

副本可能有助于提高吞吐量,但并不总是如此

除了提高弹性之外,副本还可以帮助提高吞吐量。 例如,如果你有一个单分片索引和三个节点,则需要将副本数设置为 2,以便总共拥有 3 个分片,以便利用所有节点。

现在假设你有一个 2 分片(2-shard)索引和两个节点。 在一种情况下,副本数为 0,这意味着每个节点拥有一个分片。 在第二种情况下,副本数为 1,这意味着每个节点有两个分片。 哪种设置在搜索性能方面表现最佳? 通常,每个节点总共具有较少分片的设置会表现更好。 原因是它为每个分片提供了更大份额的可用文件系统缓存,并且文件系统缓存可能是 Elasticsearch 的第一大性能因素。 同时,请注意,如果单个节点发生故障,没有副本的设置可能会失败,因此在吞吐量和可用性之间需要进行权衡。

那么正确的副本数量是多少? 如果您的集群总共有 num_nodes 个节点、num_primaries 个主分片,并且你希望能够一次最多处理 max_failures 个节点故障,那么适合你的副本数量是 max(max_failures, ceil(num_nodes / num_primaries) - 1).

使用搜索分析器调整你的查询

Profile API 提供有关查询和聚合的每个组件如何影响处理请求所需时间的详细信息。

Kibana 中的 Search Profiler 可以轻松导航和分析分析结果,并让你深入了解如何调整查询以提高性能并减少负载。

由于 Profile API 本身会显着增加查询开销,因此此信息最好用于了解各种查询组件的相对成本。 它不提供实际处理时间的可靠测量。

使用 index_phrases 加快短语查询速度

Text 字段有一个索引 2-shingles 的 index_phrases 选项,并由查询解析器自动利用来运行没有倾斜的短语查询。 如果你的用例涉及运行大量短语查询,这可以显着加快查询速度。

使用 constant_keyword 来加速过滤

一般规则是过滤器的成本主要是匹配文档数量的函数。 想象一下你有一个包含 cycles 的索引。 自行车 (bicycle) 数量很多,许多搜索都会对 cycle_type: bycycle 进行过滤。 不幸的是,这种非常常见的过滤器也非常昂贵,因为它与大多数文档匹配。 有一种简单的方法可以避免运行此过滤器:将 bycycles 移动到自己的索引并通过搜索此索引来过滤自行车,而不是向查询添加过滤器。

不幸的是,这可能会使客户端逻辑变得棘手,而这正是 constant_keyword 可以发挥作用的地方。 通过将 cycle_type 映射为 constant_keyword,并在包含 bicycles 的索引上使用值 bicycle,客户端可以继续运行与在整体索引上运行完全相同的查询,并且 Elasticsearch 将通过忽略 cycle_type 上的过滤器来对 bicycles 索引执行正确的操作,如果该值是 bycycle,否则不返回任何命中。

映射可能如下所示:

PUT bicycles
{
  "mappings": {
    "properties": {
      "cycle_type": {
        "type": "constant_keyword",
        "value": "bicycle"
      },
      "name": {
        "type": "text"
      }
    }
  }
}

PUT other_cycles
{
  "mappings": {
    "properties": {
      "cycle_type": {
        "type": "keyword"
      },
      "name": {
        "type": "text"
      }
    }
  }
}

我们将索引一分为二:一个仅包含 bicycles,另一个包含其他 cycles:独轮车、三轮车等。然后在搜索时,我们需要搜索这两个索引,但不需要修改查询 。

GET bicycles,other_cycles/_search
{
  "query": {
    "bool": {
      "must": {
        "match": {
          "description": "dutch"
        }
      },
      "filter": {
        "term": {
          "cycle_type": "bicycle"
        }
      }
    }
  }
}

在 bicycles 索引上,Elasticsearch 将简单地忽略 cycle_type 过滤器并将搜索请求重写为以下请求:

GET bicycles,other_cycles/_search
{
  "query": {
    "match": {
      "description": "dutch"
    }
  }
}

在 other_cycles 索引上,Elasticsearch 会很快发现 cycle_type 字段的术语字典中不存在 bicycle 并返回没有命中的搜索响应。

通过将通用值放入专用索引中,这是一种降低查询成本的强大方法。 这个想法也可以跨多个领域组合:例如,如果你跟踪每个自行车的颜色并且你的 bicycles 索引最终包含大多数黑色自行车,你可以将其分为 bicycles-black 索引和 bicycles-other-colors 索引 。

此优化并不严格需要 constant_keyword:还可以更新客户端逻辑,以便根据过滤器将查询路由到相关索引。 然而,constant_keyword 使其变得透明,并允许将搜索请求与索引拓扑解耦,以换取很少的开销。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

c++简单实现avl树

文章目录 AVL树节点类节点类的构造函数 AVLinsert()插入RotateL(左单旋)RotateR(右单旋)RotateLR(右双旋)RotateRL(左双旋) Find(查找)IsBalance(检查是否是avl树) AVL树 AVL树:又名高度平衡树,在二叉搜索树的基础上加上了一个条件,条件是左右子树高度差…

【并查集】模版

【模板】并查集 - 洛谷 #include <bits/stdc.h> using namespace std; const int N2e59; int a[N]; int Find(int x) {if(xa[x]){return x;}else{a[x]Find(a[x]);return a[x];} } void push(int x,int y) {a[Find(x)]Find(y);return ; } int main() {int n,m; cin>>…

(十七)【Jmeter】取样器(Sampler)之JSR223取样器

该实例使用python 2.7.3的插件,jython-standalone-2.7.3.jar:https://www.123pan.com/s/VppKjv-5YvTv.html 提取码:tfsX 把该插件放在Jmeter安装的:apache-jmeter-5.6.3\lib\ext目录下: 简述 JSR是Java Specification Requests的缩写,意思是Java规范提案 操作路径如下: …

Linux-新手小白速秒Hadoop集群全生态搭建(图文混编超详细)

在之前的文章中&#xff0c;我教会大家如何一步一步搭建一个Hadoop集群&#xff0c;但是只提供了代码&#xff0c;怕有些朋友会在一些地方产生疑惑&#xff0c;今天我来以图文混排的方式&#xff0c;一站式交给大家如何搭建一个Hadoop高可用集群包括&#xff08;HadoopHA&#…

鸿蒙Harmony应用开发—ArkTS声明式开发(容器组件:SideBarContainer)

提供侧边栏可以显示和隐藏的侧边栏容器&#xff0c;通过子组件定义侧边栏和内容区&#xff0c;第一个子组件表示侧边栏&#xff0c;第二个子组件表示内容区。 说明&#xff1a; 该组件从API Version 8开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起…

第九届多媒体系统和信号处理国际会议(ICMSSP 2024)即将召开!

2024年第九届多媒体系统和信号处理国际会议&#xff08;ICMSSP 2024&#xff09;将在5月24-26日在泰国曼谷举行。ICMSSP 2024旨在展示多媒体系统和信号处理等相关主题的最新研究和成果&#xff0c;为不同领域的专家代表提供了面对面交流新想法以及应用经验的机会&#xff0c;建…

【经验总结】ubuntu 20.04 git 上传本地文件给 github,并解决出现的问题

1. 在GitHub 上创建仓库 登录 GitHub 个人网站 点击 New 填写 Repository name, 以及 Description (optional) 选择 Public &#xff0c; 并添加 Add a README file 点击 Create repository github repository 创建成功 2. 设置SSH key 在本地 bash 运行&#xff1a;…

sqllab第十八关通关笔记

知识点&#xff1a; UA注入 不进行url解析&#xff0c;不能使用 %20 编码等操作出现在User-agent字段中一般为insert语句 insert 表名(字段1&#xff0c;字段2&#xff0c;。。。) values(数据1&#xff0c;数据2&#xff0c;。。。) 通过admin admin进行登录发现页面打印出了…

arp动态表缓存清除

一、arp表里清除表状态&#xff1a; 1&#xff0c;Delay&#xff1a;请求arp 2&#xff0c;Reachab&#xff1a;响应arp 3&#xff0c;Stale此状态下&#xff0c;待gc_stale_time超时后&#xff0c;准备gc_interval定期清理 二、限制条件 base_reachable_time&#xff1a;后变…

数据结构的概念大合集04(队列)

概念大合集04 1、队列1.1 队列的定义1.2队列的顺序存储1.2.1 顺序队1.2.2 顺序队的基本运算的基本思想1.2.3 顺序队的4要素的基本思想 1.3 环形队列1.3.1 环形队列的定义1.3.1 环形队列的实现 1.4 队列的链式存储1.4.1 链队1.4.2 链队的实现方式1.4.3 链队的4要素的基本思想 1.…

双指针 | 移动零 | 复写零

1.移动零 题目描述&#xff1a; 给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。 示例&#xff1a; 输入: nums [0,1,0,3,12] 输出: [1,3,12,0,0]解题思路&#xff1a; right指针一直往后移动&#xff0c;当…

Java实现简单的通讯录

每日一言 泪眼问花花不语&#xff0c;乱红飞过秋千去。 —欧阳修- 简单的通讯录实现&#xff0c;跟写Java实现图书管理系统差不多&#xff0c;用到的知识也差不多&#xff0c;就当个小练习&#xff0c;练习一下写Java程序的手感。 Java实现图书管理系统 关于通讯录的代码都写…

【JVM】(内存区域划分 为什么要划分 具体如何分 类加载机制 类加载基本流程 双亲委派模型 类加载器 垃圾回收机制(GC))

文章目录 内存区域划分为什么要划分具体如何分 类加载机制类加载基本流程双亲委派模型类加载器 垃圾回收机制&#xff08;GC&#xff09; 内存区域划分 为什么要划分 JVM启动的时候会申请到一整个很大的内存区域,JVM是一个应用程序,要从操作系统这里申请内存,JVM就需要根据,把…

Android Studio字体大小调节

外观页面字体调节 settings->Appearance->User cunstom font 代码字体调节 Settings->Editor->Font此时logcat窗口、Build窗口和Ternimal窗口字体大小也会同步调节&#xff08;2023.2.1版本上验证&#xff09;

基于Springboot和Redis实现的快递代取系统

1.项目简介 本项目基于springboot框架开发而成&#xff0c;前端采用bootstrap和layer框架开发&#xff0c;系统功能完整&#xff0c;界面简洁大方&#xff0c;比较适合做毕业设计使用。 本项目主要实现了代取快递的信息管理功能&#xff0c;使用角色有三类&#xff1a;一是客…

Elasticsearch 主副分片切换过程中对业务写入有影响吗

&#x1f34a;&#x1f349;&#x1f34b; 先说下结论&#xff0c;只要集群中的工作节点过半&#xff0c;有候选的master节点&#xff0c;挂掉的节点中不同时包含索引的主分片和副分片&#xff0c;那么ES是可以做到让业务无感知的进行主副分片切换的。 蓝胖子会先讲解下ES集群写…

ARM_基础之RAS

Reliability, Availability, and Serviceability (RAS), for A-profile architecture 源自 https://developer.arm.com/documentation/102105/latest/ 1 Introduction to RAS 1.1 Faults,Errors,and failures 三个概念的区分&#xff1a; • A failure is the event of devia…

外包干了3天,技术明显进步。。。。。

先说一下自己的情况&#xff0c;本科生&#xff0c;19年通过校招进入南京某软件公司&#xff0c;干了接近2年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了2年的功能测试&…

16、技巧之九: 修改参数,如何让表格翻页滚动到底部?【Selenium+Python3网页自动化总结】

1、问题提出 在网页配置参数时&#xff0c;输入参数名称搜索&#xff0c;搜出来的同名参数结果有多个&#xff0c;分布在一个表格的不同行&#xff0c;表格是动态加载的&#xff0c;需要滚动鼠标才能把所出参数找出来。用selenium怎么实现这种参数修改&#xff1f; 2、网页元素…

JVM学习-JVM的自动优化

目录 1.语法糖 1.1默认构造器 1.2自动拆装箱 1.3泛型集合取值 1.4可变参数实现 1.5 foreach循环 1.6 switch配合String使用 1.7 switch配合枚举使用​编辑 1.8 try-with-resources 1.9方法重写的桥接方法 2.运行时优化 2.1分层优化以及逃逸分析 2.2方法内联 2.3字段优化 JVM会…