Lucene BooleanQuery相关算法

摘要:
布尔查询针对两种不同的查询场景实现不同的算法:场景1:必须满足所有子句,并且所有子句中没有嵌套的布尔查询。此场景的代码在ConjunctionScorer类中实现,主要代码逻辑在方法doNext中:而{//finddocw/allclassesmore=first().skipTo;//skipfirstup_lastscorers.addLast;//movefirst_last}。这里,它将连续判断第一个单词的当前文档是否小于最后一个单词的现有文档。如果没有,第一个单词的文档将跳转到最后一个单词的文件位置。该数据记录在requiredMask和prohibitedMask中。这两个数字类型为int,每个数字代表一个子句。该判断通过使用上述所需掩码和禁止掩码的位操作来实现。

BooleanQuery对两种不同查询场景执行不同的算法:

场景1:

所有的子句都必须满足,而且所有的子句里没有嵌套BooleanQuery。

例:

a    AND    b    AND    c

上面语句表示要同时包含a,b,c三个字符(词元)的文档,假如现在索引里包含a的文档有4,6,8;b的文档有:2,4,6;c的文档有:3,4,5,这个语句就是找出编号为4的这个文档。

注:在倒排索引里存储的包含某个词元的文档列表都是从小到大排列的。

初始状态如下:

abc
-> 4-> 2-> 3
644
865

指针表示当前遍历到哪个文档

第一步:按照每个词元文档列表的第一个文档对词元排序。排序以后的状态如下:

bca
-> 2-> 3-> 4
446
658

第二步:判断第一个词元(b)的当前遍历文档(2)是否小于最后一个词元(a)的当前遍历文档(4)。如果小于,则表示第一个词元的当前遍历文档不是符合的文档,如果是符合的最后一个词元的当前文档应该和第一个词元的相同。

第三步: 第一个词元文档位置(2)跳转到最后一个词元的当前遍历的文档(4),跳转以后的状态如下:

bca
2-> 3-> 4
-> 446
658

第四步: 将第一个词元放到词元列表最后,重置位置后状态如下:

cab
-> 3-> 42
46-> 4
586

重复第二、三、四步,直到找到第一个词元的当前遍历文档ID和最后一个词元的相同,则这个文档就是符合查询要求的文档。

这种场景的代码实现在ConjunctionScorer类里,主要的代码逻辑在方法doNext里:

 while (more && first().doc() < last().doc()) { // find doc w/ all clauses
      more = first().skipTo(last().doc());      // skip first upto last
      scorers.addLast(scorers.removeFirst());   // move first to last
    }

这里会不断的判断第一个词元的当前文档是否小于最后一个词元的当前文档,如果不相同,则第一个词元的文档跳转到最后一个词元的文档位置。

排序是在第一次进去的时候在init方法里做的。

场景2:

除了上面第一种场景就是第二种场景,第一种场景因为排序的原因,不需要遍历所有的文档,第二种场景需要遍历所有的文档。

第二种场景的实现在BooleanScorer类里,

每次往BooleanScorer类里添加一个子句,会记录当前这个子句的序号和这个子句的定义,是必须满足还是必须不满足。这个数据记录在requiredMask和prohibitedMask中,这两个数是int类型,里面每一位都代表一个子句。requiredMask记录了哪些子句必须满足;prohibitedMask记录了哪些子句必须不能满足。比如一共有5个子句,1、3、5必须满足,2、4必须不能满足,则requiredMask二进制的值为: 10101。prohibitedMask的值为: 01010。

当调用next的时候会批量从各子句中取出符合这些子句的部分文档(文档ID批范围,1024为一批)到内存中的一个缓存BucketTabke里,在这个缓存里会根据文档ID进行聚合(Bucket),每个文档ID都有个满足哪些子句的属性bits。

然后遍历这些文档,那些bits里包含所有必须符合子句且不包含所有必须排查子句的文档是最终符合的文档。这个判断是通过bits和上面requiredMask和prohibitedMask做位运算实现的。

if ((current.bits & prohibitedMask) == 0 && 
            (current.bits & requiredMask) == requiredMask) {
          return true;
}

 

 

免责声明:文章转载自《Lucene BooleanQuery相关算法》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Lucene搜索核心代码TermInfosReaderLucene搜索/索引过程笔记下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

【剑指offer】04 重建二叉树

题目地址:重建二叉树 题目描述 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。 时间限制:C/C++ 1秒,其他语言2秒空间限制:C/...

PAT甲级1127. ZigZagging on a Tree

PAT甲级1127. ZigZagging on a Tree 题意: 假设二叉树中的所有键都是不同的正整数。一个唯一的二叉树可以通过给定的一对后序和顺序遍历序列来确定。这是一个简单的标准程序,可以按顺序打印数字。但是,如果您认为问题太简单,那么您太天真了。这次你应该以“锯齿形顺序”打印数字 - 也就是说,从根开始,逐级打印数字,从左到右交替,从右到左。例如...

数据结构与算法一

前言 树是数据结构中的重中之重,尤其以各类二叉树为学习的难点。一直以来,对于树的掌握都是模棱两可的状态,现在希望通过写一个关于二叉树的专题系列。在学习与总结的同时更加深入的了解掌握二叉树。本系列文章将着重介绍一般二叉树、完全二叉树、满二叉树、线索二叉树、霍夫曼树、二叉排序树、平衡二叉树、红黑树、B树。希望各位读者能够关注专题,并给出相应意见,通过系...

js中遍历对象的属性和值

今天想看一下js的数组遍历的内容,搜索到了一个关于对象遍历写好的函数,保留一下。以后好用。 function allPrpos ( obj ) {// 用来保存所有的属性名称和值var props = "" ;// 开始遍历for ( var p in obj ){ // 方法if ( typeof ( obj [ p ]) == " function "...

深度优先遍历DFS--用简单的方式理解

DFS 深度优先遍历 直接上图: 如我刚才所讲,从A点出发,将路径画出来就是以下效果。 实线是走过的路程,虚线就是我们的小人敲门然后发现标记过的一个过程,大家可以寄几模拟一哈。一句话总结就是: 从图中某个顶点 v 出发,访问此顶点,然后从 v 的未被访问的邻接点出发 深度优先遍历图结构,直至图中所有和 v 有路径相通的顶点都被访问到。 厦门大学数据结...

closest()一个在评论里很有用的函数

实例 本例演示如何通过 closest() 完成事件委托。当被最接近的列表元素或其子后代元素被点击时,会切换黄色背景: $( document ).bind("click", function( e ) { $( e.target ).closest("li").toggleClass("hilight"); }); 定义和用法 close...