[zz]學習lucene應該多看源代碼

最近在爲星網將要上線的商城系統開發搜索功能,要求使用lucene和數據庫。由於lucene是完全開源的,所以對於學習與使用lucene的人,這麼好的源代碼資源一定要看並且利用,只有多看源代碼,自身的能力纔會提高,lucene使用起來,效率也會更高。
從一個小例子中,可以看出看源代碼的好處。
商品搜索時,肯定要使用核心包下的org.apache.lucene.search.Searcher類,而這個類的search()方法有八個,其中有三個是abstract類型,被searcher的子類IndexSearcher所實現,如果只看javadoc的話,可以看到這八個方法分別是:
Java代碼
public TopFieldDocs search(Query query,
Filter filter,
int n,
Sort sort)
throws IOException
public void search(Query query,
Collector results)
throws IOException
public void search(Query query,
Filter filter,
Collector results)
throws IOException
public TopDocs search(Query query,
Filter filter,
int n)
throws IOException
public TopDocs search(Query query,
int n)
throws IOException
public abstract void search(Weight weight,
Filter filter,
Collector results)
throws IOException
public abstract TopDocs search(Weight weight,
Filter filter,
int n)
throws IOException
public abstract Document doc(int i)
throws CorruptIndexException,
IOException

其中query是搜索項,filter是過濾條件,n說明要返回前n個搜索到的結果,sort是搜索結果的排序方式,Collector也是用來指定返回結果中執行排序與過濾信息的。
在javadoc中,還可以看到這八種方法的一些粗略介紹,大概告訴你這些方法是怎麼用的。
現在如果已經給定你一個query,而在前臺搜索界面是這樣的:給了價格區間選項,用戶可以指定價格區間,也就是填入兩個價格去過濾搜索結果,此時應該使用filter構造過濾條件,當然用戶也可以不指定價格區間,也就是不用過濾搜索結果到某一特定的價格區間,此時,看到javadoc中上面幾種search方法,你可能會這樣想:在後臺的控制邏輯裏面,也就是action與service(impl)中,去判斷一下用戶到底有沒有輸入價格信息,如果輸入了,則調用上面第1種或第4種方法(第三種方法雖然也包含filter條件,但是返回類型爲void,肯定不行),而如果用戶沒有輸入價格過濾信息,就使用第5種方法。
按照上面的邏輯你會寫出下面這樣的代碼:
Java代碼
IndexSearcher searcher =new IndexSearcher(FSDirectory.open(new File(INDEX_PATH)));
if(min != null && max != null) {
Filter filter = new TermRangeFilter("price",NumberUtils.pad(MIN), NumberUtils.pad(MAX), true, true);
TopDocs td = searcher.search(query, filter, TOP_NUM);
}
else {
TopDocs td = searcher.search(query, TOP_NUM);
}

上面代碼中,由於IndexSearcher是Searcher的子類,所以IndexSearcher繼承了Searcher的五種search方法,實現了Searcher的三種抽象方法。
而如果你的query也需要判斷構造的話,那麼在構造query時,每有一個判斷分支,上面的代碼就要寫進去一次,十分麻煩。
但是如果你看過Searcher以及IndexSearcher的源代碼,情況就不同了,你可以看到上面提到的search方法的源代碼如下:
Java代碼
public TopFieldDocs search(Query query, Filter filter, int n, Sort sort) throws IOException {
return search(createWeight(query), filter, n, sort);
}
public void search(Query query, Collector results)
throws IOException {
search(createWeight(query), null, results);
}
public void search(Query query, Filter filter, Collector results)
throws IOException {
search(createWeight(query), filter, results);
}
public TopDocs search(Query query, Filter filter, int n)
throws IOException {
return search(createWeight(query), filter, n);
}
public TopDocs search(Query query, int n)
throws IOException {
return search(query, null, n);
}

還可以看到子類IndexSearcher實現的三種抽象方法的實現.
或許從上面代碼中你已經看出了玄機,那就是上面五種search方法實際上調用的只有一兩個核心的search方法而已,而且Searcher中五個方法在IndexSearcher中有三個都被重寫(override)了。
而且你可以看到其實那兩個核心的search方法,也就是被其他search方法多次調用的,構造中都包含filter條件,只不過有的是null而已,所以我們的搜索代碼完全沒必要根據價格過濾信息的有無來分別寫流程,因爲如果有價格過濾信息的話,filter就是你構造的價格過濾條件,如果用戶沒有輸入價格過濾信息的話,filter只需爲null即可。
所以我們的代碼可以修改爲:
Java代碼
Filter filter = null;
if(min != null && max != null)
filter = new TermRangeFilter("price",NumberUtils.pad(MIN), NumberUtils.pad(MAX), true, true);

然後這個filter就是通用的了。
我們的例子中調用IndexSearcher的search並不是IndexSearcher中的方法,因爲我們的條件都包含Query,而IndexSearcher的search方法中都沒有包含Query條件,而是Weight條件,而此Weight都是在Searcher的search方法中進一步調用其他類型的search方法,而此時調用的search方法已經是IndexSearcher中的search方法了,這裏面的邏輯需要搞清楚。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章