Lucene的檢索優化(二) Hits的改進

2021-06-17 00:16:56 字數 2502 閱讀 9002

剛剛開始學lucene,看的是lucene in action。順著看下去,很自然的就是使用hits來訪問search的結果。但是使用起來,發現search的速度是很快,不過如果結果很多的話(比如1w個),通過hits訪問所有的結果速度非常慢,就是簡單地從每個結果中讀乙個field,在我的機器上用了接近2分鐘。因為我的應用索引的只是我的資料的兩個域包含文字資訊的域,我本希望通過lucene查詢出符合需求的資料id,再通過id去判斷資料庫中的其他域來決定最終的結果。這樣連取id就需要2分鐘,我的應用可受不了。

第乙個想到的方法是把我的全部資料域都做成lucene的索引,然後全部通過lucene去搜尋。但是由於我的很多域是數字,全部轉換成lucene能接受的字串,感覺效能不會好。另外如果我想針對搜尋的結果做統計,也沒法避免需要遍歷全部的搜尋結果,如果1w個結果就需要2分鐘的話,就算不用處理其他的域,也是不能忍受的。

開源軟體的好處就是可以讀**。通過閱讀hits的**,終於找到了解決問題的辦法。

lucene 的**看起來並不是特別professional。比如下面這兩個hits的初始化函式。首先裡面的q,s,f什麼的讓人看起來就不是太舒服(其他的**裡還用i,j做迴圈變數)。其次這兩個函式只有o那乙個賦值不一樣,明顯應該只寫乙個,讓另乙個來呼叫。最後程式裡面直接用了50這個常數,程式設計的大忌。(50在其他函式裡面也有)

hits(searcher s, query q, filter f) throws ioexception

hits(searcher s, query q, filter f, sort o) throws ioexception

通過這兩個函式,應該看出hits初始化的時候只調入了前100個文件。

一般我們是通過document doc(int n)函式來訪問的。這個函式裡面先判斷了有多少資料已經被調入了,如果要訪問的資料不在,就去呼叫getmoredocs函式,getmoredocs會取得需要的2倍文件進來。

但是getmoredocs的**比較讓人疑惑,裡面一段**是這樣的:

int n = min * 2; 

// double # retrieved

topdocs topdocs = (sort == null) ? searcher.search(weight, filter, n) : searcher.search(weight, filter, n, sort);

這不成了每次翻倍的時候都要去調search重新查詢嗎?除非search裡面有快取,否則效能一定指數下降啊!

實際上hits最終使用的也是topdocs,searcher組合來實現輸出結果,那不如我們來直接使用下層一點的物件了。我原來的**是:

hits hits = searcher.search(query);

for( int i=0;i

document doc = hits .doc(i );

sztest.add(doc);

}現在改為:

topdocs topdoc = searcher.search(query.weight(searcher), null, 100000);//注意最後乙個引數,是search返回的結果數量,應該比你最大可能返回的數量大,否則scoredoc裡面就是你設定的數量。

scoredoc scoredocs = topdoc.scoredocs;

for( int i=0;i

document doc = searcher.doc(scoredocs[i].doc );

sztest.add(doc);

}結果把12000個id加入arraylist用時0.4秒,快了幾百倍。

等等,還沒完。

我只需要id欄位,但是返回整個doc,其他兩個文字field也返回了。因為lucene是倒索引儲存資訊的,每乙個文字field需要重新組合成原始的字串,這也是要耗時間的。searcher的doc函式有乙個可以限定只取部分域的:

document doc(int n, fieldselector fieldselector)

我下面定義乙個fieldselector,只取某乙個給定名字的field

class specialfieldselector implements fieldselector

public fieldselectorresult accept(string fieldname)

else } }

再修改我的**:

scoredoc scoredocs = topdoc.scoredocs;

arraylistsztest = new arraylist();

fieldselector fieldselector = new specialfieldselector(field_id);

for( int i=0;i

document doc = searcher.doc(scoredocs[i].doc, fieldselector);

sztest.add(doc);

}現在返回1.2w個id耗時0.25秒。雖然比前面只少了大約150毫秒,但是是接近40%的提高了,在負載比較大的應用中還是很重要的。

Lucene4 7 索引和檢索的常用API 二

前面幾篇筆者已經把lucene的最基本的入門,介紹完了,本篇就對lucene基本的知識做乙個總結,以便於加深對lucene基本api元件的理解。為了方便對比學習,下面給出 資料 索引期間使用的api元件 檢索期間使用的api元件 indexwriter indexreader indexwriter...

lucene針對分頁文字的檢索和檢索結果定位問題

首先,索引一些文件的全文,在搜尋 電腦科學 時,首先,根據檢索詞可以找到命中的所有文件,有沒有辦法獲取到對某個命中的文件中所有的檢索關鍵字的上下文資訊?就像在word中進行搜尋時,會在目錄中高亮顯示在那些節有檢索詞,並返回共有多少個匹配項。就是需要先定位到文件,然後還要定位到文件中的位置資訊。用lu...

Lucene建立索引和索引的基本檢索

author 百知教育 gaozhy 注 演示 所使用jar包版本為 lucene 5.2.0.jar lucene索引操作建立索引 try catch exception e 索引日期 document.add new field date datetools.datetostring new d...