Xapian索引-文檔檢索過程分析之匹配百分比

    本文屬於文檔檢索過程分析的一部分,重點分析文檔匹配百分比(percent)的計算過程。html

1 percent是什麼?算法

    咱們以前分析的檢索demo:api

Xapian::Query term_one = Xapian::Query("T世界");
Xapian::Query term_two = Xapian::Query("T比賽");
Xapian::Query query = Xapian::Query(Xapian::Query::OP_OR, term_one, term_two); // query組裝

std::cout << "query=" << query.get_description() << std::endl;

Xapian::Enquire enquire(db);
enquire.set_query(query);
Xapian::MSet result = enquire.get_mset(0, 10); // 執行檢索,獲取結果
std::cout << "find results count=" << result.get_matches_estimated() << std::endl;

for (auto it = result.begin(); it != result.end(); ++it) {
    Xapian::Document doc = it.get_document();
    std::string data = doc.get_data();
    double doc_score_weight = it.get_weight();
    /// 匹配百分比
    int doc_score_percent = it.get_percent();
    std::cout << "doc=" << data << ",weight=" << doc_score_weight << ",percent=" << doc_score_percent << std::endl;
}
percent就是 int doc_score_percent = it.get_percent(); 這裏獲取的文檔匹配百分比。

2 爲何須要percent?ide

    先說一下背景,作過搜索的人應該都知道BM25算法,這也是xapian內部默認的相關性打分算法,它是一個針對term作打分的公式。這個公式能夠分爲三個部分,第一部分跟term的idf有關,第二部分跟term在doc的權重有關,第三部分跟term在query中的權重有關(能夠參考這裏理論分析部分的介紹)。公式第一部分的idf是以索引庫中的文檔來統計的,第二部分中用到的文檔平均長度,也是以索引庫中的文檔來計算的,當咱們的數據含有多個業務,而且每一個業務有獨立的索引庫時,相同term的idf在不一樣索引庫中差異可能很大,而idf又是BM25公式中一個很重要的因子,這就可能致使同一個query在A庫中搜索出來的doc BM25打分永遠比在B庫中搜索出來的要高,而且,xapian的打分支持term-boost的(打分系數),乘上係數以後,BM25打分值差距可能就更大了。因此,咱們不能也不該該直接拿BM25打分來比較哪一個doc更相關,咱們須要一個歸一化後的數值,這就是percent。ui

3 percent是怎麼算出來的?spa

    percent是某個doc跟query的相關性歸一化分值,是爲作相關性打分排序而存在的,它的基本原則是:歸一化。code

    分紅兩個層面,首先是term匹配個數:匹配個數爲分子,query term個數爲分母,term匹配的越多,percent越高;而後是term匹配個數同樣多時,某個doc的BM25打分爲分子,最大的doc BM25打分爲分母,BM25打分越高,percent越高。htm

    相關代碼:blog

void MultiMatch::get_mset(Xapian::doccount first, Xapian::doccount maxitems,
             Xapian::doccount check_at_least,
             Xapian::MSet & mset,
             Xapian::Weight::Internal & stats,
             const Xapian::MatchDecider *mdecider,
             const Xapian::KeyMaker *sorter) {
......
    {
        /// greatest_wt_subqs_matched 表示最大的匹配query數
        /// total_subqs 表示總query數
/// percent_scale是計算percent的一個因子,後面會看到怎麼用
percent_scale = greatest_wt_subqs_matched / double(total_subqs); percent_scale /= greatest_wt; } ...... }
int MSet::Internal::convert_to_percent_internal(double wt) const {
    LOGCALL(MATCH, int, "Xapian::MSet::Internal::convert_to_percent_internal", wt);
    if (percent_factor == 0) {
        RETURN(100);
    }
    /// wt是文檔的打分,percent_factor是以前計算的 percent_scale * 100
    // Excess precision on x86 can result in a difference here.
    double v = wt * percent_factor + 100.0 * DBL_EPSILON;
    int pcent = static_cast<int>(v);
    LOGLINE(MATCH, "wt = " << wt << ", max_possible = " << max_possible << " =>  pcent = " << pcent);
    if (pcent > 100) pcent = 100;
    if (pcent < 0) pcent = 0;
    if (pcent == 0 && wt > 0) pcent = 1;

    RETURN(pcent);
}

     以上就是xapian源碼中percent的計算過程。排序

4 percent並不適用全部場景

    percent是歸一化後的相關性分值,從上面的分析,咱們知道它的計算方式很是依賴匹配詞個數,若是隻用percent的方式來作匹配doc的排序,會有一個明顯的缺陷: 當某term(詞)極其重要時,percent值可能難以有所體現,譬如:有檢索語句:A or B or C,其中,A term的重要性極高,只要它匹配了就認爲相關性高達90%,而B、C term不重要,加起來只有10%的權重。若是是採用BM25的分值,咱們能夠經過對A term加權到極大,保證A term匹配到的doc的BM25打分比B、C term匹配到的高一個數量級。可是,若是採用了percent,則命中B term和C term的percent值在2/3左右,而只命中A term的percent值在1/3左右,這樣子沒法體現A term的重要性。解決辦法有不少,譬如:既使用percent(歸一化後的BM25打分)又使用score(BM25打分),綜合考慮;或者,將A term設置爲必出詞(And語法),這樣子保證了召回的doc(文檔)中A詞一定出現,doc之間的排序就變成了只會在含有A詞的doc之間排。

相關文章
相關標籤/搜索