Document

索引管理 《第四篇》

一、索引管理

  1、查看索引的相关信息

  查看索引的信息大概有如下方法:

  1. 通过IndexWriter类读取索引的相关信息,将其显示出来。
  2. 通过IndexReader及其子类读取索引的相关信息,将其显示出来。
  3. 通过可视化工具查看索引的相关信息。

  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、物理删除文档

  要从物理上删除索引中的文档,需要有如下步骤:

  1. 使用IndexReader为文档作删除标记。
  2. 执行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、更新索引中的单个文档

  到目前为止,更新索引中的文档只能够:先删除,再添加。

复制代码
    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并发访问规则

  并发访问问题,如果处理不好,就会导致索引文件的损坏。为了避免出现这类问题,需要遵守如下规则:

  1. 任意数量的只读操作都可以同时执行。
  2. 某一时刻,只允许执行一个修改索引的操作。也就是说,在同一时间,一个索引文件只能够被一个IndexWriter、IndexReader对象打开。要做到这一点并不难,在编写代码的时候,这三个类的操作都分别进行,一个类操作完成后立即释放资源,然后再调用下一个类的方法。
  3. 只读的搜索操作可以在索引被修改的时候进行。

  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属性来设定或取得锁的时间。参数的单位都是毫秒。

posted @ 2016-05-05 14:59  从未被超越  阅读(328)  评论(0编辑  收藏  举报