xapian搜索系统存储结构解读

  Xapian的database是所有用于检索的信息表的集合,以下的表是必需的:
  1. posting list table 保存了被每一个term索引的document,实际上保存的应该是document在database中的Id,此Id是唯一的。这个就是倒排表。
  2. record table 保存了每一个document所关联的data,data不能通过query检索,只能通过document来获取。这个相当于快照。
  3.  term list table 保存了索引每个document的所有的term。这个相当于正排表。
  4.  position list table 保存了每一个Term出现在每一个document中的位置。就是term位置表。

  其他可选的表还包括,value table 保存了每一个document的values,values是用作保存、排序或其它作用的。 + spelling table 保存了拼写纠正的数据。 + synonym table 保存术语的字典,例如NBA、C#或C++等。

  目前最新版本的xapian,一个表一般会包含三个数据,如termlist表会被存储为以下三个文件“termlist.baseA”、“termlist.baseB”、“termlist.dB”。在这些文件中,其实只有”.db”文件存储了真实的数据,“.baseA”和“baseB”文件是用作跟踪如果于“.dB”文件中查找数据。

 

图 1 一个实际的xapian文件列表示意图

  term可以用作有效地查找它的posting list,在posting list里,每一个document带有一个很短的标识符,就是document id。简单来说,一个posting list可以被认为是一个由document ids组成的集合。而term list则是一个字符串组成的集合。在某些IR系统的内部是使用数字来表示term的,因此在这些系统中,term list则是数字组成的集合,而Xapian则不是这样,它使用原汁原味的term,而使用前缀来压缩存储空间。
 
一个例子:
    Xapian::Document doc;
    doc.add_term("K你好");
    doc.add_term("K那里");
    //posting是带position的term
    doc.add_posting("K吃饭", 14);
    doc.add_posting("K玩耍", 8);
    /*
    这里最好先用一个map<string, int>放置value的名称和索引的配对
    这里使用起来像Lucene的SortField一样了。
    */
    doc.add_value(1, "1");
    doc.set_data("你好啊,在那里玩耍呢?还没吃饭吗?");
    //创建一个可写的db
    Xapian::WritableDatabase db("c:\\db");
    //将document加入到db中,返回document的id,此id在db中是唯一的
    Xapian::docid id = db.add_document(doc);
    //刷新到硬盘中
    db.flush();

获取document信息的例子:

//获取
    Xapian::Document doc = db.get_document(id);
    string v = doc.get_value(1);
    printf(v);//输出
    string data = doc.get_data();
    printf(data);//输出"你好啊,在那里玩耍呢?还没吃饭吗?"
    for (Xapian::TermIterator iter = doc.termlist_begin(); iter != doc.termlist_end(); ++iter)
    {
        printf(*iter);//依次输出term和posting
    }


读取倒排列表(posting table的例子)
相关的类主要有两个,一个是PositionIterator,一个是PostingSource
其中
PositionIterator用来遍历一个term的所有docid列表
PostingSource则用来提供postings的扩展数据资源。

string t_name = "K你好";
cout<<"is exist "<<db.term_exists(t_name) <<endl;
PostingIterator term_begin = db.postlist_begin(t_name);
PostingIterator term_end = db.postlist_end(t_name);

for (PostingIterator iter=term_begin; iter != term_end ; iter++)
{
cout<<"doc id "<<*iter<<endl; //读取docid
cout<<"term freq "<<iter.get_wdf()<<endl; //读取文档内词频,tf
}

 

posted on 2013-08-28 13:49  排行榜技术  阅读(898)  评论(0编辑  收藏  举报

导航