7.索引的管理

1.        查看索引的信息

l         通过 IndexWriter 类读取索引的相关信息,将其显示出来

l         通过 IndexReader 及其子类读取读取索引的相关信息,将其显示出来

l         通过可视化工具(如 Luke Limo )查看索引相关信息

 

1.1    使用 IndexWriter 类读取索引相关信息

该类不是用于查看索引的类,使用它不是最佳方法

String indexPath = "index";

             

              //IndexWriter

              IndexW riter writer = new IndexWriter(indexPath,new StandardAnalyzer());                 

              String d = writer.getDirectory().toString();

              System.out.println(d);

             

              double t = writer.getDefaultWriteLockTimeout();

              System.out.println(t);

             

              int n = writer.numRamDocs();

              System.out.println(n);

             

 

              int c = writer.docCount();

              System.out.println(c);

1.2    使用 IndexReader 及其子类读取索引的相关信息

IndexReader 类是专门用于读取索引的类,它是一个抽象类,含有 FilterIndexReader MultiReader ParallelReader 等子类

IndexReader 类通过静态方法 open(String indexPath) 可以得到其子类。

使用 IndexReader 类可以获得某个索引的详细信息,如指定路径的索引是否存在,索引中包含文档个数,索引中包含词条情况,索引是否经过优化等。

1.3    通过可视化工具(如 Luke Limo )查看索引相关信息

示例一:是否存在、最后修改时间、路径信息、含有文档数量

String indexPath = "index";

             

              // 建立 IndexReader

              IndexReader ir = IndexReader.open(indexPath);

             

              //indexExists

              if(ir.indexExists(indexPath))

              {

                     System.out.println(" 该索引存在! ");

              }

              else

              {

                     System.out.println(" 该索引不存在! ");

              }

             

              //lastModified

              Date d = new Date(ir.lastModified(indexPath));

              System.out.println(d);

             

              //isCurrent()

              System.out.println(ir.isCurrent());

 

              //isOptimized() 索引是否优化

              System.out.println(ir.isOptimized());

 

              //directory() 索引路径

              System.out.println(ir.directory());

             

             

              //numDocs() 索引中的文档数量

              int num = ir.numDocs();

              System.out.println(num);

                    

             

              // 关闭 IndexReader

              ir.close();

示例二:读取指定文档、指定字段

String indexPath = "index";

             

              // 建立 IndexReader

              IndexReader ir = IndexReader.open(indexPath);

                           

              //numDocs() 索引中的文档数量

              int num = ir.numDocs();

             

              //Document 文档对象信息,各个字段

              Document doc = ir.document(44);

              System.out.println(doc); 

             

              if(num>10)

              {

                     for(int i=0;i<10;i++)

                     {

                            doc = ir.document(i);

                            Field field = doc.getField("filename");  // 特定字段

                            System.out.println(field.stringValue());

                     }

              }

 

              // 关闭 IndexReader

              ir.close();

示例三:词条、过滤词条 ReaderIndex3

String indexPath = "index";

             

              // 建立 IndexReader

              IndexReader ir = IndexReader.open(indexPath);

             

              //terms() 索引中的所有词条

              int i = 0;

              TermEnum te = ir.terms();  // 不带过滤

              while(te.next())

              {

                     Term t = te.term();

                     i++;

                     if(i<10)

                     {

                            System.out.println(t);

                     }

              }

             

              te.close();

             

              // 词条总数

              System.out.println(i);

             

              // 符合 "text: 鼻祖 " 的词条

              i = 0;

              Term t = new Term("text"," 鼻祖 ");  //  过滤

              te = ir.terms(t);

              while(te.next())

              {

                     t = te.term();

                     i++;

              }

             

              te.close();

              System.out.println(i);

             

              //"text: 鼻祖 " 词条总数

              System.out.println(ir.docFreq(t));

 

              TermDocs td = ir.termDocs(t); // 输出含有词条的文档

              while(td.next())

              {

                     int id = td.doc();

                     Document doc = ir.document(id);

                     Field field = doc.getField("filename");

                     System.out.println(field.stringValue());

              }    

                    

              // 关闭 IndexReader

              ir.close();

 

2.        删除索引中的文档

通过 IndexReader IndexModifier 两个类删除文档。

2.1 IndexReader

删除文档需要根据文档序号或词项进行

a)        删除指定序号的文档

IndexReader deleteDocument(int id) 方法

              IndexReader ir = IndexReader.open(indexPath);

              ir.deleteDocument(0);

执行后,会发现索引目录下生成了一个扩展名 del 的新文件,存储着被删除文档的信息。这时候,文档并没有真正从索引中删除,只是做了已经删除的标记,从而不能参与检索。

b)        恢复被删除的文档

undeleteAll 方法可以回复所有逻辑删除的文档。

ir.undeleteAll();

c)         物理删除文档

两个步骤:

(1)       使用 IndexReader 作删除标记

(2)       执行 IndexWriter optimize 方法

              / / undeleteIndex1.java

              String indexPath = "index";

 

              IndexReader ir = IndexReader.open(indexPath); // 建立 IndexReader        

              ir.deleteDocument(0); // 逻辑删除                          

              ir.close(); // 关闭 IndexReader

             

              // 建立 IndexWriter

              IndexWriter iw = new IndexWriter(indexPath, new StandardAnalyzer());         

              iw.optimize(); // 执行 优化方法

              iw.close(); // 关闭 IndexWriter

 

d)        批量删除文档

1 IndexReader 按序号批量删除

2 IndexReader 按词项批量删除

在倒排索引中,索引是以文档编号和短语为标志排列的,所以 Lucene 实现了按照 Term 删除文档,也是逻辑删除。 deleteIndex3.java

              IndexReader ir = IndexReader.open(indexPath);

              Term t = new Term("filename","lucene"); // 词项

              int i = ir.deleteDocuments(t);            // 批量删除的文档个数

 

2.2 IndexModifier

IndexModifier 是专门用于全面操作索引的类,集成了 IndexWriter IndexReader 两个类的方法,既可以建立索引、查看索引、修改索引。

String indexPath = "im";       

              IndexModifier indexModifier = new IndexModifier("im", new StandardAnalyzer(),true); 

              Document doc = new Document();

              doc.add(new Field("id", "1", Field.Store.YES, Field.Index.UN_TOKENIZED));               doc.add(new Field("body", "aaaaaaaaa", Field.Store.YES, Field.Index.TOKENIZED));         indexModifier.addDocument(doc);

 

              doc.add(new Field("id", "2", Field.Store.YES, Field.Index.UN_TOKENIZED));               doc.add(new Field("body", "bbbbbbbbb", Field.Store.YES, Field.Index.TOKENIZED));              indexModifier.addDocument(doc);

 

              System.out.println("1:" + indexModifier.docCount());

 

              int deleted = indexModifier.deleteDocuments(new Term("id", "1"));

              System.out.println("Deleted " + deleted + " document");

             

              System.out.println("2:" + indexModifier.docCount());

             

              // 将修改内容写入磁盘

              indexModifier.flush();

             

              System.out.println("3:" + indexModifier.docCount());

 

              indexModifier.close();

 

3.        更新索引中的文档

先删除,再添加

3.1 更新单个文档

// 建立索引

              String indexPath = "di";

              IndexWriter iw = new IndexWriter(indexPath,new StandardAnalyzer());

 

              Document doc = new Document();

              doc.add(new Field("id", "1", Field.Store.YES, Field.Index.UN_TOKENIZED));       

              doc.add(new Field("body", "aa", Field.Store.YES, Field.Index.TOKENIZED)); 

              iw.addDocument(doc);

 

              doc = new Document();

              doc.add(new Field("id", "2", Field.Store.YES, Field.Index.UN_TOKENIZED));       

              doc.add(new Field("body", "bb", Field.Store.YES, Field.Index.TOKENIZED));

              iw.addDocument(doc);

             

              iw.close();

             

              /******************************************************************/

              // 删除第一个文档

              IndexReader ir = IndexReader.open(indexPath);

             

              System.out.println("before updatinging:");

              System.out.println("total: " + ir.numDocs());

             

              doc = ir.document(0);

              System.out.println("body: " + doc.getField("body").stringValue());

             

              //delete

              ir.deleteDocument(0);

             

              System.out.println("after deleting:");

              System.out.println("total: " + ir.numDocs());

 

              ir.close();

             

              /******************************************************************/

             

              // 添加第一个文档

              iw = new IndexWriter(indexPath,new StandardAnalyzer());

 

              doc = new Document();

              doc.add(new Field("id", "1", Field.Store.YES, Field.Index.UN_TOKENIZED));       

              doc.add(new Field("body", "up", Field.Store.YES, Field.Index.TOKENIZED));

              iw.addDocument(doc);

              iw.optimize();

 

              iw.close();

             

              /******************************************************************/

             

              // 查看更新结果

              ir = IndexReader.open(indexPath);

             

              System.out.println("after updatinging:");

              System.out.println("total: " + ir.numDocs());

             

              doc = ir.document(0);

              System.out.println("body: " + doc.getField("body").stringValue());

              doc = ir.document(1);

              System.out.println("body: " + doc.getField("body").stringValue());

              ir.close();

结果:原来的 0 号文档被删除, 1 号文档变为 0 号文档,新添加的文档成为 1 号文档。

 

3.2 批量更新文档

先批量删除,再批量添加

UpdateIndex2.java

// 建立索引

// 批量删除文档

ir.deleteDocuments(new Term(“body”, “aa”));

// 逐个添加文档

IndexWriter updateDocument 方法用于实现索引的更新,该方法以 Term 为条件,先批量删除对应的文档,然后批量增加文档。

void updateDocument(Term term, Document doc, Analyzer analyzer);

void updateDocument(Term term, Document doc);

UpdateIndex3.java

// 建立索引

              String indexPath = "u3";

              IndexWriter iw = new IndexWriter(indexPath,new StandardAnalyzer());

 

              Document doc = new Document();

              doc.add(new Field("id", "1", Field.Store.YES, Field.Index.UN_TOKENIZED));

              doc.add(new Field("body", "aa", Field.Store.YES, Field.Index.TOKENIZED)); 

              iw.addDocument(doc);

 

              doc = new Document();

              doc.add(new Field("id", "2", Field.Store.YES, Field.Index.UN_TOKENIZED));

              doc.add(new Field("body", "bb", Field.Store.YES, Field.Index.TOKENIZED));

              iw.addDocument(doc);

             

              iw.close();            

              /******************************************************************/

             

              // 添加第一个文档

              iw = new IndexWriter(indexPath,new StandardAnalyzer());

 

              doc = new Document();

              doc.add(new Field("id", "1", Field.Store.YES, Field.Index.UN_TOKENIZED));

              doc.add(new Field("body", "up", Field.Store.YES, Field.Index.TOKENIZED));

              iw.updateDocument(new Term("body","aa"),doc);

// 个人认为该方法只能使用这一次,下面还是要一个个添加的,与示例二的方法差别不大。

              iw.close();

 

4.        索引的同步

同步,即并发访问,当许多用户同时访问某个索引文件的时候就会遇到该问题。

4.1 Lucene 并发访问机制

1 )任意数量的只读操作都可以同时执行

2 )在某一时刻,只允许一个写操作。即同一时刻,只能被一个 IndexWriter IndexReader IndexModifier 对象打开。一个类操作完后要立即关闭。

3 )只读的搜索操作可以在索引被修改的时候进行。

4.2 线程安全性

Lucene 保证索引操作线程安全性的原则是: IndexWriter IndexReader IndexModifier 三个类不能同时操作同一索引。

但是,这三个类本身是线程安全的,可以被多线程共享, Lucene 会对各个线程中所有修改索引的方法的调用进行恰当的同步处理,以保证修改操作能一个接一个的有序进行。

应用程序不需要进行额外的同步处理,只需保证这三个类的对象对索引的修改操作不重叠。一个类操作完成要马上调用 close 方法,然后再使用下一个类。

4.3 索引锁机制

为了处理索引同步问题, Lucene 内置了一种锁机制。锁,体现为一种文件。

锁有两种: write.lock commit.lock

write.lock 文件用于阻止进程同时修改一个索引。三个类对索引进行添加、删除或修改的时候, write.lock 文件就产生了。

在读取和合并索引块的时候,会用到 commit.lock 锁,这是一种事务锁。

这两种锁都是自动建立的,不需要手动建立和修改。 IndexWriter 类可以通过四种方法设定或取得锁的时间。

iw.setWriteLockTimeout(long writeLockTimeout);

iw.getWriteLockTimeout(long writeLockTimeout);

iw.setDefaultWriteLockTimeout(long writeLockTimeout);

iw.getDefaultWriteLockTimeout(long writeLockTimeout);

5.        使用 Luke 管理索引

Luke 是一套可视化管理 Lucene 索引的软件。通过 Luke ,可以根据文档的编号浏览文档内容、复制文档内容、执行搜索、,查看结果等。

http://getopt.org/luke/

http://code.google.com/p/luke/

6.        使用 Limo 管理索引

Luke 是一个桌面应用程序, Limo 则是一个基于 Web 的应用程序,需要 JSP 服务器的支持。

你可能感兴趣的:(多线程,优化,String,Lucene,文档,化工)