Xapian 是一款开源的C++信息检索系统,内部系统试用了xunsearch,因此稍微了解了一下“虾片”的机制
先看一下执行过程:
检索相关:
Xapian::Database 用于读取索引。
Xapian::Enquire 提供检索服务,与Xapian::Database配合使用
Xapian::QueryParser 查询语句解析器
Xapian::Query 查询语句
Xapian::MSet 检索返回的匹配结果记录集
建索引相关:
Xapian::WritableDatabase 用于建立索引。
Xapian::TermGenerator 非常简单的切词、建索引器,不是必须使用的,可用其他替代,但是提供了一些帮助函数,非常好用。
共用:
Xapian::Document 文档的抽象。
Xapian::SimpleStopper 停用词
Xapian::Error 异常类,.get_description()获取详细信息。
后端相关:
Xapian::Database::Internal 每个后端都要实现
Database,也可以称为Index
Database类型
- auto
-
- brass
- 当前开发中的后端,并将作为1.4.x版本起的默认后端
- chert
- 1.2.x的默认后端,支持增量修改、单写者+多读者的并发。
- 高效且可扩展
- flint
- 1.0.x的默认后端,类chert
- inmemory
- 全内存的database,可用于建立临时小database
- quartz
- 1.0的默认后端,1.1.0后移除
文档
- 粒度
- RMDB:表中的一条记录
- html:一个html文件/一个标签
- 表示方式
- 32位 Document ID
- 3个组分
- 数据data
- 只存储,不分析其内容,通常用于结果的返回
- 是文档的部分/全部数据
- 词集terms
- 基本的查询单元
- 值域集values
分词器
- xapian没有Field的概念,通过在每个词前加前缀来标识
-
需要注意的是,在Xapian中,如果你在索引的时候使用了TermGenerate来进行分词,那在查询的时候一定要使用QueryParser来对查询条件进行解析
索引
一些限制:
- Term Length:一个词限制在256个字节内,
- Document Data:一个data区不能大于100MB,默认是8KB
- Document value:和一个data区的限制是一样的,但一般建议value不要太大
- Document ID: 当前范围是32bit,大概在43亿左右,文档删除的ID号不会被重新利用,除非你对数据库进行compact
- B-tree block number: 目前支持最大为32bit个块
- OS file size:所有操作系统对于单个文档的限制对于Xapian都适用,如ext4对于单个文件的大小为16TB,
- Document length:文档长度的存储限制为unsigned 64bit
索引格式
- Xapian有多种数据库格式
分面搜索(faceted search)
- 将搜索结果进行聚类处理
并行读写操作
- 写
-
数据库只支持单个数据库写对象存在
-
也就是说在创建一个DataBaseWritable对象的时候,会对数据库进行加锁,如果另一个写数据库对象再去写这个数据库时,会出现DatabaseLockError错误。
- 读
-
但是多个读对象是同时存在于同一个数据库。
- 更新
-
读/写操作隔离
-
当打开一个数据库准备进行读操作时,会创建一个找开数据库的镜像,这样有写操作时,读对象是不可见的,除非读对象运行reopen()操作。
- 限制
-
现在的Xapian多版本同步还是有一些限制的,特别是当数据库有两个版本同时存在时,也就是说有多个读,一个写数据库操作时,当写数据库只修改了数据库,运行了一次commit时,是没问题的,但是当写数据库又运行了第二次commit时,读数据库操作会收到了一个Xapian::DatabaseModifiedError,在这种情况下,读数据库操作要更新其数据库的镜像版本,使用reopen()操作,这个要在编程上注意一下。
数据同步
- 同时支持数据库的复制,而且只复制那些变更过的索引数据,这样可以使用数据冗余,达到负载均衡的目的
常见问题
- DatabaseLockError错误
- 数据库只支持单个数据库写对象存在,也就是说在创建一个DataBaseWritable对象的时候,会对数据库进行加锁,如果另一个写数据库对象再去写这个数据库时,会出现DatabaseLockError错误
- 但是多个读对象是同时存在于同一个数据库。
- DatabaseModifiedError错误
- 当打开一个数据库准备进行读操作时,会创建一个找开数据库的镜像,这样有写操作时,读对象是不可见的,除非读对象运行reopen()操作。这样读/写操作就隔离了。
- 现在的Xapian多版本同步还是有一些限制的,特别是当数据库有两个版本同时存在时,也就是说有多个读,一个写数据库操作时,当写数据库只修改了数据库,运行了一次commit时,是没问题的,
- 但是当写数据库又运行了第二次commit时,读数据库操作会收到了一个Xapian::DatabaseModifiedError,在这种情况下,读数据库操作要更新其数据库的镜像版本,使用reopen()操作。
- 多线程支持
- Xapian没有显示的支持多线程,为了避免不必要的线程死锁,Xapian没有使用任何全局变量,所以你可以你的多线程应用中放心的使用Xapain对象。
- 但是一些Xapian对象内部是有关联的,如Xapian::Database::get_document(),返回的对象Xapian::Document对象内部保存了一个指向DataBase的一个引用,所以它不适合在多线程中使用,所以在多线程中使用Xapian的时候还是要注意一些东西的。