学习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;
}

Leave a Reply

Your email address will not be published.