转自:http://blog.csdn.net/wen158809179/article/details/7419254
1. 让程序中只有一个 IndexWriter。因为 IndexWriter 是对索引库目录下的文件进行操作,就算在多线程情况下,每次也只会有一个线程在访问这个文件。
因此,程序中没必要维持多个 IndexWriter。
- /**
- * 使用 IndexWriter 进行保存或更新操作时,
- * 若不手动调用 IndexWriter 的 close 方法,数据并不会持久化到索引库中。
- * IndexWriter 一般只需要在程序退出的时候再关闭。
- * 因此,需要调用它的 commit 方法手动提交。需要特别注意。
- */
- public class LuceneUtils {
- private static IndexWriter indexWriter;
- static {
- try {
- /* 最好将目录放在配置文件 */
- Directory directory = FSDirectory.open(new File("./indexDir/"));
- /* 最好将版本放在配置文件 */
- Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_30);
- indexWriter = new IndexWriter(directory, analyzer, MaxFieldLength.LIMITED);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
- /**
- * 获取 IndexWriter
- */
- public static IndexWriter getIndexWriter() {
- return indexWriter;
- }
- /**
- * 关闭 IndexWriter
- */
- public static void closeIndexWriter() {
- try {
- indexWriter.close();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
- }
2. 文件优化
Lucene 会为每一次addDocument(document) 是在索引库目录下新增一个文件".cfs"后缀的文件。
这意味我们的程序将便对越来越多的文件(但是默认情况下,最多也不会超过10个,当文件达到10个的时候,lucene 会将它们合并为一个大的文件)。意味着 IO 流的打开和关闭也将越来越多。这对效率的影响是比较大的。
方式是调用 IndexWriter 的 IndexWriter.optimize() 或 indexWriter.setMergeFactor(int)
IndexWriter.optimize() 被调用后,lucene 会立即将索引库目录下所有 ".cfs" 后缀的文件合并为一个大的文件。但是它的数据是不会改变的。
indexWriter.setMergeFactor(int) 接收一个整型参数表示当 ".cfs" 文件达到多少数量时就自动合并。
3. 结合使用 FSDirectory 和 RAMDirectory
/*文件系统的索引库,指向物理介质上真实存在的文件 */
Directorydirectory = FSDirectory.open(new File("./indexDir/"));
/*内存索引库,是在内存中模拟的一个索引库 */
DirectoryRAMdir = new RAMDirectory();
优缺点:
FSDirectory 速度相对慢,但是 FSDirectory 的优点是能够在磁盘上持久化数据。
RAMDirectory 读写数据的速度明显要快,但是缺点是数据在程序退出时就没有了。而且受限制于内存的大小。
双剑合璧:
1. 在程序启动的时候,将磁盘上的索引库加载到内存中来。
2. 在程序退出的时候(或指定一个时机),将内存中的索引库数据状态同步会磁盘上。
怎样将磁盘上的索引库加载到内存中来?
Directory fsDir = FSDirectory.open(newFile("./indexDir/"));
//使用带参构造器创建 RAMDirectory 对象。下面代码参数为指向磁盘索引库的 FSDirectory 对象
Directory RAMdir = newRAMDirectory(directory);
怎样将内存中的索引库的数据同步回磁盘。
Directory RAMdir = newRAMDirectory();
Analyzeranalyzer = new StandardAnalyzer(Version.LUCENE_30);
IndexWriter ramIndexWriter = new IndexWriter(directory,analyzer,
MaxFieldLength.LIMITED);
//ramIndexWriter.update.delete... 更新索引库
/*同步数据回磁盘 */
DirectoryfsDir = FSDirectory.open(new File("./indexDir/"));
IndexWriter fsIndexWriter = new IndexWriter(directory,analyzer, MaxFieldLength.LIMITED);
fsIndexWriter.addIndexesNoOptimize(RAMdir);
以上是一种默认情况,就是 fsIndexWriter 会采用创建或追加的方式来同步数据。
-- 当磁盘上不存在对于索引库时则创建,并同步数据;否则,则追加和更新改变后的数据。
IndexWriter的另一个构造其可以改变这种默认形式:
IndexWriter fsIndexWriter =
new IndexWriter(directory,analyzer, [true | false], MaxFieldLength.LIMITED);
[true| false]: 若设置为 true,将总是创建或覆盖磁盘上的索引库。
-- 当磁盘上不存在对于索引库时则创建,并同步数据;否则,则覆盖掉原有的索引库的全部数据。
若设置为 false。则只追加和更新改变后的数据。若原有数据库不存在,将报错。
因此,一般用默认的就行了。true 的话要慎用。因为每次都推到重来,数据量很大的话,时间会比较久。