Lucene搜尋 索引過程筆記

2022-03-24 07:14:09 字數 3859 閱讀 7962

lucene索引文件過程: 

>初始化indexwriter

>構建document

>呼叫indexwriter.adddocument執行寫入

>初始化documentwriter。引數指定寫出位置為記憶體

>生成自增段id

>呼叫documentwriter.adddocument(); 執行寫入

>寫出fieldinfos到記憶體

>寫出fieldvalues到記憶體

>計算詞元列表

>排序詞元列表

>寫出詞元到記憶體檔案

>寫出歸一化變數到記憶體檔案

>全域性變數segmentinfos新增新增段

>增量合併段

>呼叫indexwriter.optimize()優化索引

>合併記憶體中的段並將合併後的段寫出到磁碟

>如果當前索引裡有多個索引,則合併這些索引

>呼叫indexwriter.close()關閉索引

歸一化變數是什麼? 幹什麼用的?

為什麼要在searchable介面上放乙個rewrite方法?

為什麼weight的建立要用query的createweight,而不是直接new weight();

為什麼search介面不返回乙個包含查詢結果的list,而是把查詢過程包含在返回物件的構造方法裡面?

searcher可以執行多次query,query和result是繫結的,如果search介面只返回乙個list,那同乙個查詢後面頁數查詢的時候又待重新parse等一些過程,把查詢過程包含在返回物件中實現了乙個query的自治,可以在返回物件中做一些優化,比如快取啥的

為什麼searcher不能帶pageno pagesize?

打分是在記憶體裡做的,肯定需要把所有符合的文件全都查出來

為什麼要把搜尋任務放在query頭上?不同的query搜尋邏輯有什麼不一樣?

如果要把搜尋邏輯放在searcher上,則在搜尋的時候需要判斷是哪類搜尋然後從裡面取出來引數,與其這樣判斷,不如直接把搜尋邏輯放在query上,以後加新的query邏輯也不需要修改已有的**

term搜尋過程:

>初始化indexsearcher

>根據查詢語句和解析器解析出query

>呼叫indexsearcher.search(query); 執行搜尋

>執行搜尋,獲取前100條

>重寫query

>建立weight

> 計算weight的平方和(?)

> 計算權重歸一化因子(?)

>執行weight的歸一化操作

>建立scorer

>通過reader獲取命中的文件列表

>獲取搜尋term所屬field的歸一化因子

>獲取當前query的相似性演算法

>返回termscorer

>通過scorer對命中的文件打分,並獲取得分前100條文件

>計算得分歸一化值

>將命中的100條文件得分乘上歸一化因子,然後新增到hitdocs快取中

>遍歷hitdocs獲取最終命中的文件列表資料

>如果當前遍歷的文件沒有文件內容資料,則通過searcher獲取該文件內容

>如果遍歷超過100條,則重新執行搜尋獲取當前遍歷的位置資料

lucene文件得分是如何計算的? 計算公式是什麼?

query是如何簡單化的?

boolquery執行步驟?

由queryparser生成boolquery, 每新增乙個子句都會給這個子句新增required和prohibited引數,required表示這個子句必須滿足,prohibited表示這個子句一定不能滿足

當所有的子句都必須滿足,且所有的子句已經是最基礎子句了,則使用conjunctionscorer打分器,該打分器裡會通過乙個演算法來獲取多個子句都包含的文件。具體**如下:

while (more && first().doc() < last().doc()) 

注: 所有scorer的doc都是按照從小到大排序的,這個在寫索引的時候就確定下來了(termquery),在conjunctionscorer裡第一次執行next時,會對所有的子scorer按照第乙個文件編號從小到大排序,

每當執行next尋找下乙個文件時,先看排在第一位的scorer當前文件號是否小於排在最後一位的scorer的當前文件號,如果小於,則表明排在第一位的scorer當前文件並不是所有scorer都具備的,所以

排在第一位的scorer會跳到排在最後一位scorer當前文件編號的位置,一直找到排在第一位的scorer和排在最後一位scorer都具備的乙個文件,這樣的文件滿足and的關係,可以返回。

對於子句不滿足所有子句都是required的情況,使用booleanscorer,booleanscorer的邏輯是,每往該打分器裡新增乙個子scorer,這個子scorer都帶rquired和prohibited屬性,至於這兩個屬性是從**得來的,

目前我猜測應該是從queryparser中已經計算好的。每呼叫booleanscorer的next時,都會按順序從新增進來的子scorer中取命中的文件(批量取),然後判斷取的這個文件是否應該排除掉(所屬的子scorerprohibited屬性值為true),

如果應該排除掉,則直接丟棄,再取下乙個,直到找到乙個文件符合所有子打分器要求,然後返回。重要的**片段如下:

while (buckettable.first != null) 

}在取命中的文件id的時候,是批量取的,記憶體裡會快取在乙個叫buckettable的資料結構裡面,按照文件id分組快取。 比如第一批快取的文件id為 0 ~ 1024。 第二組為 1024 ~ 2048 ... 為什麼要這樣取,而不是先取100個,再取一百個?

我理解應該是為了防止一直遍歷乙個必須排除掉的子打分器命中的文件,這樣可能會大大增加搜尋的延遲,通過文件id,可以將快取的文件均勻的分散在多個打分器上,增加命中文件的比率。那為啥不先遍歷required=true的打分器命中的文件呢?

如果先遍歷這樣的打分器,命中率不是更高麼?我理解是應該可以這樣來優化的,先遍歷requrired=true的子打分器,然後再遍歷prohibited=true的打分器,增加文件命中率。不知道作者這樣寫是不是有什麼其他的考慮,關鍵**如下:

// refill the queue

more = false;

end += buckettable.size;

for (subscorer sub = scorers; sub != null; sub = sub.next)

if (!sub.done)

}} while (buckettable.first != null | more);

queryparser是如何解析查詢指令碼的?

是不是索引都會載入到記憶體裡?

這不是的,在根據term搜尋的時候,只會把tii檔案內容載入到記憶體裡,tii檔案是詞元字典的索引,在初始化tisreader的時候就會把所有tii檔案中的內容給載入到記憶體裡

skipinterval是幹什麼用的?

frq檔案中儲存了某個詞元命中的文件列表,skipinterval記錄了隔幾個文件記錄一下該詞元命中的文件列表索引

termvector幹啥用的? 可以實現從文件到屬性到詞元的對映

段合併是如何維護合併後文件id的?

1. 在寫合併文件資料(.fdt)資料時,是按照segmentinfos裡的順序按順序寫入的。

2. 在合併時寫出合併的詞元資料時,會修改每個詞元下的文件id,會把當前詞元所屬段的base documentid加上寫出的文件id

如果在查詢時寫入的文件導致同乙個查詢結果不一樣lucene是如何處理的?

先前查詢的不會變化,但是新頁的資料是按照新查詢的結果分頁得到。因為es用了乙個快取,先前查詢的不會再更新。

每一次查詢都會把所有符合的文件和相應的打分載入到記憶體裡,然後在記憶體裡做排序、過濾、分頁

lucene搜尋索引

官方demo,裡面思路也算清晰,也可以執行 lucene 6.3.0建立索引 public class searchfiles string index index string field contents string queries null int repeat 0 boolean raw ...

Lucene初探之索引過程分析(一)

經過上面的學習,我們對於lucene的索引檔案的儲存原理有了初步的了解,不過了解了這些只是為隨後的操作lucene打下了乙個很小的基礎,我們無法依靠這些知識就去自完成搜尋引擎的整個設計。接下來,我們將開始深入lucene的索引過程,進一步去深入了解lucene的執行。對於lucene的索引過程,除了...

Lucene初探之索引過程分析(二)

在上乙個章節我們講到lucene的索引過程的起點是建立乙個indexwriter物件。在indexwriter物件建立之後,我們將會建立document文件物件,並且將其加入域 field document doc new document doc.add new field path f.getp...