天天看點

一步一步學lucene——(第四步:搜尋篇)lucene的主要搜尋的API對特定項進行搜尋解析使用者查詢搜尋用到的各個類的互相關系搜尋結果分頁

下面說的主要是lucene如何進行搜尋,相比于建索引,搜尋可能更能提起大家的興趣。

下面通過表格來看一下lucene用到的主要的搜尋API

目的

IndexSeacher

搜尋操作的入口,所有搜尋操作都是通過IndexSeacher執行個體使用一個重載的search方法來實作

Query(及其子類)

具體的Query子類為每一種特定類型的查詢進行邏輯上的封裝。Query執行個體被傳遞到IndexSearcher的search方法中

QueryParser

将使用者輸入的(并且可讀的)查詢表達式處理為一個具體的Query對象

TopDocs

保持由IndexSearcher.search()方法傳回的具有較高評分的頂部文檔

 ScoreDoc

 提供對TopDocs中每條搜尋結果的通路接口

其中IndexSearcher是對索引中文檔進行搜尋的核心類,我們下面的例子中就會對subject域進行索引,使用的是Query的子類TermQuery。

測試程式如下:

一步一步學lucene——(第四步:搜尋篇)lucene的主要搜尋的API對特定項進行搜尋解析使用者查詢搜尋用到的各個類的互相關系搜尋結果分頁
一步一步學lucene——(第四步:搜尋篇)lucene的主要搜尋的API對特定項進行搜尋解析使用者查詢搜尋用到的各個類的互相關系搜尋結果分頁

View Code

當然在不同的情況下你可以改變其中的代碼來搜尋你想要的東西。

lucene中解析使用者的查詢需要一個Query對象作為參數。那麼也就是将Expression組合成Query的過程,這裡邊有一個對象叫QueryParser,它将前面傳過來的規則的解析成對象然後進行查詢。下面我們看下流程是如何處理的:

            圖:QueryParser對象處理複雜的表達式的過程

下面看一個程式示例,這個是基于lucene 3.0的,在後面的版本中會有所變化。

程式結構如下:

一步一步學lucene——(第四步:搜尋篇)lucene的主要搜尋的API對特定項進行搜尋解析使用者查詢搜尋用到的各個類的互相關系搜尋結果分頁
一步一步學lucene——(第四步:搜尋篇)lucene的主要搜尋的API對特定項進行搜尋解析使用者查詢搜尋用到的各個類的互相關系搜尋結果分頁

其實主要就是A和B兩部分,将規則解析成lucene能識别的表達式。

下面的表格中列出了查詢表達式的範例:

表達式

比對文檔

java

在字段中包含java

java junit

java or junit

在字段中包含java或者junit

+java +junit

java and junit

在字段中包含java以及junit

title:ant

在title字段中包含ant

title:extreme

-subject:sports

AND NOT subject:sports

在title字段中包含extreme并且在subject字段中不能包含sports

(agile OR extreme) AND methodology

在字段中包含methodology并且同時包括agile或者extreme

title:"junit in action"

在title字段中包含junit in action

title:"junit action"~5

包含5次junit和action

java*

包含以java開頭的,例如:javaspaces,javaserver

java~

包含和java相似的,如lava

lastmodified:[1/1/04 TO 12/31/04]

在lastmodified字段中值為2004-01-01到2004-12-31中間的

接下來測試一下QueryParser的各個表達式,程式結構如下:

一步一步學lucene——(第四步:搜尋篇)lucene的主要搜尋的API對特定項進行搜尋解析使用者查詢搜尋用到的各個類的互相關系搜尋結果分頁
一步一步學lucene——(第四步:搜尋篇)lucene的主要搜尋的API對特定項進行搜尋解析使用者查詢搜尋用到的各個類的互相關系搜尋結果分頁

運作程式就會得到輸出結果。

我想看圖應該會比較清晰,下面的圖比較清晰的組合了程式的結構:

      圖:搜尋用到的各個類的互相關系

其實這個所謂的分頁跟資料庫的分頁功能差不多,隻是一個是從資料庫中讀取資料,而一個是從索引檔案中找到對應的資料。

在lucene搜尋分頁過程中,可以有兩種方式:

一種是将搜尋結果集直接放到session中,但是假如結果集非常大,同時又存在大并發通路的時候,很可能造成伺服器的記憶體不足,而使伺服器當機

還有一種是每次都重新進行搜尋,這樣雖然避免了記憶體溢出的可能,但是,每次搜尋都要進行一次IO操作,如果大并發通路的時候,你要保證你的硬碟的轉速足夠的快,還要保證你的cpu有足夠高的頻率

而我們可以将這兩種方式結合下,每次查詢都多緩存一部分的結果集,翻頁的時候看看所查詢的内容是不是在已經存在在緩存當中,如果已經存在了就直接拿出來,如果不存在,就進行查詢後,從緩存中讀出來。比如:現在我們有一個搜尋結果集 一個有100條資料,每頁顯示10條,就有10頁資料。按照第一種的思路就是,我直接把這100條資料緩存起來,每次翻頁時從緩存種讀取而第二種思路就是,我直接從搜尋到的結果集種顯示前十條給第一頁顯示,第二頁的時候,我在查詢一次,給出10-20條資料給第二頁顯示,我每次翻頁都要重新查詢。

第三種思路就變成了

我第一頁僅需要10條資料,但是我一次讀出來50條資料,把這50條資料放入到緩存當中,當我需要10--20之 間的資料的時候,我的發現我的這些資料已經在我的緩存種存在了,我就直接存緩存中把資料讀出來,少了一次查詢,速度自然也提高了很多. 如果我通路第六頁的資料,我就把我的緩存更新一次.這樣連續翻頁10次才進行兩次IO操作同時又保證了記憶體不容易被溢出.而具體緩存設定多少,要看你的伺服器的能力和通路的人數來決定。

下面是一個示例程式沒有做緩存,緩存的部分可以自己實作,也可以選擇ehcache等開源的實作。

一步一步學lucene——(第四步:搜尋篇)lucene的主要搜尋的API對特定項進行搜尋解析使用者查詢搜尋用到的各個類的互相關系搜尋結果分頁
一步一步學lucene——(第四步:搜尋篇)lucene的主要搜尋的API對特定項進行搜尋解析使用者查詢搜尋用到的各個類的互相關系搜尋結果分頁

<a href="http://files.cnblogs.com/skyme/3_search.rar">[源碼下載下傳]</a>

<a href="http://www.cnblogs.com/skyme/archive/2012/07/29/2613970.html">一步一步學lucene——(第一步:概念篇)</a>

<a href="http://www.cnblogs.com/skyme/archive/2012/07/30/2615054.html">一步一步學lucene——(第二步:示例篇)</a>

<a href="http://www.cnblogs.com/skyme/archive/2012/07/31/2616213.html">一步一步學lucene——(第三步:索引篇)</a>

<a href="http://www.cnblogs.com/skyme/archive/2012/08/01/2618341.html">一步一步學lucene——(第四步:搜尋篇)</a>