`
beyondqinghua
  • 浏览: 41424 次
  • 性别: Icon_minigender_1
  • 来自: 南昌
社区版块
存档分类
最新评论

lucene初探(三):性能优化篇

 
阅读更多

一、一、优化创建索引性能

这方面的优化途径比较有限,IndexWriter提供了一些接口可以控制建立索引的操作,另外我们可以先将索引写入RAMDirectory,再批量写入 FSDirectory,不管怎样,目的都是尽量少的文件IO,因为创建索引的最大瓶颈在于磁盘IO。另外选择一个较好的分词器也能提高一些性能。

 

1、合并索引库片段文件

Lucene3.6版本中,合并文件使用LogMergePolicysetMergeFactor(int)方法用于批量创建索引。当setMergeFactor(int)的参数值较小的时候,创建索引的速度较慢;当参数值较大的时候,创建索引的速度就比较快;大于10适合批量创建索引。

写道
package com.iris.scm.lucene.test3;

import java.io.File;
import java.util.List;
import java.util.Map;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Field.Index;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.LogByteSizeMergePolicy;
import org.apache.lucene.index.LogMergePolicy;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.wltea.analyzer.lucene.IKAnalyzer;

import com.iris.scm.lucene.test2.IndexBuilder;

/**
* 使用LogMergePolicy合并索引创建.
*
*
*/
public class MergeFactorTest {

/**
* @param args
*/
public static void main(String[] args) throws Exception {

createIndex();
}

public static void createIndex() throws Exception {
// 建立一个IK分词器
Analyzer analyzer = new IKAnalyzer();
// 创建索引存储目录
Directory directory = FSDirectory.open(new File("D:\\lucene\\LuceneTest3"));
IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_36, analyzer);
LogMergePolicy mergePolicy = new LogByteSizeMergePolicy();
// 达到10个文件时就和合并
mergePolicy.setMergeFactor(10);
indexWriterConfig.setMergePolicy(mergePolicy);
IndexWriter indexWriter = new IndexWriter(directory, indexWriterConfig);
List<Map<String, String>> list = IndexBuilder.readerFiles("D:\\lucene\\textfiles3_1");

for (Map<String, String> map : list) {

// Document是Lucene的文档结构,需要索引的对象都要转换为Document
Document document = new Document();
// 文件名,可查询,不分词,存储到索引库记录中
document.add(new Field("file_name", map.get("file_name"), Store.YES, Index.NOT_ANALYZED));
// 文件路径,可查询,不分词,存储到索引库记录中
document.add(new Field("file_path", map.get("file_path"), Store.YES, Index.NOT_ANALYZED));
// 文本内容,这里因为文件较小,直接存储到索引记录库,如果大文件不建议存储
document.add(new Field("content", map.get("content"), Store.YES, Index.ANALYZED));

// 把文档添加到索引库
indexWriter.addDocument(document);
}
indexWriter.close();
}

}

 

2、内存索引目录和文件系统索引目录结合使用

我们可以先把索引写入RAMDirectory,达到一定数量时再批量写进FSDirectory,减少磁盘IO次数。内存索引目录的操作速度非常快,所以我们在操作索引的时候可以把索引库从文件系统加载到内存中,操作完成后再写回文件系统。

内存中的索引文件写回到文建系统中的时候,我们需要对索引数据进行重构。比如原来文件系统中的索引目录有10个文件,加载到内存目录的时候是把10个文件copy一份到内存,然后我们添加了一个索引文件,内存中的索引目录文件数就变成11个,写回到文件系统的时候,内存索引目录文件数(11)加上原来文件系统索引目录的文件数(10)就变成21个了,有10个文件是重复了,所以我们需要覆盖原来文件系统中的索引目录。当然对于巨型索引库,不建议使用,因为所需的内存非常大。

写道
package com.iris.scm.lucene.test3;

import java.io.File;
import java.util.List;
import java.util.Map;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Field.Index;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.IndexWriterConfig.OpenMode;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.util.Version;
import org.wltea.analyzer.lucene.IKAnalyzer;

import com.iris.scm.lucene.test2.IndexBuilder;

/**
* 内存索引目录和文件系统索引目录结合.
*
*
*/
public class RAMDirectoryTest {

public static void main(String[] args) throws Exception {

createIndex();
}

public static void createIndex() throws Exception {
// 建立一个IK分词器
Analyzer analyzer = new IKAnalyzer();
// 创建索引存储目录
Directory directory = FSDirectory.open(new File("D:\\lucene\\LuceneTest3"));
// 创建内存索引目录,把文件系统中的索引库加载进来
RAMDirectory ramDirectory = new RAMDirectory(directory);
IndexWriterConfig ramIndexWriterConfig = new IndexWriterConfig(Version.LUCENE_36, analyzer);
IndexWriter ramIndexWriter = new IndexWriter(ramDirectory, ramIndexWriterConfig);
List<Map<String, String>> list = IndexBuilder.readerFiles("D:\\lucene\\textfiles3_2");

for (Map<String, String> map : list) {

// Document是Lucene的文档结构,需要索引的对象都要转换为Document
Document document = new Document();
// 文件名,可查询,不分词,存储到索引库记录中
document.add(new Field("file_name", map.get("file_name"), Store.YES, Index.NOT_ANALYZED));
// 文件路径,可查询,不分词,存储到索引库记录中
document.add(new Field("file_path", map.get("file_path"), Store.YES, Index.NOT_ANALYZED));
// 文本内容,这里因为文件较小,直接存储到索引记录库,如果大文件不建议存储
document.add(new Field("content", map.get("content"), Store.YES, Index.ANALYZED));

// 把文档添加到索引库
ramIndexWriter.addDocument(document);
}
ramIndexWriter.close();
// 文件目录config
IndexWriterConfig fsIndexWriterConfig = new IndexWriterConfig(Version.LUCENE_36, analyzer);
// 创建新的索引目录或者覆盖原来的索引目录
fsIndexWriterConfig.setOpenMode(OpenMode.CREATE);
IndexWriter fsIndexWriter = new IndexWriter(directory, fsIndexWriterConfig);
// 把内存中的索引库写到文件系统中
fsIndexWriter.addIndexes(ramDirectory);
fsIndexWriter.close();

}
}

 

二、优化搜索性能

Lucene提供了RAMDirectory可以在内存中容纳索引,条件允许的话可以使用内存索引。

写道
package com.iris.scm.lucene.test3;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.queryParser.MultiFieldQueryParser;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.util.Version;
import org.wltea.analyzer.lucene.IKAnalyzer;

/**
* 利用创建的内存目录索引检索..
*
*
*/
public class IndexQuery {

public static void main(String[] args) throws Exception {

List<Map<String, String>> list1 = query("D:\\lucene\\LuceneTest3", "重金属");
System.out.println("检索式关键词:重金属");
printFileInfo(list1);

List<Map<String, String>> list2 = query("D:\\lucene\\LuceneTest3", "商业化生物");
System.out.println("检索式关键词:商业化生物");
printFileInfo(list2);
}

public static void printFileInfo(List<Map<String, String>> list) {

for (Map<String, String> map : list) {
System.out.println("文件名:" + map.get("file_name"));
System.out.println("文件路径:" + map.get("file_path"));
System.out.println("文件内容:" + map.get("content"));
System.out.println();
System.out.println();
}
}

/**
* 利用创建的内存目录索引检索.
*
* </pre>
*
* @param idxDir
* @param keyword
* @return
* @throws Exception
*/
public static List<Map<String, String>> query(String idxDir, String keyword) throws Exception {

String[] fields = { "file_name", "content" };
// 创建一个分词器,和创建索引时用的分词器要一致
Analyzer analyzer = new IKAnalyzer();
// 创建查询解析器
QueryParser queryParser = new MultiFieldQueryParser(Version.LUCENE_36, fields, analyzer);
// 将查询关键词解析成Lucene的Query对象
Query query = queryParser.parse(keyword);

// 打开索引目录
File indexDir = new File(idxDir);
Directory directory = FSDirectory.open(indexDir);
Directory ramDir = new RAMDirectory(directory);

// 获取访问索引的接口,进行搜索
IndexReader indexReader = IndexReader.open(ramDir);
IndexSearcher indexSearcher = new IndexSearcher(indexReader);

// TopDocs 搜索返回的结果
TopDocs topDocs = indexSearcher.search(query, 100);// 只返回前100条记录

int totalCount = topDocs.totalHits; // 搜索结果总数量
System.out.println("搜索到的结果总数量为:" + totalCount);
List<Map<String, String>> list = new ArrayList<Map<String, String>>();
ScoreDoc[] scoreDocs = topDocs.scoreDocs; // 搜索的结果集合
for (ScoreDoc scoreDoc : scoreDocs) {
// 文档编号
int docID = scoreDoc.doc;
// 根据文档编号获取文档
Document doc = indexSearcher.doc(docID);
Map<String, String> map = new HashMap<String, String>();
map.put("file_name", doc.get("file_name"));
map.put("file_path", doc.get("file_path"));
map.put("content", doc.get("content"));
list.add(map);
}
indexReader.close();
indexSearcher.close();
return list;
}
}

  

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics