java lucene技术 (1):索引操作
Lucene 可以帮你完成搜索存储在硬盘上的文件、电子邮件、或网页,甚至是数据库中的数据,但是,在进行搜索以前,你必须预先完成对这些数据的索引操作(Indexing)。这正是本节所要讲解的主题。接下来,你将学会如何对数据进行索引。
程序1.1 通过Lucene API 的几个方法完成对数据建立索引的过程:
File FileAddress = new File(“索引路径”);
IndexWriter iw = new IndexWriter(FileAddress,new StandardAnalyzer(),true);
Field field = new Field(“content”, “字串”, Field.Index.Tokenize,Field.Store.Yes);
Document doc = new Document();
Doc.add (field);
iw.addDocument(doc);
iw.close();
以上,是Lucene建立索引的一般步骤,在涉及索引的问题上,不仅仅是它的建立,还有索引的删除,更新等等。下边,我将较详细的描述它们的操作原理和步骤:
1.1索引的删除与更新
Lucene不提供update(Document)方法。为了达到更新的目的,必须首先从一个索引中删除待更新的文档,然后将修改过的文档重新添加到索引中。
程序1.2提供更新索引的过程:
IndexReader reader = IndexReader.open(dir);
reader.delete(newTerm(“city”,“ Amsterdam ”));
reader.close();
IndexWriterwriter=newIndexWriter(dir,getAnalyzer(),false);
Documentdoc=newDocument();
doc.add(Field.Text(“city”,“Haag”));
writer.addDocument(doc);
writer.optimize();
writer.close();
但是当数据更新频繁,Lucene不能很好得以增量索引的方式实时更新,对同一个索引文件读写添加。
1.2 调整索引性能
在一个典型的索引应用中,程序性能的瓶颈存在于将索引文件写入磁盘的过程中。新的Document对象添加到Lucene的索引里时,它们最初将被缓存在内存中,而不是立刻写入磁盘里。这个缓存操作的目的是提高性能;IndexWriter提供了几个变量,用于调节缓存的大小和磁盘写入的频率。
mergeFactor : 控制段的合并频率和大小。
maxMergeDocs : 限制每个段的文档数量。
minMergeDocs : 控制索引时RAM使用的总量。
下面通过一个程序,可以使读者更清晰的了解它们的作用
public class MergeIndex {
public static void main(String[] args) throws IOException {
MergeIndex mergeindex = new MergeIndex();
mergeindex.indexBuild();
System.out.println("ok");
}
public void indexBuild(){
try {
File index_dir = new File("F:/Test/data");
if (index_dir.exists()) {
index_dir.delete();
}
IndexWriter writer = new IndexWriter("F:/Test/dbtest",
new StandardAnalyzer(), true);
writer.setUseCompoundFile(true);
writer.mergeFactor = 3;
writer.maxMergeDocs = 20;
writer.minMergeDocs = 2;
indexFile(writer, index_dir);
writer.close();
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
public static void indexFile(IndexWriter writer, File file)
throws IOException {
if (file.canRead()) {
if (file.isDirectory()) {
String[] files = file.list();
if (files != null) {
for (int i = 0; i < files.length; i++) {
indexFile(writer, new File(file, files[i]));
}
}
} else {
try {
if (file.getName().endsWith(".txt")) {
writer.addDocument(FileDocument.Document(file));
}
}
catch (FileNotFoundException fnfe) {
System.out.println(fnfe.getMessage());
}
}
}
}
}
minMergeDocs是控制多少个document生成一个segement;mergeFactor控制几个segment合并的;maxMergeDocs控制一个segment中最多包含多少document.
在路径F:/Test/data下建立3个txt文本,分别为01.txt、02.txt、03.txt,然后运行MergeIndex,在路径F:/Test/dbtest下,生成3个文件:_4.cfs、deletable、segments(关于这些文件,将在以后的文章中给出说明),使用编辑工具打开_4.cfs,会发现它包含了F:/Test/data下3个txt文件信息,打开segments,发现有’_9’信息,这是因为minMergeDocs = 3 只允许有3个文档文件生成一个segment,segments文件中包含有目前segment信息。
1.3对索引批处理
一种方式是:可以把RAMDirector作为缓冲器,先将索引文件缓存在缓冲器中,再把数据写入基于FSDirectory的索引中,以达到改善性能的目的。
程序1.3可供读者参考:
FSDirectory fsd = FSDirectory.getDirectory("F:/Test/dbtest",true);
RAMDirectory ramd = new RAMDirectory();
IndexWriter fsdiw = new IndexWriter(fsd,new StandardAnalyzer(),true);
IndexWriter ramdiw = new IndexWriter(ramd,new StandardAnalyzer(),true);
ramdiw.mergeFactor = 3;
ramdiw.minMergeDocs = 2;
indexFile (ramdiw,INDEX_DIR);
Directory[] ramdirectory = {ramd};
if(ramdiw.docCount()>=6){
fsdiw.addIndexes(ramdirectory);
ramdiw.close();
ramdiw = new IndexWriter(ramd,new StandardAnalyzer(),true);
fsdiw.close();
}
public static void indexFile(IndexWriter writer, File file)
throws IOException {
if (file.canRead()) {
if (file.isDirectory()) {
String[] files = file.list();
if (files != null) {
for (int i = 0; i < files.length; i++) {
indexFile(writer, new File(file, files[i]));
}
}
} else {
try {
if (file.getName().endsWith(".txt")) {
writer.addDocument(FileDocument.Document(file));
}
}
catch (FileNotFoundException fnfe) {
System.out.println(fnfe.getMessage());
}
}
}
}