参考http://www.manning.com/hatcher3
或者看《Lucene in action》第二版中关于Hot backup部分,也可以直接采用下面的代码。
为什么要热备份
- Lucene对索引是没有保证的(说的有点别扭原文用词是guarantee),意思是因为各种原因导致的索引破坏,这个真的不能怪它,倒排索引使用了大量类似指针链的方式来记录数据,所以部分的损坏就会导致整个完蛋。当然这不是说它就不可靠了,os也有crash的时候,大多数时候还是非常稳定的;
- 索引备份采用最多的当然是拷贝,可是在IndexWriter打开的情况下索引文件是不稳定实时变化的,所以必须在IndexWriter关闭的情况下才能拷贝。对于一个在线的网站来说这个是不能忍受的,特别是对于数据量比较大的站点,拷贝可能需要很长时间;
- 倒排索引之所以快是因为花费了大量时间先做分词,所以当索引crash后变成了不可再利用的垃圾,最好的办法也是官方推荐的办法就是重建,为了不让用户等待太久,最好的当然是从一个现有的最近的备份来恢复更新;
- 很多站点不允许停止搜索服务去备份,咱也不愿意大半夜去备份不是;
热备份
最理想的方式就是能always online的前提下备份,于是在2.3版本中引入了SnapshotDeletionPolicy,它的原理就是lucene可以保留一个commit了,这个commit就是snapshot,我觉得这是个很牛比的东西,就跟数据库的snapshot一样,不是谁都能轻轻松松做出来的,下面是实现新建一个保留最后一次提交策略的IndexWriter。
新建一个支持Sanpshot的writer
- IndexDeletionPolicy policy = new KeepOnlyLastCommitDeletionPolicy();
- SnapshotDeletionPolicy snapshotter = new SnapshotDeletionPolicy(policy);
- IndexWriter writer = new IndexWriter(dir, analyzer, snapshotter,
- IndexWriter.MaxFieldLength.UNLIMITED);
下面是需要热备份时调用的代码
备份的代码
- try {
- IndexCommit commit = snapshotter.snapshot();
- Collection<String> fileNames = commit.getFileNames();
- /*<iterate over & copy files from fileNames>*/
- } finally {
- snapshotter.release();
- }
使用热备份需要注意的地方
- snapshotter每次备份完要release(),不然writer不会删除这个commit;
- 如果你有多个writer,那么自求多福吧,我一直认为多个w是自己抽自己的行为;
- 每次getFileNames()出来可以做一个比较,因为lucene是一次写入的,意思是尽量重用已经写入的数据,所以只要文件名相同不需要hash检查可以武断的认为他们的数据是一样的,更新的时候可以删除没有在这个list的文件,segment是每次都会被重写的,这个谁都知道;
- 使用热备份肯定会比原来多出很多文件,占用空间增加也是正常的,所以要留好足够的空间;
- 有经常开关writer的同学要注意,在section2代码中拷贝时不能关闭writer,如果你一定要这么干,可以写一个保留当前commit的策略,当然同时还会带来其它问题;