除了IndexWriter外,IndexReader也可以用来删除文档。那么两者之间有什么区别呢?
A. IndexReader可以按文档id删除一个文档。
IndexReader用来删除文档的核心方法为:
public synchronized void deleteDocument(int docNum) throws StaleReaderException, CorruptIndexException, LockObtainFailedException, IOException { ensureOpen(); acquireWriteLock(); hasChanges = true; doDelete(docNum); }
很显然,这是一个模板方法,其中acquireWriteLock默认为空实现,doDelete方法强制子类实现。
这个方法可以让你通过IndexReader方便的查出结果集,然后删掉其中的某条数据。
B. IndexReader也提供按Term删除的方法:
int deleteDocuments(Term term);
然而,此方法的实现中依然调用了deleteDocument(int docNum); 不同与IndexWriter中对应的方法,此方法可以立即返回执行结果,而IndexWriter会缓存待删除的Term,并在之后的时间里执行删除操作。
C. IndexWriter可以通过Query删除。
如同通过Term删除,其实你完全可以实现自己的Query删除方式。只需要通过Query查出结果,用deleteDocument(int docNum);一一删除。
值得注意的是,IndexReader会以“写”方式完成删除。这就意味着,在执行删除操作前,必须关闭所有在此索引上打开的IndexWriter,反之亦然。因此,频繁交替进行添加、删除操作,会使索引能力变得低下,因而要设计成批量添加或删除。通常来说,最好用IndexWriter进行删除操作,除非你确实需要通过docNum来删除文档,或者希望删除后的结果立即生效。
Lucene通过“黑名单”列出索引中删除的文档,换言之,文档仅仅是被标记成删除状态并存于数组中。这也意味着删除操作并不能释放磁盘空间,好在可以通过调用IndexWriter的expungeDeletes()方法释放这部分空间。更好的消息是,新版的Lucene已经不需要考虑这些了,而且expungeDeletes也被标记为Deprecated,应该会在4.0版本去掉。
FOR Doudou