在IndexReader中提供了两个方法来删除Document :
public final void deleteDocument(int docNum) throws IOException
public final int deleteDocuments(Term term) throws IOException
(注:在1.4的Lucene中分别为delete(int docNum)和delete(Term term)
对于一个document被删除之后,它只是在TermDocs 或者TermPositions enumerations 中不会被出现,但是并没有真正的被删除,这个时候试图用方法document(int)方法读取document的field就会出错,但是The presence of this document may still be reflected in the docFreq(org.apache.lucene.index.Term) statistic, though this will be corrected eventually as the index is further modified.
但是这个方法在实际的应用中就显得麻烦,因为你很难知道一个document的docNum,从而就不能用这个方法去删除document。
这个时候就会选择第二个方法,它会删除包含term的所有的document,要使的这个方法每次只删除一个document,简单的做法就是在document的中加一个有着唯一的ID的field,那么在删除这个document的时候就用这个方法deleteDocuments(new Term("xx_ID",xx.getID()); 这样就可以删除对应的document,然后加进去新的document。
但是在写代码的过程中我还是遇到了没有办法删除document对象的状况。在确定不是参数有问题的情况下,我的第一反应是,对同一个索引打开了一个IndexWriter和一个IndexReader,在IndexReader删除的时候,IndexWriter还没有关闭,我怀疑有写锁的存在(PS:关于Lucene的线程安全性还没有仔细看呢),但是独立写了个测试,发现这不是问题的所在。
我用 deleteDocument(int docNum) 确成功的删除了document,那么是什么导致deleteDocuments(Term term)没有办法删除呢??
仔细检查了一下,发现1.4版本中的示例代码中是这样的
doc.add(Field.Text("name","Word1 word2 word3"));
reader.delete(new Term("name","word1"));
而我的代码中是doc.add(new Field("xx_ID",xx.getID(),Field.Store.YES,Field.Index.NO));
而在1.4中Field.Text()是将字段切词,索引,存储的
!!!!!!!!!所以我将代码改为Field.Index.UN_TOKENIZD再测试就没有问题了,顺利将document删除了。分析原因,把lucene的源代码下了下来,没看之前的想法是,它要删除包含这个term的document可能调用类似search的方法,而我没有将这个ID的field索引打开,可能就导致搜索不到这个document。(PS:只是乱想)
源代码还是很烦,不是一下就能看明白,以后再说~~~~
有一个简单的认识:
termDocs()实现的是Term =>
这样一个映射,也许这两个删除的方法都是由protected abstract void doDelete(int docNum) throws IOException 这个方法真正实现的(PS:猜测而已),也许问题的入口就在如何构建到这个映射关系的,看了代码之后再慢慢想。