『壹』 為什麼說Lucene不好
在Lingway公司,我們使用了Lucene至進今已有好幾年時間。對那些剛接觸Lucene的人來說,這里是使用它的關鍵:Apache Lucene是一個由java編寫的高性能,全方位的單詞搜索引擎庫。
在批評它之前,我必須承認Lucene是一個高性能的劃詞搜索引擎。幾年來,Lucene已經被看作是用java編寫的嵌入式搜索引擎中的一等公民。它的聲譽每日劇增,並且仍然是開源java搜索引擎中的最佳。每個人都在說:「Doug Cutting做了一項偉大的工作」。然而,最近的幾個月內,開發的進程變得緩慢,我認為Lucene將不會滿足現代的文檔處理需求。不要把東西搞糟:我不是搜索引擎開發者,我只是個開發者,使用搜索引擎,來提供合適信息的檢索科技。
Lucene不是最好選擇,至少對我們而言如此,並且情況並沒有得到改變。我們列出Lucene的局限性:Lingway公司基於語意來生成復雜的查詢。例如當你正在查找關於「中東地區沖突」的文章,你也許還需要找關於「伊拉克戰爭」文章。在上面這個用例中,「戰爭」和「伊拉克」分別是「沖突」和「中東」的擴展。我們使用一種技術能分析你的查詢,產生相應的最合適的擴展,為它們生成查詢。然而,為了得到相關的結果,這些還是不夠的:通過Lucene實現的類似Google的等級或是經常變化積分的並不能滿足語意級別積分。例如,一個包含「中」和「東」短語,但是被超過一個以上的單詞隔開,這種情況並不是我們想要查找的。更重要的是,相對常規的單詞,我們應該給擴展更低的分數。比如,我們應該給「中東地區沖突」這個短語更高的分數,而不是「伊拉克戰爭」。
在Lingway公司,我們認為這種文章相關性技術是一種未來的搜索引擎。Google在文章搜索上做的很出色。但我們想要的卻是最相關的文章。但是,大部分的當代搜索引擎都沒有對這樣復雜查詢做相關的設計…Lucene被wikipedia使用,如果你注意到當你查詢查過一個單詞時,大多數的查詢結果並不是由關聯的…
為了演示需求,這里有一個Lingway公司即將上線的KM3.7產品的界面截圖。這里我們用法語寫一個查詢,用來查找那些同樣主題,而用英語寫的文章。注意,這可不僅僅是簡簡單單的翻譯,我們稱之為語言交叉模式:
注意到那些綠色的匹配:chanteur變成了singer,但是我們也發現singing被匹配了。同樣情況流行樂成為藍調的擴展。
6大理由不選用Lucene
6. 沒有對集群的內置支持。
如果你創建集群,你可以寫出自己對Directory的實現,或是使用Solr或者使用Nutch+Hadoop。Solr和Nutch都支持Lucene,但不是直接的替代。Lucene是可嵌入的,而你必須支持Solr和Nutch..我認為Hadoop從Lucene團隊中產生並不驚訝:Lucene並不是通用的。它的內在性決定了對大多數場合來說它是非常快速的,但是對大型文檔集合時,你不得不排除Lucene。因為它在內核級別上並沒有實現集群,你必須把Lucene轉換到別的搜索引擎,這樣做並不直接。轉換到Solr或者Nutch上的問題會讓你遇到許多不必要的麻煩:Nutch中的集成crawling和Solr中的檢索服務。
5.跨度查詢太慢
這對Lingway公司來說可能是個特殊的問題。我們對跨度查詢有很強要求,Lucene檢索結構已經開始添加這一細節,但它們當初可沒這么想。最基礎的實現導致了復雜的演算法並且運行緩慢,尤其是當某些短語在一份文檔中重復了許多次出現。這是為什麼我傾向說Lucene是一個高性能的劃詞檢索引擎當你僅僅使用基本的布爾查詢時。
4.積分不能被插件化
Lucene有自己對積分演算法的實現,當條件增加時使用Similarity類。但很快它顯示出局限性當你想要表示復雜的積分,例如基於實際匹配和元數據的查詢。如果你這樣做,你不得不繼承Lucene的查詢類。因為Lucene使用類似tf/idf的積分演算法,然而在我們遇到的場合,在語意上的積分上Lucene的積分機制並不合適。我們被迫重寫每一個Lucene的查詢類使得它支持我們自定義的積分。這是一個問題。
3.Lucene並非良好設計
作為一個系統架構師,我傾向認為(1)Lucene有一個非常糟糕的OO設計。雖然有包,有類的設計,但是它幾乎沒有任何設計模式。這讓我想起一個由C(++)開發者的行為,並且他把壞習慣帶到了java中。這造成了,當你需要自定義Lucene來滿足你的需求(你將來必定會遇到這樣的需求),你必須面對這樣的問題。例如:
<!--[if !supportLists]--> <!--[endif]-->幾乎沒有使用介面。查詢類(例如BooleanQuery,SpanQuery,TermQuery…)都是一個抽象類的子類。如果你要添加其中的一個細節,你會首先想到寫一個介面來描述你擴展的契約,但是抽象的Query類並沒有實現介面,你必須經常的變化自己的查詢對象到Query中並在本地Lucene中調用。成堆的例子如(HitCollecor,…)這對使用AOP和自動代理來說也是一個問題.
<!--[if !supportLists]--> <!--[endif]-->別扭的迭代實現.沒有hasNext()方法,next()方法返回布爾類型並刷新對象內容.這對你想要保持對迭代的元素跟蹤來說非常的痛苦.我假定這是故意用來節省內存但是它又一次導致了演算法上的雜亂和復雜.
2.一個關閉的API使得繼承Lucene成為痛苦
在Lucene的世界中,它被稱之為特性。當某些用戶需要得到某些細節,方針是開放類。這導致了大多數的類都是包保護級別的,這意味著你不能夠繼承他們(除非在你創建的類似在同一個包下,這樣做會污染客戶代碼)或者你不得不復制和重寫代碼。更重要的是,如同上面一點提到的,這個嚴重缺乏OO設計的結構,一些類應該被設為內部類卻沒有,匿名類被用作復雜的計算當你需要重寫他們的行為。關閉API的理由是讓代碼在發布前變得整潔並且穩定。雖然想法很光榮,但它再一次讓人感到痛苦。因為如果你有一些代碼和Lucene的主要思路並不吻合,你不得不經常回歸Lucene的改進到你自己的版本直到你的補丁被接受。
然而當開發者開始越來越長的限制API的更改,你的補丁很少有機會被接受。在一些類和方法上加上final修飾符會讓你遇到問題。我認為如果Spring框架有這樣的限制,是覺不會流行起來。
<!--[if !supportLists]-->1. Lucene搜索演算法不適合網格計算<!--[endif]-->
Lucene被寫出來的時候硬體還沒有很大的內存,多處理器也不存在。因此,索引結構是被設計成使用線性的內存開銷很小的方式。我花了很長的時間來重寫跨度查詢演算法,並使用多線程內容(使用雙核處理器),但是基於迭代器的目錄讀取演算法幾乎不能實現。在一些罕見的場合你能做一些優化並能迭代一個索引通過並行方式,但是大多數場合這是不可能的。我們遇到的情況是,當我們有一個復雜的,超過50+的內嵌跨度查詢,CPU還在空閑但I/O卻一直忙�擔踔獵謔褂昧薘AMDirectory.
有沒有替代品?
我認為最後一個觀點充滿疑問:Lucene到達了它的極限當它在現在硬體基礎的條件下,檢索大型數據集合時。那就是我為什麼尋找下一個可以替代Lucene的出現。在閱讀了博客目錄和 Wikia的討論後,我發現並沒有很多的替代品。然而我最後推薦一個有希望的方案:MG4J。它有一個良好的面向對象設計,性能良好的檢索(索引比Lucene慢),內存開銷上也很小,達到10倍於Lucene速度的跨度查詢,在我的跨度查詢基準上,並且是原生上支持集群。同樣它也內置了負載平衡,而Lucene最近才加入這項功能並且還是實驗性質的。然而MG4J仍然缺少一些特性例如簡單的索引指數,文檔移除和更簡單的使用索引處理。讓我感到高興的是我可以自定義Lucene上的功能在MG4J上只需花幾個小時,而在Lucene上卻需要數天。
我認為對開源的搜索引擎來說仍然有發展空間,它不是通過單台電腦用有限的內存來索引批量文檔,而是通過透明的分布式索引來提供對大型數據集合檢索更為快捷的答案。你不必利用應用來獲得集群特性。Lucene對第一類搜索引擎有了很好的實現,單我認為它並不符合我們的需求:在一個合理的時間內找到最佳的答案。基於tf/idf的搜索演算法和google的等級並不是未來搜索引擎的趨勢。實現對原數據和語義的復雜查詢並找出相關的信息,這是Lingway公司(通過Lucene和其他搜索引擎技術)所作的,不過它要求有更多支持新硬體的新技術。
使用Lucene的一個好理由
無論我如何指責Lucene,它仍然是java開源解決方案中的最佳實現。
『貳』 用Lucene searchafter分頁,怎樣排序
TopFieldDocs tds = searcher.search(query, num, sort);
return (FieldDoc) tds.scoreDocs[num - 1];
在獲取上一頁最後一個ScoreDoc方法中,也需要將sort傳入。 TopDocs tds = searcher.search(query, num, sort); return tds.scoreDocs[num - 1];