XAPIAN简介(三)

2022-04-27 00:00:00 数据 文件 压缩 数据结构 在这里

今天主要介绍的是Xapian::Database这个类。先上图


  
看上去就很恐怖的吧,我们一点点的说。
首先一切的开始都来自那个include文件夹中的database.h,他的直接实现是在omdatabase.cc中,此外在common文件夹中还有一个database.h这个文件是DataBase的私有类指针的声明,在backends/database.cc中给出了这个私有类的实现,当然这个类其实是个抽象类,他把Database的所要实现的功能都抽象出来了,并且他也是个私有类,对外也是隐藏的,并且代码的编译速度也会变快,因为pimpl技术。那么既然抽象类关键的就在于new的地方了,因为这里会实现多态的。在这里xapian把Database这个类的实现写在了两个文件!!!相对摆架子的部分在前面我说的omdatabase.cc中。而真正关键的就是这个类的构造函数,这里会给出internal的实现。这个关键的代码在dbfactory.cc中。在dbfactory.h和dbfactory.cc中我们在这里被多态了。
在使用中xapian大家有时候可能会这样的写法Xapian::WritableDatabase(Xapian::Brass::open(fullpath, Xapian::DB_CREATE_OR_OPEN, XAPIAN_BLOCK_SIZE))
在这里我们open()的方法其实调用的是不同的backends的writedatabase的构造函数,然后得到这个类再去用Xapian::WritableDatabase的拷贝构造函数实现了不同的backends做事。此外internal是个接口类这里根据宏我们对其进行了不同的new。


 
在这里我们才进入了真正的database的处理。下面我就以brassdatabase为例,讲述database的实现。各位看官赶紧刷卡上车,我们开车了。
class BrassDatabase : public Xapian::Database::Internal,说个有意思的,他把基类的虚函数写在了子类的私有方法里面,当然多态之后,还是进入了子类中的那个方法。在这个类中我们可以清晰的看到了Xapian的数据库文件的构成了,这个BrassDatabase类聚合了7个类:
BrassPostListTable(不压缩数据)
BrassPositionListTable(不压缩数据)
BrassTermListTable(压缩数据)
BrassValueManager
BrassSynonymTable(压缩数据)
BrassSpellingTable(压缩数据)
BrassRecordTable(压缩数据)
这里的类大家对他的印象参照我篇文章给出的xapian的概念,这里不再重复,我主要给大家说下各自的实现。
首先BrassPostListTable,BrassTermListTable,BrassSynonymTable,BrassSpellingTable这四个类继承于BrassLazyTable,而BrassRecordTable,BrassPostListTable这两个类继承于BrassTable。
BrassValueManager这个类比较有意思他其实可以看成是BrassPositionListTable,BrassTermListTable这两个类的组合。在这里我把xapian的value概念看成了特殊的term。value除了维护了一个和term一样的概念PostListTable,而且本身的value是排序的放置的,其中维护所有Value的状态
Xapian::doccount freq; (一个slots对应的value对应的document的个数)
std::string lower_bound;(一个slots对应的value低值)
std::string upper_bound;(一个slots对应的value大值)

这个结构体叫ValueStats。然后本身还维护了一个结构,这个结构保存了document id,slots,value三者的对应关系。
std::map<Xapian::valueno, std::map<Xapian::docid, std::string> > changes;

我们接着聊其他的6个类,首先前面说到了BrassLazyTable和BrassTable,BrassLazyTable继承于BrassTable。他们区别就在于BrassTable默认不压缩数据,我们的xapian采用zlib技术来压缩数据。
BrassTable(const char * tablename_, const std::string & path_,
bool readonly_, int compress_strategy_ = DONT_COMPRESS,
bool lazy = false);
1
2
3
4
5
6
7
在Xapian里面的基类都不是摆设,很多时候做事的主要都是基类在做,(此基类非抽象类)。在这个BrassTable中使用了 BrassTable_base完成了B树的数据结构,也就是插入树的相应位置(原谅小弟才疏学浅这个充满位运算和B树的数据结构类我基本是略过了。。。),在完成了B树的插入之后调用write_to_file方法完成数据写入也就是类似于fopen,Xapian本身是单写多读的,他运用了fcntrl文件锁的方式。这个部分也是写在了BrassTable类中。BrassTable位于底层真正读写数据库文件就在这里,而在这之上的那6个类维护了数据在进程中的关系。Value这个类应该是被拆解出BrassPositionListTable,BrassTermListTable记录到数据库中。
说到底,我们再回来到开始Xapian::Database中,Xapian::WritableDatabase继承自Xapian::Database,前面Xapian::Database有的他都有,你结合我的章和这一章,我觉得你应该有一个数据分析存储提交的大概流程了吧,这里的PositionListTable即传说中的倒排索引的概念我讲得不好,推荐大家看下这个http://www.cnblogs.com/chenying99/p/3149233.html
然后再到我们xapian来,他是一层层后到BrassTable中写入了数据。
后说下Xapian::WritableDatabase中事务的实现。
begin_transaction(bool flushed)
commit_transaction()
cancel_transaction()
begin_transaction对外是默认flushed=true。调用他的时候,他会把开始事务之前的数据从内存也就是我前面提到的七个类维护的数据结构中写到文件中,再然后他会把transaction_state = TRANSACTION_FLUSHED;然后你开始数据写操作,数据先写入了七个类中的数据结构中,当你需要cancel_transaction()就清除七个类的数据结构中保存的数据就好了,你commit_transaction()就提交到磁盘。因为数据不是随写随提交,而是有个写数据先到内存保存根据你的commit请求再从内存到文件,才有了可方便的撤销事务。
有些的不好的地方大家多多指教,我这边文章其实重点还是说数据的写,下面一篇会写到数据的读。
上面的UML可能图太大,我截取了两个局部的。



————————————————
版权声明:本文为CSDN博主「RobotZKB」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/ZHOUKUANBIN/article/details/51034182

相关文章