Apache Lucene中的并发查询执行

Apache Lucene是一个出色的并发纯Java搜索引擎,如果您愿意,它可以轻松地使服务器上的可用CPU或IO资源饱和。 “典型” Lucene应用程序的并发模型在搜索时每个查询一个线程,但是您知道Lucene还可以使用多个线程同时执行一个查询以大大减少最慢查询的时间吗?

Lucene的IndexSearcher类负责执行传入查询以从索引中查找最匹配的匹配项,它接受一个可选
施工期间执行器 (例如线程池)。 如果您通过Executor并且CPU足够闲置(即,服务器远低于其红线QPS吞吐能力),Lucene将使用多个并发线程来查找每个查询的总点击率最高。


它是如何做到的? Lucene索引是分段的 ,这使搜索成为一个棘手的并行问题:每个查询都必须访问索引中的所有细分,并收集其具有全球竞争力的点击量。 当查询为单线程查询时,因为您没有将Executor传递给IndexSearcher ,所以一个查询线程必须按顺序访问所有段。 如果索引很大,并且您的查询成本很高,那么这些查询自然会需要较高的CPU成本和挂钟时间才能找到热门广告。 即使您在远远低于其红线QPS(吞吐量)容量的情况下运行服务器,这也会导致高长杆(P90 +)查询延迟。

相反,当您将Executor传递给IndexSearcher ,索引中的段首先被IndexSearcher分组为单个线程工作单元,称为
螺纹片 。 默认情况下 ,大段属于它们自己的线程片,最多5个较小的段(最多250K总文档)将合并为一个线程片,因为它们可以快速地按单个线程顺序搜索。 通过子类化IndexSearcher并覆盖其受保护的slices方法,可以轻松地自定义将段合并为线程片的方式。 只要服务器闲置到足以在一个查询上花费多个CPU内核,并且该查询的每个线程片上都有一个线程,那么每个并发的查询就会同时执行。

这个强大的功能最初是由Jean-FrançoisHalleux于16年前提出的 ,然后由Doug Cutting自己 (您好,Doug!)提出,并于大约9年前最终重构为IndexSearcher ,此后进行了许多迭代的改进,许多现在都在不断发展。感谢Atri Sharma ,最近添加了新的Lucene / Solr提交者 。 这就是热情的开源软件开发的分布式力量!

并发查询执行是Lucene中很少有人知道的sleeper功能,因为它尚未在基于Lucene构建的两个流行的分布式搜索应用程序Elasticsearch和Solr中公开。 他们的并发模型是跨索引分片(通常在不同的服务器上)针对单个查询的并发搜索,但是在每个分片内使用单线程搜索。

这意味着需要许多并发的独立查询才能使集群范围的CPU或IO资源饱和。 直到群集至少看到最低最低QPS,才能使用全部硬件资源。 对于经常看到高查询率的用例,此限制是可以接受的。 但是,如果Elasticsearch或Solr使用此功能,则具有较大索引和较低查询率的其他常见用例将从单个群集节点内的并发查询执行中受益匪浅。

摩尔定律在现实世界中的影响已经发生了变化:现代服务器级计算机是用惊人且Swift增长的并发硬件构建的,不仅在其CPU中,我们现在在最新的c5.24xlarge AWS EC2实例中还可以看到96个内核,图形处理单元(GPU),内存总线,DIMM和固态磁盘(SSD),实际上是底层的大型并发RAID 0阵列。 最近的趋势是CPU和GPU获得更多的并发(内核),而每个单独的内核获得的并发速度则更快。 为什么不使用所有这些增加的并发性来提高所有查询的速度,甚至在低查询负载时也使CPU / IO饱和?

棘手的权衡

不幸的是,尽管搜索Lucene索引是一个自然而尴尬的并行问题,但对一个查询使用多个线程会产生固有的协调开销。 要理解为什么,请考虑一个简单的类比:假设您需要苹果,那么您将孩子送到当地的杂货店购买。 如果您只有一个孩子,则将其送给她,她会在整个农产品区域四处走走,挑选十个最好的苹果,然后带回家。

但是,如果您有五个孩子,然后将所有孩子都送到商店,他们会不会再快五倍,而忽略了他们往返商店的“联网”时间? 他们如何有效地分割工作?

也许您的孩子很聪明,他们首先将商店中的所有苹果部分(现在有很多苹果选择 !)分成五个大致相等的部分。 每个人都围绕着自己的苹果区运行,挑选她能找到的十个最好的苹果,然后他们都在结帐柜台集合,密切合作,从现在拥有的五十个苹果中选出十个最好的苹果? 这有点浪费,因为孩子们总共收集了五十个苹果,只是为了最终选择实际的十个最佳苹果,但确实比一个孩子选出十个最佳苹果要快。

这实际上是Lucene今天实现并发搜索的方式:每个搜索器线程单独工作以从一个线程片中找到自己的前N个最佳匹配(“映射”阶段),然后,一旦所有查询线程完成并重新加入主线程在主线程中,主线程使用部分合并排序从为每个线程切片收集的匹配中找到总前N个最佳匹配(“减少”阶段)。 Lucene的CollectorManagerCollectorLeafCollector抽象都协同工作以实现此目的。 从现在开始,这意味着与单线程情况相比,完成了更多的工作
收集了M * N总匹配,然后最后减少到前N ,其中M是并发搜索线程的数量, N是请求检索的顶级匹配的数量。

并发运行每个查询时,增加的协调成本必然会损害搜索节点的红线QPS容量(吞吐量),因为Lucene会花费更多的总CPU周期来查找最热门。 但是,与此同时,当搜索节点具有大量备用CPU资源时,它可以大大提高长杆查询的等待时间,因为最困难的查询现在可以同时运行。 此外,收集更多匹配并最终合并它们的额外成本通常对总体影响不大,因为通常是每个匹配的匹配和排名决定了总查询成本,尤其是随着索引变大,并且该成本是有效地跨线程拆分。

您可以通过限制可以同时运行的查询数来进一步“扩大”这种折衷,从而最大化每个查询将使用多少个CPU内核。 您还可以预先估算每个查询的成本,并仅在其成本足够大时并发执行该查询,以便可以在单个线程中快速运行的简单查询不会支付在多个线程之间进行同步的开销。

这种吞吐量与延迟之间的权衡令人沮丧,这意味着在您的Lucene应用程序中使用模式方法可能很有意义。 集群负载较轻时,通过限制可以同时运行的查询数来减少每个查询的多个线程,从而减少长杆延迟。 但是,当群集正在运行时,接近其红线容量时,每个查询将转移到单个线程以最大化吞吐量。 确保您正确地测量了等待时间,并且负载测试客户端没有遭受普遍常见的协调遗漏错误 ! 确认您的负载测试客户端正在使用开环测试,以便您看到真正的延迟影响,例如长时间的垃圾收集暂停,I / O打ic或交换。

持续的和未来的改进

幸运的是,最近进行了一些激动人心的改进,以减少多线程查询的额外开销。 Lucene现在还使用传入(调用)线程来帮助并发搜索 。 用于将小段分组为切片(线程工作单元)的算法已得到改进 。 现在,提前终止现在可以在多个搜索线程中使用一个共享的全局命中计数器来查询一个查询,从而降低了查询的总成本。 查询缓存将很快使用Executor进行并发缓存,并且在某些情况下使用Executor时甚至可以更高效。 他们应该在共享信息的同时共享信息,例如到目前为止收集的最差得分的最高命中 ,甚至在所有线程中使用单个共享优先级队列,而不是每个搜索线程都完全独立地工作并仅在最后合并热门命中。 共享优先级队列可能会导致过多的锁定,因此,作为一种折衷,现在搜索可以高效地共享搜索器线程中收集到的最差命中值中的最好值 ,这显示了令人印象深刻的luceneutil 基准测试结果 。


这些改进减少了并发搜索的额外成本,但是该成本永远不会为零,因为更频繁的线程上下文切换,共享优先级队列的锁争用,命中计数器和优先级队列底部以及潜在的困难后果都会带来固有的自然成本。现代非均匀内存架构(NUMA) 。

Lucene并发搜索的一个令人惊讶且令人失望的局限性在于,完全合并的索引(直至单个段)会丢失所有并发性! 这就是Bizarro World ,因为通常可以将其索引合并到一个段中以提高查询性能! 但是,当您查看长杆查询延迟时,不幸的是,完全合并的索引会变慢,因为即使将Executor传递给IndexSearcher所有查询现在都将再次成为单线程。 即使单个新近完成的大型合并也会在您的长极点延迟中导致锯齿状的模式,因为这会减少净查询并发,尽管通过这种合并红线群集的吞吐量仍会提高。 解决这个问题的一个简单方法是允许多个线程搜索一个大的段 ,这很有效,因为Lucene具有自然的API,可以在段的“ docid空间”中搜索单独的区域。

自让-弗朗索瓦·哈勒克斯(Jean-FrançoisHalleux)首次为Lucene提出并行搜索以来,并发搜索已经走了很长一段路,我希望它还有很长的路要走,以使我们真正减少使用多线程进行昂贵查询的额外开销。 随着Lucene改进其查询计划和优化,我们将达到一个容易查询运行单线程但代价高昂的查询同时高效运行的地步。 这些改进必须归功于Lucene:现代服务器继续添加越来越多的内核,但并没有使这些内核变得更快,因此,包括Lucene在内的现代软件不可避免地必须找到有效利用所有这些并发性的方法。

[我在亚马逊工作,并且本网站上的帖子属于我自己,不一定代表亚马逊的职位]

翻译自: https://www.javacodegeeks.com/2019/10/concurrent-query-execution-apache-lucene.html

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

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

相关文章

Windows设置自己的程序开机自动启动

Windows系统想要快速设置开机自动启动某个程序,可以使用以下方法设置: 1.找到启动文件夹 CtrlR 打开运行,输入shell:startup,回车,找到启动文件夹 2.拷贝需要开机启动的程序的快捷方式到此文件夹即可。 3.打开任务管理器-启动查…

Citavi中文件管理

目录 I 文献相对应的PDF文件相关操作 1 打开PDF所在位置 2 直接重命名PDF文献 注:设置角标方式 II 阅读文献相关的文件的添加与删除 1 添加 2 删除 III PPT CAJ文件的添加 I 文献相对应的PDF文件相关操作 PDF文件可直接拉入文献框进行导入 1 打开PDF所在位置…

coldfusion_我从ColdFusion迁移到Java开发

coldfusion尽管我在大学和研究生的整个职业生涯中都研究和尝试了不同的开发技术和工具,但我的全职职业生涯始于Adobe ColdFusion的开发。 从学校毕业后,使用技术解决现实世界中的业务问题本身就是一个挑战。 由于其相当简单的性质,ColdFusio…

Citavi插件的安装和使用以及注意事项

【文章转载于知乎大神:Citavi插件的安装和使用以及注意事项 - 知乎】 没有软件是十全十美的,基础功能够用,附加功能以插件、脚本的方式来支持是个不错的思路。 Citavi提供了自定义宏和插件的方式,来满足更为复杂的格式修整和文献…

Java 9中的HTTP / 2支持简介

1.简介 IETF流媒体小组于2015年(即HTTP / 1.1发布后的16年) 批准了HTTP / 2协议。 HTTP / 2有望降低延迟,并且使许多替代方法变得过时,而这些替代方法是HTTP / 1.1所必需的,以便能够满足当今的响应时间要求。 在本文中…

MiUI特色功能设置总结

一 常用设置 【转载于知乎https://www.zhihu.com/question/514792652/answer/2377622710】 1 自动优化系统 其实在手机开发者模式设置中,有2个地方我们需要设置,设置了不仅可以让手机运行更流畅,而且还能帮我们自动优化系统。 &#xff0…

potplayer怎么设置无边框播放,播放时隐藏进度条

potplayer默认情况下播放视频时会显示边框,那么怎么设置无边框播放呢?下面小编就为大家详细的介绍一下,大家感兴趣的话就一起来了解下吧! potplayer怎么设置无边框播放?potplayer设置无边框播放方法 1、点击左上角的potplayer 2、在下拉菜单中点击选项…

蓝牙播放Stereo和Hands-Free AG Audio两种模式的区别?

当使用蓝牙耳机时,发现电脑的播放设备显示了两种模式(如下图所示),Stereo模式下声音正常,而调到Hands-Free AG Audio模式下声音频带窄了很多且音质差,典型的电话音,下面具体说说这两种模式的区别…

office工作日志文件_风暴事件处理器–每个工作者的GC日志文件

office工作日志文件在过去的三个月中,我正在与一个新团队合作,为电信领域的大数据分析构建产品。 Storm事件处理器是我们使用的主要框架之一,它确实很棒。 您可以阅读其官方文档中的更多详细信息(已改进)。 Storm使用…

workrave使用方法

一 模式介绍 阅读模式: 不论电脑什么状态,倒计时一直进行 普通模式: 当检测到电脑没有任何操作,比如打字与移动鼠标,则暂停倒计时。如果长时间没有操作,则默认进入休息状态,下次移动鼠标&…

OpenJDK织机和结构化并发

Project Loom是Hotspot Group赞助的项目之一,旨在向JAVA世界提供高吞吐量和轻量级的并发模型。 在撰写本文时,Loom项目仍处于积极开发中,其API可能会更改。 为什么要织机? 每个新项目可能会出现的第一个问题是为什么?…

在已打开的程序上打开新的窗口

在支持多开的程序上面按shift加鼠标左键,则打开程序新的窗口

Virgo软件的介绍

使用Virgo的场景 Win10自带的虚拟桌面存在BUG,当在第二个虚拟桌面上打开某个软件时(如WPS),会自动跳转到打开该应用的第一个窗口。 Virgo介绍 原代码8KB,启用后占用内存1MB,极简桌面 快捷键 ALT 1..4…

java 8 lambda_玩Java 8 – Lambda,路径和文件

java 8 lambda我最近需要读取一堆文件,而不是仅仅抓住我和可能是大多数开发人员拥有的旧FileUtils.java,然后从一个项目复制到另一个项目,我决定快速看看其他方法。 是的,我知道有Commons IO和Google IO ,我为什么还要…

设置花里胡哨的Xshell字体与背景颜色(超全)

大部分运维和开发经常接触到的客户端连接工具很多都是Xshell,但是经常看到别人的背景色和字体都是五颜六色,还有护眼色的背景(想必大家也会遇到在深夜加班时为了不打扰身边小伙伴的休息不开灯,打开Xshell时可以闪瞎人眼的白色背景…

Jakarta EE贡献–入门

您是否有兴趣帮助Jakarta EE向前发展? 我也是。我想提供一些详细信息,以帮助有兴趣入门的人。 步骤1: 开始捐款的第一步是签署Eclipse Foundation Committer and Contributor Agreement(ECA): https : //…

Ubuntu “sudo apt-get update”报错

一 sudo apt-get update作用 从服务器拉取可用的包到本地 二 出错情况 Ign:9 https://download.sublimetext.com apt/stable/ Packages Ign:10 https://download.sublimetext.com apt/stable/ Translation-en_US Ign:11 https://download.sublimetext.com apt/stable/ Transl…

dpkg:错误:无法新建文件 ‘/var/lib/dpkg/info/format-new’: 没

错误 dpkg:错误:无法新建文件 ‘/var/lib/dpkg/info/format-new’: 没有那个文件或目录 E: Sub-process /usr/bin/dpkg returned an error code (2) 解决方法 1.尝试去查看没有那个文件或目录 2.逐级进入目录,返现没有的是 info 3.用root权限…

add-apt-repository命令详解

该命令是通过PPA源方式安装软件的添加PPA源到Source list中的命令,该软件安装方式的流程为: 1.搜索PPA软件源,如在Google上软件名称关键字 PPA ,或者也可直接到 launchpad.net 上搜索2.sudo apt-add-repository ppa_source_name…

过度配置堆上的OutOfMemoryError

在分配一个应该很适合我为JVM提供的堆中的数据结构时,为什么会出现OutOfMemoryError? 这是我最近遇到的一个问题。 确实,当查看开发人员要完成的工作并通过-Xmx参数对提供给JVM的堆大小进行三重检查时,似乎确实存在着一些可疑之处…