Lucene系列 - 索引(五) - Lucene索引高级特性:索引优化与同步锁

时间:2022-10-06 21:15:54

5.5 Lucene索引高级特性:
5.5.1 选择索引域类型:
5.5.2 索引参数优化:
5.5.3 使用磁盘索引:
5.5.4 使用内存索引:
5.5.5 同步与锁机制:

5.5.1 选择索引域类型:

1、尽量减少不必要的存储:
Store.NO不存储/YES存储/COMPRESS压缩存储原始内容
eg:

Field fieldId = new Field("id", keywords[i], Field.Store.YES, Index.NOT_ANALYZED);//生成关键字域

2、不需要建索引的内容不要建索引:
Field.Index.NO/TOKENIZED等等
eg:

Field fieldContent = new Field("content", textDetail[i], Field.Store.YES, Index.NOT_ANALYZED);//生成文本内容域

3、非文本格式化需要提前转化:
Lucene中处理的所有信息都是以文本形式进行的。
4、需要整体存放的内容不要分词:
对于文件名等信息需要以整体来检索访问。

5.5.2 索引参数优化:

Lucene索引在创建时,默认存储在内存中,超过一定数量时,写入硬盘设备。
这个机制使用了计算机操作系统 内存缓冲的成块读写机制。避免频繁I/O操作降低效率。

1、设置合并参数,setMergeFactor
控制合并索引的频率,也就是多少个文件之后把索引合并为一个新的子索引字段。系统默认为10.
2、设置最大文档个数setMaxBufferedDocs
控制合并段的大小,也就是多少个段之后可以合并为一个更大的新段。
为了避免无穷增大,使用这个参数来指定索引的停止条件。
3、限制索引项个数 setMaxFieldLength
默认的索引长度是前面10000个索引项。
4、设置最大内存删除项数setMaxBufferedDeleteTerms
用来修改删除文档时,最大一次可操作的个数。
当达到最大个数时,需要进行磁盘回写才能继续操作。

5.5.3 使用磁盘索引 FSDirectory:

Lucene中提供了内存索引模式(RAMDirectory)和 磁盘索引模式(FSDirectory)。
- 内存索引直接在内存中建立索引,速度最快,但是耗费内存资源,且重启后就丢失了。
另外某些海量数据的应用中,物理内存无法存储超大的数据。
- 物理索引的存储介质直接是磁盘,便于大量数据的存放。生成的存储文件可以长期保存,不会由于掉电而丢失。
索引建立的过程只占用很少的内存空间来缓存,以内存块的格式进行磁盘缓存读写,有很大的应用价值。
磁盘索引建立过程:

Directory directory = FSDirectory.open(new File(Dest_Index_Path));
Analyzer analyzer = new SimpleAnalyzer();//文本分析器
IndexWriterConfig conf = new IndexWriterConfig(Version.LATEST, analyzer);
conf.setUseCompoundFile(true);//采用多文件索引结构
IndexWriter indexWriter = new IndexWriter(directory, conf);

– 磁盘索引建立的过程仍然使用了内存索引,只不过缓存的大小是文档和文档集的层次,并没有把整个索引完全建立在内存中。
磁盘索引适合大数据量的存储,但是在检索和修改操作上有一定的效率问题。

5.5.4 使用内存索引 RAMDirectory:

响应速度快,不进行磁盘存储,适用于数据量小的检索系统。

内存索引建立过程:

- Directory directory = new RAMDirectory();
- Analyzer analyzer = new SimpleAnalyzer();//文本分析器
- IndexWriterConfig conf = new IndexWriterConfig(Version.LATEST, analyzer);
- IndexWriter indexWriter = new IndexWriter(directory, conf);

– 内存存储的RAMDiretory方式索引可以完成任何磁盘索引的工作,但是上面的构造函数并没有
指明索引创建的存放位置,检查磁盘的实际结果也是没有任何文档生成。
这种纯粹的内存索引虽然高效,但是每次需要重新建立索引,并不能保存已经索引过的数据,造成另一个角度的效率损失。

可以将内存索引和磁盘索引两者结合起来使用:
提高索引和检索的性能指标。
大致步骤:
- 1、生成FSDiretory类实例,使用IndexWriter创建磁盘索引对象;
- 2、生成RAMDiretory类实例,使用IndexWriter创建内存索引对象;
- 3、创建Directory实例,并添加相应的域;
- 4、把新建的Document添加到RAMDirectory中,关闭内存索引对
- 5、使用addIndexes 把RAMDiretory内容合并到FSDiretory中;
- 6、关闭磁盘索引。
—————————- code —————————-
Analyzer analyzer = new SimpleAnalyzer();//文本分析器
IndexWriterConfig conf = new IndexWriterConfig(Version.LATEST, analyzer);
conf.setUseCompoundFile(true);//采用多文件索引结构

//创建磁盘索引目录和磁盘索引 
Directory fsdDirectory = FSDirectory.open(new File(Dest_Index_Path));
IndexWriter fsIndexWriter = new IndexWriter(fsdDirectory, conf);

//创建内存索引目录和内存索引
Directory ramDirectory = new RAMDirectory();
IndexWriter ramIndexWriter = new IndexWriter(ramDirectory, conf);

//创建文档
Document doc = new Document();
Field fieldId = new TextField("id", "001", Store.YES);
Field fieldName = new TextField("name", "name 001", Store.YES);
doc.add(fieldId);
doc.add(fieldName);

//文档添加到内存索引
ramIndexWriter.addDocument(doc);
ramIndexWriter.close();//关闭内存索引,保存添加的数据

//添加内存索引到磁盘索引
fsIndexWriter.addIndexes(new Directory[] {ramDirectory});
fsIndexWriter.close();//关闭磁盘索引

—————————- code —————————-

– 上面code中,我们创建的内存索引在关闭以后已经不存在了,但是磁盘索引仍然可以取到索引的内容。
这是因为 实际内存索引的索引 存放在RAMDiretory创建的directory中,其结构和层次与磁盘索引一致,
只是存放在内存中,在索引创建完成后,索引数据只与内存虚拟目录结构有关系,在Directory对象释放之前都可以继续使用。

5.5.5 同步与锁机制:

搜索引擎支持动态索引和增量索引,不可避免的会产生同步问题。
同步机制可以保证索引文件不会同时被两个对象操作,保证索引的一致性和完整性。
对索引操作的主要的类有IndexWriter、IndexReader和IndexModifier(新版本已去除),以及检索类。
检索类属于读操作,不会破坏索引的完整性,其他3个操作需要保持互斥,避免破坏索引。
最后实现在同一时刻只存在一个修改操作。

Lucene为了保证索引的同步和并发,提供了【索引锁】。
- 实际就是一个存放在临时文件中的一个文件。当索引的操作类进行修改操作之前会查看该文件是否存在,
如存在,后来的操作者需要等待前面的操作者完成。
- 实现中采用了write.lock和commit.lock两种锁。
1、write.lock锁:
能够避免几个线程同时修改一个索引文档而设置。
当使用IndexWriter和IndexReader等进行索引建立、添加或删除文档时使用,在索引操作类初始化时创建,在关闭退出时删除。
2、commit.lock锁:
主要在segment建立、合并或读取时使用,只在索引的合并函数和段合并函数中使用。
当索引或段合并完成,会自动删除。