排序是對於全文檢索來言是一個必不可少的功能,在實際運行中,排序功能在某些時候給咱們帶來了很大的方便,好比在淘寶、京東等一些電商網站咱們可能經過排序來快速找到價格最便宜的商品,或者經過排序來找到評價數最高或賣的最好的商品,再好比在iteye裏的博客欄裏,天天都會以降序的方式,來顯示出最新發布的幾篇博客,有了排序,咱們就能在某些時候很方便快速的獲得某些有效信息,因此說排序功能,無處不在。
java
本篇,就來看下咱們在lucene中怎麼使用其豐富的排序功能。
數據庫
在此以前,咱們先來熟悉下lucene中排序的基本知識,在默認狀況下,lucene使用是以關聯性降序的方式做爲默認的排序方式,這樣可使得咱們搜索的結果一般是最優的,由於它會盡量使得首先出現的幾個結果是與咱們搜索的內容最相關的,而不不須要咱們翻頁尋找咱們最想要的內容,這一點是與數據庫相比,是全文檢索一個很大的有點。固然,在實際開發中咱們也須要根據業務的實際狀況來個咱們的客戶提供多種不一樣的排序方式。咱們先來看下載lucene中比較特殊的兩種基本的排序方式。
編程
咱們再來看幾個檢索是須要用的方法
數組
=========SortField類============ //field是排序字段type是排序類型 public SortField(String field, Type type); //field是排序字段type是排序類型reverse是指定升序仍是降序 //reverse 爲true是降序 false爲升序 public SortField(String field, Type type, boolean reverse) =========Sort類============ public Sort();//Sort對象構造方法默認是按文檔評分排序 public Sort(SortField field);//排序的一個SortField public Sort(SortField... fields)//排序的多個SortField能夠傳入一個數組 =========IndexSearche類r======== //query是查詢的Query對象 filter是過濾 n返回的數量 sort是排序 search(Query query, Filter filter, int n, Sort sort) //doDocScores 爲true狀況下每一個命中的結果下都會被評分 //doMaxScore 爲true狀況下對最大分值的搜索結果進行評分 search(Query query, Filter filter, int n, Sort sort, boolean doDocScores, boolean doMaxScore)
一、在尚未進行一點排序前咱們先來看下索引裏的內容,核心代碼以下:
性能
TopDocs topDocs=searcher.search(new MatchAllDocsQuery(),10000);
二、使用默認的關聯性評分後,核心代碼和運行效果圖以下:網站
Sort sort=new Sort();//默認使用關聯性評分 TopDocs topDocs=searcher.search(new MatchAllDocsQuery(),10000,sort);
關於上圖中亂碼字符緣由是由於默認排序狀況下lucene是不會對搜索結果進行評分操做的,由於評分操做會下降性能,因此關於score的那一列返回的是NAN的字符串,處於格式的須要,散仙在使用DecimalFormat類給出其評分結果保留2爲小數是,由於是一個特殊字符,因此就出現了上圖狀況。(轉者注:原博主在上面代碼中沒有給出評分細則的代碼)spa
三、按照日期降序排序,核心代碼和運行效果圖以下:code
Sort sort=new Sort(new SortField("date", Type.INT,true));//true爲降序排列 TopDocs topDocs=searcher.search(new MatchAllDocsQuery(),10000,sort);
四、按照價格升序排序,核心代碼和運行結果效果圖以下:
orm
Sort sort=new Sort(new SortField("price", Type.DOUBLE,false));//false爲升序排列 TopDocs topDocs=searcher.search(new MatchAllDocsQuery(),10000,sort);
五、多字段排序,按照日期降序的狀況下,由於id爲7和8的日期相同,因此咱們就新增一個排序字段按ename升序排序,核心代碼和運行結果以下:
對象
// Sort sort=new Sort(new SortField("date", Type.INT, true),new SortField("ename", Type.STRING, false)); //這兩段代碼效果同樣 Sort sort=new Sort(new SortField[]{new SortField("date", Type.INT, true),new SortField("ename", Type.STRING, false)}); TopDocs topDocs=searcher.search(new MatchAllDocsQuery(),10000,sort);
六、帶評分的排序,注意後面兩個布爾類型的變量能夠控制是否評分,特別是在沒有要求須要打分時,建議別開啓,大數量時對性能影響較大,檢索"編程"獲得的結果,默認按評分降序排序,核心代碼和運行結果以下:
=========IndexSearche類r======== //query是查詢的Query對象 filter是過濾 n返回的數量 sort是排序 search(Query query, Filter filter, int n, Sort sort) //doDocScores 爲true狀況下每一個命中的結果下都會被評分 //doMaxScore 爲true狀況下對最大分值的搜索結果進行評分 search(Query query, Filter filter, int n, Sort sort, boolean doDocScores, boolean doMaxScore)
Sort sort=Sort.RELEVANCE; TopDocs topDocs=searcher.search(new TermQuery(new Term("bookname", "編程")),null,100,sort,true,true);
上面的編程,編程由於在切分時編程的tf出現了2次,因此在查詢時有較高的得分,因此排在首位。
七、注意幾點
(1)排序對一個文檔裏什麼域都沒有存儲,使用字符串排序會排在首位;
(2)排序對一個文檔裏什麼域都沒有存儲,使用數字類型排序會默認給其賦值爲0進行排序;
(3)咱們能夠對數字類型的null值的文檔進行代碼控制,能夠將其設置爲最大,因此將會排在最後面,代碼以下:
SortField sortField = new SortField("value", SortField.Type.INT); sortField.setMissingValue(Integer.MAX_VALUE);