一、索引管理
1、查看索引的相关信息
查看索引的信息大概有如下方法:
- 通过IndexWriter类读取索引的相关信息,将其显示出来。
- 通过IndexReader及其子类读取索引的相关信息,将其显示出来。
- 通过可视化工具查看索引的相关信息。
1、使用IndexWriter类读取索引的相关信息
使用IndexWriter读取并非最佳方法。
2、使用IndexReader及其子类读取索引的相关信息
IndexReader类是专门用于读取索引信息的类,它是一个抽象类,含有FilterIndexReader、MultiReader、ParallelReader等子类。
IndexReader类通常使用其静态方法Open创建其子类对象。
使用IndexReader类可以获得某个索引的详细信息。例如,指定路径的索引是否存在,索引中包含的文档,索引中包含的词条情况,索引是否经过了优化等等。
using (IndexReader reader = IndexReader.Open(fsdirectory, true)) { Console.WriteLine(reader.IsCurrent()); //False 是否当前正在使用的索引 Console.WriteLine(reader.IsOptimized()); //False 索引是否经过了优化 Console.WriteLine(reader.Directory()); //索引路径 Console.WriteLine(reader.NumDocs()); //含有文档数目 Console.WriteLine(reader.Document(1).GetField("Name").StringValue); //输出 第1个文档 Name字段的值 //所有词条 TermEnum te = reader.Terms(); while (te.Next()) { Console.WriteLine(te.Term.Text); } } //上次更新时间 long g = IndexReader.LastModified(fsdirectory); DateTime dt = DateTime.FromFileTime(g); Console.WriteLine(dt);
2、删除索引中的文档
如果某个文档不需要被检索了,就应该把它从索引中删除。在Lucene.net中,通过IndexReader和IndexModifier两个类从索引中删除文档。
1、使用IndexReader从索引中删除文档
(1)、删除指定序号的文档
通过调用IndexReader类的DeleteDocument(int id),可以从索引中删除指定序号的文档。
using (IndexReader reader = IndexReader.Open(fsdirectory, false)) //注意readonly参数要设为false { reader.DeleteDocument(1); }
查看索引目录,发现生成了一个扩展名为"del"的新文件,在这个文件中存储着被删除文档的信息。
这个时候,文档并没有真正从索引中删除,只是做了已经被删除的标记,从而使之不能参与检索。如果此时再通过NumDocs()方法读取,会减少一条。
2、恢复被删除的文档
通过调用IndexReader类的DeleteDocument(int id)方法,文档并没有实际删除,所以可以把这些标记为删除的文档恢复过来,调用UnDeleteAll()方法即可将所有文档都恢复。
此时,刚才生成的"del"文档消失了。
3、物理删除文档
要从物理上删除索引中的文档,需要有如下步骤:
- 使用IndexReader为文档作删除标记。
- 执行IndexWriter的Optimize()方法。
3、批量删除文档
IndexReader还有一个方法
int DeleteDocuments(Term term);
通过这个方法,可以删除指定Term的文档。
using (IndexReader reader = IndexReader.Open(fsdirectory, false)) //注意readonly参数要设为false { Term term = new Term("Name", "备"); reader.DeleteDocuments(term); }
4、更新文档
1、更新索引中的单个文档
目前的版本,索引的更新是可以用的,但是也相当于原有索引作废,不参与检索,然后新增一条索引,可以用UpdateDocument了。2018-03-19
using (IndexWriter writer = new IndexWriter(fsdirectory, analyzer, maxFieldLength)) { Document document1 = new Document(); document1.Add(new Field("Name", "刘备", Field.Store.YES, Field.Index.ANALYZED)); writer.AddDocument(document1); } using (IndexReader reader = IndexReader.Open(fsdirectory, false)) { reader.DeleteDocument(1); //删除文档 } using (IndexWriter writer = new IndexWriter(fsdirectory, analyzer, maxFieldLength)) { //再添加 Document document2 = new Document(); document2.Add(new Field("Name", "关羽", Field.Store.YES, Field.Index.ANALYZED)); writer.AddDocument(document2); }
2、批量更新索引中的文档
这个不再说明,批量删除然后再一个个的添加。
3、更新方法
IndexWriter有一个方法可以实现索引的更新。
public virtual void UpdateDocument(Term term, Document doc); public virtual void UpdateDocument(Term term, Document doc, Analyzer analyzer);
该方法使用示例如下:
using (IndexWriter writer = new IndexWriter(fsdirectory, analyzer, maxFieldLength)) { Document document1 = new Document(); document1.Add(new Field("Name", "张飞", Field.Store.YES, Field.Index.ANALYZED)); writer.AddDocument(document1); } using (IndexWriter writer = new IndexWriter(fsdirectory, analyzer, maxFieldLength)) { Document doc = new Document(); doc.Add(new Field("Name", "赵云", Field.Store.YES, Field.Index.ANALYZED)); writer.UpdateDocument(new Term("Name", "飞"), doc); }
二、索引的同步
1、Lucene并发访问规则
并发访问问题,如果处理不好,就会导致索引文件的损坏。为了避免出现这类问题,需要遵守如下规则:
- 任意数量的只读操作都可以同时执行。
- 某一时刻,只允许执行一个修改索引的操作。也就是说,在同一时间,一个索引文件只能够被一个IndexWriter、IndexReader对象打开。要做到这一点并不难,在编写代码的时候,这三个类的操作都分别进行,一个类操作完成后立即释放资源,然后再调用下一个类的方法。
- 只读的搜索操作可以在索引被修改的时候进行。
2、线程安全性
Lucene保持索引操作线程安全性的原则是:IndexWriter、IndexReader两个类不能同时对同一个索引进行操作。
但是这三个类本身都是线程安全的。这三个类的实例都可以被多线程共享,Lucene会对各个线程中所有修改索引的方法的调用进行恰当的同步处理。以此来确保修改操作能一个接一个地有序进行。
应用程序不需要额外的同步处理,只需确保这三个类的对象对索引的修改操作部重叠。即:一个类操作完成,要马上释放资源,然后在使用下一个类。
3、索引锁机制
为了处理索引同步问题,Lucene内置了一种锁机制,锁,体现为一种文件。锁分为以下两种:
- write.lock
- commit.lock
write.lock文件用于阻止进程同时修改一个索引。对于IndexWriter、IndexReader这三个类,在它们对索引进行添加、修改或删除的时候,write.lock文件就产生了。这时候如果有人也想修改索引,是做不到的。必须等到这三个类close()之后调用,write.lock文件才会消失,这时,锁解除了。其他用户才可以对索引进行修改操作。
在读取和合并索引块的时候,会用到commit.lock锁,这时一个事务锁。例如,在优化索引的时候,需要先将所有的索引块合并起来,等合并成功之时,再将原先分散的索引块删除,整个过程中任何一步出现问题都会导致索引优化失败,因此要用到事务锁。
这两种锁都是在操作索引时Lucene自动建立的,不需要手动去建立和修改。
IndexWriter类可以通过WriteLockTimeout属性来设定或取得锁的时间。参数的单位都是毫秒。