apache lucene_Apache Lucene中的并发查询执行

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

apache lucene

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

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

相关文章

最小生成树——Prim(普利姆)算法

【0】README 0.1) 本文总结于 数据结构与算法分析, 源代码均为原创, 旨在 理解Prim算法的idea 并用 源代码加以实现; 0.2)最小生成树的基础知识,参见 http://blog.csdn.net/pacosonswjtu/article/details…

mysql grant usage on_grant 权限 on 数据库对象 to 用户

grant 权限 on 数据库对象 to 用户一、grant 普通数据用户,查询、插入、更新、删除 数据库中所有表数据的权利。grant select on testdb.* to common_user’%’grant insert on testdb.* to common_user’%’grant update on testdb.* to common_user’%’grant del…

openjdk8 项目结构_OpenJDK织机和结构化并发

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

mysql连库串_数据库连接串整理 - osc_ac5z111b的个人空间 - OSCHINA - 中文开源技术交流社区...

常用JDBC驱动与连接字符串MySQLdriver:com.mysql.jdbc.Driverurl:jdbc:mysql://localhost:3306/mydbMySQL url格式:jdbc:mysql://[host:port]/[database][?参数名1][参数值1][&参数名2][参数值2]…参数名称参数说明缺省值最低版本要求us…

最小生成树——Kruskal(克鲁斯卡尔)算法

【0】README 0.1) 本文总结于 数据结构与算法分析, 源代码均为原创, 旨在 理解 Kruskal(克鲁斯卡尔)算法 的idea 并用 源代码加以实现; 0.2)最小生成树的基础知识,参见 http://blo…

java 正则表达式 开头_如何在Java中修复表达式的非法开头

java 正则表达式 开头您是否遇到过这个令人难以置信的错误,想知道如何解决它? 让我们仔细阅读一下,研究如何解决表达式Java非法开头错误。 这是一个动态错误,这意味着编译器会发现某些不符合Java编程规则或语法的内容。 初学者大…

php mysql数据备份命令_MySQL数据备份与恢复的相关操作命令

将mysql安装目录设置到系统环境变量中, 方便在命令行终端直接执行.linux下mysql安装后, root默认密码为空, 可直接执行mysql 登录将mysql安装目录设置到系统环境变量中, 方便在命令行终端直接执行.linux下mysql安装后, root默认密码为空, 可直接执行mysql 登录.正常登录命令mys…

DFS——深度优先搜索基础

【0】README 0.1) 本文总结于 数据结构与算法分析, 源代码均为原创, 旨在 review DFS——深度优先搜索 的基础知识; 【1】深度优先搜索的应用 1.1)深度优先搜索算法描述(转自天勤计算机考研高分笔记——数…

rest post put_REST / HTTP方法:POST与PUT与PATCH

rest post put每个HTTP请求都包含一个方法 (有时称为verb ),该方法指示对标识的资源执行的操作。 在构建RESTful Web服务时,HTTP方法POST通常用于创建资源,而PUT用于资源更新。 尽管在大多数情况下这很好,…

回归模型的score得分为负_深度研究:回归模型评价指标R2_score

回归模型的性能的评价指标主要有:RMSE(平方根误差)、MAE(平均绝对误差)、MSE(平均平方误差)、R2_score。但是当量纲不同时,RMSE、MAE、MSE难以衡量模型效果好坏。这就需要用到R2_score,实际使用时,会遇到许多问题,今天…

DFS应用——遍历无向图

【0】README 0.1) 本文总结于 数据结构与算法分析, 源代码均为原创, 旨在 理解 如何对无向图进行深度优先搜索 的idea 并用源代码加以实现; 0.2) 本文还引入了 背向边(定义见下文描述)&#x…

高效的磁力搜索引擎 -_高效的企业测试-结论(6/6)

高效的磁力搜索引擎 -该系列的最后一部分将涵盖其他端到端测试,生产中的测试以及各部分的结论。 进一步的端到端测试和生产中的测试 除了仅验证单个被测应用程序并模拟外部问题的系统测试之外,我们的管道还必须包括完整的端对端测试,以验证…

linux安装mysql phpmyadmin_ubuntu mysql远程连接+phpmyadmin安装

一、如何让ubuntu上的mysql允许远程连接进入MySQL,执行如下命令:use mysql;GRANT ALL PRIVILEGES ON *.* TO username% IDENTIFIED BY password WITH GRANT OPTION;flush privileges; //刷新select host,user from user; //查看是否成功退出mysql;打开su…

DFS应用——找出无向图的割点

【0】README 0.1) 本文总结于 数据结构与算法分析, 源代码均为原创, 旨在 理解 “DFS应用于找割点” 的idea 并用源代码加以实现; 0.2) 必须要事先 做个specification的是:对于给定图的除开起始vertex的那…

spock测试_将Spock 1.3测试迁移到Spock 2.0

spock测试了解Spock 2.0 M1(基于JUnit 5)的期望,如何在Gradle和Maven中迁移到它以及为什么报告发现的问题很重要:)。 重要说明 。 我绝对不建议您永久将您的现实项目迁移到Spock 2.0 M1! 这是2.x的第一个&…

mysql与jmeter环境变量配置_Java开发技术大杂烩(一)之Redis、Jmeter、MySQL的那些事...

前言毕业答辩告一段落,接下来好好努力工作。Redis遇到的一些问题DENIED Redis is running in protected mode because protected mode is enabled, no bind address was specified, no authentication password is requested to clients. In this mode connections …

DFS应用——寻找欧拉回路

【0】README 0.1) 本文总结于 数据结构与算法分析, 源代码均为原创, 旨在 理解 “DFS应用——寻找欧拉回路” 的idea 并用源代码加以实现 (源代码,我还没有找到一种有效的数据结构和DFS进行结合,往后会po出…

wiremock 使用_使用WireMock进行更好的集成测试

wiremock 使用无论您是遵循传统的测试金字塔还是采用诸如“ 测试蜂窝”这样的较新方法,都应该在开发过程中的某个时候开始编写集成测试。 您可以编写多种类型的集成测试。 从持久性测试开始,您可以检查组件之间的交互,也可以模拟调用外部服务…

mysql备份七牛云存储_定时备份 Mysql并上传到七牛的方法

多数应用场景下,我们需要对重要数据进行备份、并放置到一个安全的地方,以备不时之需。常见的 MySQL 数据备份方式有,直接打包复制对应的数据库或表文件(物理备份)、mysqldump 全量逻辑备份、xtrabackup 增量逻辑备份等。常见的数据存储方式有…

jetty java_Jetty,Java和OAuth入门

jetty java使用Okta的身份管理平台轻松部署您的应用程序 使用Okta的API在几分钟之内即可对任何应用程序中的用户进行身份验证,管理和保护。 今天尝试Okta。 Jetty是一个小型,高度可扩展的基于Java的Web服务器和servlet引擎。 它支持HTTP / 2&#xff0c…