Xapian 學習筆記 3 相關欄位的排序
在Xapina中,命中文檔的排序是以文檔的相關度降序來做的,當兩個文檔的相關度一樣時,按文檔id的升序來做,你也可以通過設定enquire.set_docid_order(enquire.DESCENDING)來把其變成降序,或者設定成不關心文檔id的排序enquire.set_docid_order(enquire.DONT_CARE);當然這個排序也可以按其它規則來做,或者其它規則與相關度結合來做,下面我們就分析這兩種排序方法。
1. 相關度排序
Xapian預設是以BM25演算法來計算每一個文檔的分數,而BM25(http://xapian.org/docs/bm25.html)的計算所需要的一些參數值是通過在文檔索引的時候統計出來的,當然,有一些參數可以在查詢的時候動態設定。
另外一些庫內建的加分演算法有TradWeight,BoolWeight。其中TradWeight實現了最原始的機率模型公式,它是BM25演算法的一個特例,只是其中一些參數如k2=0,k3=0和min_normlen=0。而BoolWeight打分器對所有文檔的分數都為0,文檔的排序由另外一些因素決定。
當然你也可以自訂自己的加分器演算法,只要實現Xapian::Weight這個抽象類別就可以了,如下是一個同等加分器
class CoordinateWeight : public Xapian::Weight { public: CoordinateWeight * clone() const { return new CoordinateWeight; } CoordinateWeight() { } ~CoordinateWeight() { } std::string name() const { return "Coord"; } std::string serialise() const { return ""; } CoordinateWeight * unserialise(const std::string &) const { return new CoordinateWeight; } Xapian::weight get_sumpart(Xapian::termcount, Xapian::doclength) const { return 1; } Xapian::weight get_maxpart() const { return 1; } Xapian::weight get_sumextra(Xapian::doclength) const { return 0; } Xapian::weight get_maxextra() const { return 0; } bool get_sumpart_needs_doclength() const { return false; }};
在查詢的時候可以調用Enquire的set_weighting_scheme方法來注入自己的加分器。
2. 特定欄位值排序
當然,Xapian還可以按使用者指定的欄位值來排序,如價格,日期等欄位,要注意的是所有的排序比較都是基於字串來做的,所以如果你要對價格進行排序比較,就要把數實值型別轉換成一個字串類型,使用Xapian::sortable_serialise()來進行編碼,在查詢的時候使用Xapian::sortable_unserialise()進行解碼,value索引的般代碼如下:
Xapian::Document doc;
doc.add_value(0, Xapian::sortable_serialise(price));
所有要排序的欄位值都要被加入Docuemnt的value中,第一個參數是value的slotId號
這裡有三種方法來決定文檔的排序優先順序:
- Enquire::set_sort_by_value() 以value為優先進行排序,與相關度無關
- Enquire::set_sort_by_value()_then_relevance() 以value為優先,如果value一樣的,再以相關度進行排序
- Enquire::set_sort_by_relevance_the_value() 以相關度優先排序,再以value排序
在查詢的時候要加入不同value的排序代碼如下:
// 產生一個多欄位的文檔key產生器
Xapian::MultiValueKeyMaker *keyMaker = new Xapian::MultiValueKeyMaker(); keyMaker->add_value(0); // 添加文檔的第0個slot的值為升序, keyMaker->add_value(1); // 添加文檔的第1個slot的值為升序,如果想用降序,使用keyMaker->add_value(1,true); enquire.set_sort_by_key(keyMaker,false); // 把key產生器注入到會話中去,第二個參數表示是否降序
當然更加靈活的方法是使用者可以實現keyMaker介面,實現自己的key產生器,當然key的比較是以字串來進行比較的。
3. 參考
http://xapian.org/docs/sorting.html