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

apache lucene_Apache Lucene中的并发查询执行相关推荐

  1. Apache Lucene中的并发查询执行

    Apache Lucene是一个出色的并发纯Java搜索引擎,如果您愿意,它可以轻松地使服务器上的可用CPU或IO资源饱和. "典型" Lucene应用程序的并发模型在搜索时每个查 ...

  2. apache lucene_Apache Lucene基础教程

    apache lucene 课程大纲 Apache Lucene是一个免费/开源信息检索软件库,它提供基于Java的索引和搜索技术,以及拼写检查,命中突出显示和高级分析/令牌化功能. Lucene是完 ...

  3. apache lucene_Apache Lucene的结构

    apache lucene 无可估量的高贵的Apache软件基金会(Apache Software Foundation)产生了许多巨大的产品(Ant,CouchDB,Hadoop,JMeter,Ma ...

  4. apache lucene_Apache Lucene拼写检查器的“您是不是要”功能

    apache lucene Google的"您是不是要"功能 在上一篇文章中对Lucene进行了介绍之后 ,现在是时候提高它并创建一个更复杂的应用程序了. 您肯定最熟悉Google ...

  5. 如何在SQL Server 2016中比较查询执行计划

    SQL Server 2016 provides great enhancement capability features for troubleshooting purposes. Some of ...

  6. 如何查询spark版本_掌握Spark SQL中的查询执行

    了解您的查询计划 自从Spark 2.x以来,由于SQL和声明性DataFrame API,在Spark中查询数据已成为一种奢侈. 仅使用几行高级代码就可以表达非常复杂的逻辑并执行复杂的转换. API ...

  7. drill apache_大数据SQL:Apache Drill查询执行功能概述–白板演练

    drill apache 在本周的白板演练中,MapR Technologies产品管理高级总监Neeraja Rentachintala概述了开源Apache Drill如何在大型数据集上实现交互式 ...

  8. android 定时器5秒执行一次,如何在android中每30秒执行一次查询?

    我有一个查询,我想每30秒执行一次并将其记录到Logcat.我是通过处理程序完成的,我没有得到回应.如何在android中每30秒执行一次查询? 这里是我的代码: runnable = new Run ...

  9. linux select读取节点数据失败_MySQL中覆盖索引查询和select*查询执行结果案例分析...

    索引优化建议 在MySQL中要尽可能使用覆盖索引进行检索,只访问索引的查询(索引列和查询列一致),减少select * 可提高查询效率 覆盖索引(Covering Index) 理解方式一: 就是se ...

最新文章

  1. android fadingedge,Android:从滚动条中仅删除底部的FadingEdge效果
  2. Drawable Resource 之旅(一):BitmapDrawable 详解
  3. 当postgres的主键序列不同步时,如何重置?
  4. 冒泡排序算法_PHP冒泡排序算法(一)
  5. css3实现烟花效果,CSS3 带颤动效果的简易烟花动效
  6. php画图取色,procreate怎么取色
  7. php注入教程,php注入点构造代码实例详解
  8. java 线程 内存分配内存_漫谈JAVA语言的内存分配
  9. python工资这么高为什么不学-推崇Python这么多人,为什么他们找不到工作!
  10. Python 中除法运算需要注意的几点
  11. 群组日记-20080303
  12. boost升压电路 开环 PI 单闭环 双闭环 数学模型 PWM matlab仿真
  13. 腾讯云服务器登录宝塔面板
  14. OSPF特殊区域(末梢区域、NSSA) 路由优化
  15. 我用二手书,在这里换了一大箱好书
  16. Charles(Mac)抓取安卓手机app的包
  17. mysql定时任务 每日执行存储过程
  18. Android11 单编调试重力感应方向
  19. [ISUX转译]iOS7人机界面指南
  20. 2019电赛总结(一)

热门文章

  1. Early Orders
  2. P5829 【模板】失配树
  3. AT2070-[ARC061D]3人でカードゲーム/Card Game for Three【计数,组合数学】
  4. P3200-[HNOI2009]有趣的数列【卡特兰数】
  5. P6860-象棋与马【欧拉函数,杜教筛】
  6. P3201-[HNOI2009]梦幻布丁【启发式合并,链表】
  7. SP1811-Longest Common Substring【SAM】
  8. P5007-DDOSvoid的疑惑【树形dp】
  9. jzoj1013-GCD与LCM【数论】
  10. 【树链剖分】LCA(P4211)