Lucene BooleanQuery相关算法
BooleanQuery對(duì)兩種不同查詢場(chǎng)景執(zhí)行不同的算法:
場(chǎng)景1:
所有的子句都必須滿足,而且所有的子句里沒(méi)有嵌套BooleanQuery。
例:
a AND b AND c
上面語(yǔ)句表示要同時(shí)包含a,b,c三個(gè)字符(詞元)的文檔,假如現(xiàn)在索引里包含a的文檔有4,6,8;b的文檔有:2,4,6;c的文檔有:3,4,5,這個(gè)語(yǔ)句就是找出編號(hào)為4的這個(gè)文檔。
注:在倒排索引里存儲(chǔ)的包含某個(gè)詞元的文檔列表都是從小到大排列的。
初始狀態(tài)如下:
| a | b | c |
| -> 4 | -> 2 | -> 3 |
| 6 | 4 | 4 |
| 8 | 6 | 5 |
指針表示當(dāng)前遍歷到哪個(gè)文檔
第一步:按照每個(gè)詞元文檔列表的第一個(gè)文檔對(duì)詞元排序。排序以后的狀態(tài)如下:
| b | c | a |
| -> 2 | -> 3 | -> 4 |
| 4 | 4 | 6 |
| 6 | 5 | 8 |
第二步:判斷第一個(gè)詞元(b)的當(dāng)前遍歷文檔(2)是否小于最后一個(gè)詞元(a)的當(dāng)前遍歷文檔(4)。如果小于,則表示第一個(gè)詞元的當(dāng)前遍歷文檔不是符合的文檔,如果是符合的最后一個(gè)詞元的當(dāng)前文檔應(yīng)該和第一個(gè)詞元的相同。
第三步: 第一個(gè)詞元文檔位置(2)跳轉(zhuǎn)到最后一個(gè)詞元的當(dāng)前遍歷的文檔(4),跳轉(zhuǎn)以后的狀態(tài)如下:
| b | c | a |
| 2 | -> 3 | -> 4 |
| -> 4 | 4 | 6 |
| 6 | 5 | 8 |
第四步: 將第一個(gè)詞元放到詞元列表最后,重置位置后狀態(tài)如下:
| c | a | b |
| -> 3 | -> 4 | 2 |
| 4 | 6 | -> 4 |
| 5 | 8 | 6 |
重復(fù)第二、三、四步,直到找到第一個(gè)詞元的當(dāng)前遍歷文檔ID和最后一個(gè)詞元的相同,則這個(gè)文檔就是符合查詢要求的文檔。
這種場(chǎng)景的代碼實(shí)現(xiàn)在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
}
這里會(huì)不斷的判斷第一個(gè)詞元的當(dāng)前文檔是否小于最后一個(gè)詞元的當(dāng)前文檔,如果不相同,則第一個(gè)詞元的文檔跳轉(zhuǎn)到最后一個(gè)詞元的文檔位置。
排序是在第一次進(jìn)去的時(shí)候在init方法里做的。
場(chǎng)景2:
除了上面第一種場(chǎng)景就是第二種場(chǎng)景,第一種場(chǎng)景因?yàn)榕判虻脑颍恍枰闅v所有的文檔,第二種場(chǎng)景需要遍歷所有的文檔。
第二種場(chǎng)景的實(shí)現(xiàn)在BooleanScorer類里,
每次往BooleanScorer類里添加一個(gè)子句,會(huì)記錄當(dāng)前這個(gè)子句的序號(hào)和這個(gè)子句的定義,是必須滿足還是必須不滿足。這個(gè)數(shù)據(jù)記錄在requiredMask和prohibitedMask中,這兩個(gè)數(shù)是int類型,里面每一位都代表一個(gè)子句。requiredMask記錄了哪些子句必須滿足;prohibitedMask記錄了哪些子句必須不能滿足。比如一共有5個(gè)子句,1、3、5必須滿足,2、4必須不能滿足,則requiredMask二進(jìn)制的值為: 10101。prohibitedMask的值為: 01010。
當(dāng)調(diào)用next的時(shí)候會(huì)批量從各子句中取出符合這些子句的部分文檔(文檔ID批范圍,1024為一批)到內(nèi)存中的一個(gè)緩存BucketTabke里,在這個(gè)緩存里會(huì)根據(jù)文檔ID進(jìn)行聚合(Bucket),每個(gè)文檔ID都有個(gè)滿足哪些子句的屬性bits。
然后遍歷這些文檔,那些bits里包含所有必須符合子句且不包含所有必須排查子句的文檔是最終符合的文檔。這個(gè)判斷是通過(guò)bits和上面requiredMask和prohibitedMask做位運(yùn)算實(shí)現(xiàn)的。
if ((current.bits & prohibitedMask) == 0 &&
(current.bits & requiredMask) == requiredMask) {
return true;
}
總結(jié)
以上是生活随笔為你收集整理的Lucene BooleanQuery相关算法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Ubuntu 14.04开发环境
- 下一篇: Day 03--设计与完善(一)