熟悉了建立索引所需要的这些类后,我们就开始对某个目录下面的文本文件建立索引了,给出了对某个目录下的文本文件建立索引的源代码。
[code]publicclassTextFileIndexer{
publicstaticvoidmain(String[]args)throwsException{
//fileDiristhedirectorythatcontainsthetextfilestobeindexed
FilefileDir=newFile("C:\\index");
//indexDiristhedirectorythathostsLucene'sindexfiles
FileindexDir=newFile("C:\\luceneIndex");
AnalyzerluceneAnalyzer=newStandardAnalyzer(Version.LUCENE_30);
IndexWriterindexWriter=newIndexWriter(FSDirectory.open(indexDir),luceneAnalyzer,true,IndexWriter.MaxFieldLength.LIMITED);
File[]textFiles=fileDir.listFiles();
longstartTime=newDate().getTime();
//Adddocumentstotheindex
for(inti=0;i<textFiles.length;i++){
if(textFiles[i].isFile()&&textFiles[i].getName().endsWith(".txt")){
System.out.println("File"+textFiles[i].getCanonicalPath()+"isbeingindexed");
ReadertextReader=newFileReader(textFiles[i]);
Documentdocument=newDocument();
document.add(newField("content",textReader));
document.add(newField("path",textFiles[i].getPath(),Field.Store.YES,Field.Index.ANALYZED_NO_NORMS));
indexWriter.addDocument(document);
}
}
indexWriter.optimize();
indexWriter.close();
longendTime=newDate().getTime();
System.out.println("Ittook"+(endTime-startTime)+"millisecondstocreateanindexforthefilesinthedirectory"+fileDir.getPath());
}
}
[/code]
我们注意到类IndexWriter的构造函数需要三个参数,第一个参数指定了所创建的索引要存放的位置,他可以是一个File对象,也可以是一个FSDirectory对象或者RAMDirectory对象。第二个参数指定了Analyzer类的一个实现,也就是指定这个索引是用哪个分词器对文挡内容进行分词。第三个参数是一个布尔型的变量,如果为true的话就代表创建一个新的索引,为false的话就代表在原来索引的基础上进行操作。接着程序遍历了目录下面的所有文本文档,并为每一个文本文档创建了一个Document对象。然后把文本文档的两个属性:路径和内容加入到了两个Field对象中,接着在把这两个Field对象加入到Document对象中,最后把这个文档用IndexWriter类的add方法加入到索引中去。这样我们便完成了索引的创建。接下来我们进入在建立好的索引上进行搜索的部分。
搜索文档
Query
这是一个抽象类,他有多个实现,比如TermQuery,BooleanQuery,PrefixQuery.这个类的目的是把用户输入的查询字符串封装成Lucene能够识别的Query。
Term
Term是搜索的基本单位,一个Term对象有两个String类型的域组成。生成一个Term对象可以有如下一条语句来完成:Termterm=newTerm(“fieldName”,”queryWord”);其中第一个参数代表了要在文档的哪一个Field上进行查找,第二个参数代表了要查询的关键词。
TermQuery
TermQuery是抽象类Query的一个子类,它同时也是Lucene支持的最为基本的一个查询类。生成一个TermQuery对象由如下语句完成:TermQuerytermQuery=newTermQuery(newTerm(“fieldName”,”queryWord”));它的构造函数只接受一个参数,那就是一个Term对象。
IndexSearcher
IndexSearcher是用来在建立好的索引上进行搜索的。它只能以只读的方式打开一个索引,所以可以有多个IndexSearcher的实例在一个索引上进行操作。
Hits
Hits是用来保存搜索的结果的。
介绍完这些搜索所必须的类之后,我们就开始在之前所建立的索引上进行搜索了,清单2给出了完成搜索功能所需要的代码。
如何添加一个文档到索引文
Documentdocument=newDocument();
document.add(newField("content",textReader));
document.add(newField("path",textFiles[i].getPath(),Field.Store.YES,Field.Index.ANALYZED_NO_NORMS));
indexWriter.addDocument(document);
//最后不要忘记了关闭
indexWriter.close();
|
首先第一行创建了类Document的一个实例,它由一个或者多个的域(Field)组成。你可以把这个类想象成代表了一个实际的文档,比如一个HTML页面,一个PDF文档,或者一个文本文件。而类Document中的域一般就是实际文档的一些属性。比如对于一个HTML页面,它的域可能包括标题,内容,URL等。我们可以用不同类型的Field来控制文档的哪些内容应该索引,哪些内容应该存储。如果想获取更多的关于Lucene的域的信息,可以参考Lucene的帮助文档。代码的第二行和第三行为文档添加了两个域,每个域包含两个属性,分别是域的名字和域的内容。在我们的例子中两个域的名字分别是"content"和"path"。分别存储了我们需要索引的文本文件的内容和路径。最后一行把准备好的文档添加到了索引当中。
从索引中删除文档
类IndexReader负责从一个已经存在的索引中删除文档。
FileindexDir=newFile("C:\\luceneIndex");
IndexReaderir=IndexReader.open(indexDir);
ir.delete(1);
ir.delete(newTerm("path","C:\\file_to_index\lucene.txt"));
ir.close();
|
第二行用静态方法IndexReader.open(indexDir)初始化了类IndexReader的一个实例,这个方法的参数指定了索引的存储路径。类IndexReader提供了两种方法去删除一个文档,如程序中的第三行和第四行所示。第三行利用文档的编号来删除文档。每个文档都有一个系统自动生成的编号。第四行删除了路径为"C:\\file_to_index\lucene.txt"的文档。你可以通过指定文件路径来方便的删除一个文档。值得注意的是虽然利用上述代码删除文档使得该文档不能被检索到,但是并没有物理上删除该文档。Lucene只是通过一个后缀名为.delete的文件来标记哪些文档已经被删除。既然没有物理上删除,我们可以方便的把这些标记为删除的文档恢复过来,如清单3所示,首先打开一个索引,然后调用方法ir.undeleteAll()来完成恢复工作。
恢复已删除文档
FileindexDir=newFile("C:\\luceneIndex");
IndexReaderir=IndexReader.open(indexDir);
ir.undeleteAll();
ir.close();
|
如何物理上删除文档
FileindexDir=newFile("C:\\luceneIndex");
AnalyzerluceneAnalyzer=newStandardAnalyzer();
IndexWriterindexWriter=newIndexWriter(indexDir,luceneAnalyzer,false);
indexWriter.optimize();
indexWriter.close();
|
第三行创建了类IndexWriter的一个实例,并且打开了一个已经存在的索引。第4行对索引进行清理,清理过程中将把所有标记为删除的文档物理删除。
提高索引性能
利用Lucene,在创建索引的工程中你可以充分利用机器的硬件资源来提高索引的效率。当你需要索引大量的文件时,你会注意到索引过程的瓶颈是在往磁盘上写索引文件的过程中。为了解决这个问题,Lucene在内存中持有一块缓冲区。但我们如何控制Lucene的缓冲区呢?幸运的是,Lucene的类IndexWriter提供了三个参数用来调整缓冲区的大小以及往磁盘上写索引文件的频率。
1.合并因子(mergeFactor)
这个参数决定了在Lucene的一个索引块中可以存放多少文档以及把磁盘上的索引块合并成一个大的索引块的频率。比如,如果合并因子的值是10,那么当内存中的文档数达到10的时候所有的文档都必须写到磁盘上的一个新的索引块中。并且,如果磁盘上的索引块的隔数达到10的话,这10个索引块会被合并成一个新的索引块。这个参数的默认值是10,如果需要索引的文档数非常多的话这个值将是非常不合适的。对批处理的索引来讲,为这个参数赋一个比较大的值会得到比较好的索引效果。
2.最小合并文档数
这个参数也会影响索引的性能。它决定了内存中的文档数至少达到多少才能将它们写回磁盘。这个参数的默认值是10,如果你有足够的内存,那么将这个值尽量设的比较大一些将会显著的提高索引性能。
3.最大合并文档数
这个参数决定了一个索引块中的最大的文档数。它的默认值是Integer.MAX_VALUE,将这个参数设置为比较大的值可以提高索引效率和检索速度,由于该参数的默认值是整型的最大值,所以我们一般不需要改动这个参数。
intmergeFactor=10;
intminMergeDocs=10;
intmaxMergeDocs=Integer.MAX_VALUE;
IndexWriterindexWriter=newIndexWriter(indexDir,luceneAnalyzer,true);
indexWriter.mergeFactor=mergeFactor;
indexWriter.minMergeDocs=minMergeDocs;
indexWriter.maxMergeDocs=maxMergeDocs;
|
下面我们来看一下这三个参数取不同的值对索引时间的影响,注意参数值的不同和索引之间的关系。我们为这个实验准备了10000个测试文档。表1显示了测试结果。
表1:测试结果
通过表
1,你可以清楚地看到三个参数对索引时间的影响。在实践中,你会经常的改变合并因子和最小合并文档数的值来提高索引性能。只要你有足够大的内存,你可以为
合并因子和最小合并文档数这两个参数赋尽量大的值以提高索引效率,另外我们一般无需更改最大合并文档数这个参数的值,因为系统已经默认将它设置成了最大。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理