學習Xapian(4) – Faceting Search(Filter)

在信息檢索中,有一類任務叫做Faceting Search,在Wikipedia中的定義如下:

Faceted search, also called faceted navigation or faceted browsing, is a technique for accessing a collection of information represented using a faceted classification, allowing users to explore by filtering available information. A faceted classification system allows the assignment of multiple classifications to an object, enabling the classifications to be ordered in multiple ways, rather than in a single, pre-determined, taxonomic order. Each facet typically corresponds to the possible values of a property common to a set of digital objects.

即可以按照分類對檢索結果進行縱覽,比如我們輸入Apple,那麼左側應該出現一個導航菜單,對結果進行分類,第一類可能是吃的水果,第二類可能是Apple公司。這個例子很明瞭了吧?

那麼如何實現這種Faceting Search呢?其本質就是一種過濾器,我們可以將分類在索引之前算好,一併存儲進索引中,然後在搜索時按照value對它進行過濾,從而達到這個效果。

1、如何創建過濾(分類)值
這個其實我們在本系列的一次《學習Xapian(1) – 基礎的建索引和搜索》中,就已經介紹過了,看看Document::add_value方法吧!

2、如何在檢索時應用過濾
一般來說有兩種方法:
(1)使用Xapian::MatchDecider,它是一個抽象類,包含一個函數,返回一個布爾數值(操作符),利用true/false控制是否將初步搜出來的結果返回到結果中。我們可以直接實現它(實現抽象方法),也可以使用它的實體類Xapian::ValueSetMatchDecider。

[構造]
Xapian::ValueSetMatchDecider(slot, inclusive),第一個是過濾第幾個slot,slot的概念見第一講,add_value。第二個決定到底是filter還是reduce(用Python的朋友知道我是什麼意思的)

[添加過濾值]
用戶可以指定一個或者多個數值的set,當doc屬於這些數值之一,則按照要求過濾或者留下。
Xapian::ValueSetMatchDecider::add_value(string)

(2)使用MatchSpy,實話講我每太看懂它什麼意思,貌似是獲取數值,但是不進行過濾?

下面我們建立兩個doc,
doc1的CLASS(slot 1)是1,
doc2分CLASS(slot 1)是2.
然後我們在取回檢索結果時應用過濾器,只選擇CLASS爲1的。

建立索引:
#include <iostream>
#include <string>
#include <xapian.h>
using namespace std;
#define DB_PATH "index_data"
#define TEXT1 "我是 文本 1"
#define TEXT2 "我是 文本 2"
#define CLASS 1
int main()
{
    //Open database
    string dbpath(DB_PATH);
    Xapian::WritableDatabase db(dbpath, Xapian::DB_CREATE_OR_OPEN);
    Xapian::TermGenerator indexer;
  
    //Create Document 1
    Xapian::Document doc1;
    doc1.add_value(CLASS, "1");
    string text1(TEXT1);
    doc1.set_data(text1);
    indexer.set_document(doc1);
    indexer.index_text(text1);
    db.add_document(doc1);
  
    //Create Document 2
    Xapian::Document doc2;
    doc2.add_value(CLASS, "2");
    string text2(TEXT2);
    doc2.set_data(text2);
    indexer.set_document(doc2);
    indexer.index_text(text2);
    db.add_document(doc2);
  
    //Commit db
    db.commit();
  
    return 0;
}

檢索並過濾:

#include <iostream>
#include <string>
#include <xapian.h>
using namespace std;
#define DB_PATH "index_data"
#define QUERY "文本"
#define CLASS 1
int main()
{
    //Open database && Search Handle
    string dbpath(DB_PATH);
    Xapian::Database db(dbpath);
    Xapian::Enquire enquire(db);
  
    //Parse Query
    Xapian::QueryParser qp;
    Xapian::Query query = qp.parse_query(string(QUERY));
    cout << "Query:\t" << query.get_description() << endl;
  
    //Set Query & Matcher Filter
    enquire.set_query(query);
    Xapian::ValueSetMatchDecider md(CLASS, true);
    md.add_value(string("2"));
    //Xapian::MSet result = enquire.get_mset(0, 10);
    Xapian::MSet result = enquire.get_mset(0, 10, 10000, NULL, &md);
  
    //Print results
    for(Xapian::MSetIterator itr = result.begin(); itr!=result.end(); itr++)
    {
        Xapian::Document doc = itr.get_document();
        cout << itr.get_rank() << ", " << doc.get_data() << endl;
    }
  
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章