Lucene 的 Directory 是一个抽象类,是针对索引文件目录操作的抽象类,对文件操作都是通过 Directory 来实现的;Directory 的实现类可以分为文件目录、内存目录和目录的代理类及工具类。
文件目录
FSDirectory 是文件目录操作的抽象类,其下主要有三个具体的实现类 SimpleFSDirectory,NIOFSDirectory 和 MMapDirectory。
SimpleFSDirectory
SimpleFSDirectory 是 FSDirectory 抽象类的最简单直接的实现,读写操作都使用的是 java.io.RandomAccessFile;然而它的并发能力很差,在多个线程针对同一个文件进行读操作时,需要进行同步操作也就是相当于串行操作,通常用 NIOFSDirectory 和 MMapDirectory 代替。
NIOFSDirectory
NIOFSDirectory 顾名思义,它是使用 NIO 的 FileChannel 来解决读索引文件并发能力的,该类仅使用 FileChannel 进行读操作,写操作则是通过 FSDirectory 的 FSIndexOutput 实现;值得注意的是,NIOFSDirectory 在 Windows 的 Sun JRE 下有致命的 bug,原因是由于 FileChannel.read 在 Windows下是同步操作(bug地址:http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6265734),此外如果一个访问该类的线程,在 IO 阻塞时被 interrupt 或 cancel,将会导致底层的文件描述符被关闭,后续的线程再次访问 NIOFSDirectory 时将会出现 ClosedChannelException 异常,此种情况应用 SimpleFSDirectory 代替。
MMapDirectory
FSDirectory 抽象类的实现类,读操作通过内存映射进行,写操作则通过 FSDirectory 的 FSIndexOutput 来实现;它的主要变化即读操作是基于内存映射的方式把文件 load 到内存来减少与 IO 的交互次数,从而提高IO性能;使用该类时要保证用足够的虚拟地址空间。此外当通过 IndexInput 的 close 方法进行关闭时,并不会立即关闭底层的文件句柄,只有 GC 进行资源回收时才会关闭。
NativeUnixDirectory
Lucene 4 开始使用新的 NativeUnixDirectory,针对所有 merge 引发的 IO,它会跳过操作系统的 IO cache 层,而使用 DIRECT I/O。这会保证 merge 不会 evict 搜索使用的热门 pages。
RAFDirectory
NIOFSDirectory 在 Windows 平台下有个致命的 BUG,官方建议在 Windows 平台下使用 RAFDirectory 来代替 NIOFSDirectory。
WindowsDirectory
Windows 平台下的 Directory 的实现类。
文件目录实现类对比
类 | 写操作 | 读操作 | 特点 |
---|---|---|---|
SimpleFSDirectory | java.io.RandomAccessFile | java.io.RandomAccessFile | 简单实现,并发能力差 |
NIOFSDirectory | FSDirectory.FSIndexOutput | java.nio.FileChannel | 并发能力强 |
MMapDirectory | FSDirectory.FSIndexOutput | 内存映射 | 读取操作基于内存 |
内存目录
读写操作都在内存中进行的方式。
RAMDirectory
常驻内存的 Directory 实现方式。默认通过 SingleInstanceLockFactory (单实例锁工厂)进行锁的实现。该类不适合大量索引的情况。另外也不适用于多线程的情况。在索引数据量大的情况下,建议使用 MMapDirectory 代替。
RAMDirectory 是 Directory 抽象类在使用内存作为文件存储的实现类,其主要是将所有的索引文件保存到内存中。这样可以提高效率。但是如果索引文件过大的话,则会导致内存不足,因此,小型的系统推荐使用,如果大型的,索引文件达到G级别上,推荐使用 FSDirectory。
NRTCachingDirectory
NRTCachingDirectory 是针对 RAMDirectory 封装的代理类,主要用在近实时搜索场景下,NRT 就是 near-real-time (近实时)的缩写;具体特点是在少量写入索引时,写索引稍微慢,读索引相对比较快。
目录的代理类及工具类
FileSwitchDirectory
FileSwitchDirectory 是 Lucene 的另一种 Directory 实现类,从名字个就可以理解为文件切换的 Directory 实现,是针对 Lucene 的不同的索引文件使用不同的 Directory。借助 FileSwitchDirectory 整合不同的 Directory 实现类的优点于一身。比如 MMapDirectory,借助内存映射文件方式提高性能,但又要减少内存切换的可能,当索引太大的时候,内存映射也需要不断地切换,这样优点也可能变缺点,而之前的 NIOFSDirectory 实现 java NIO 的方式提高高并发性能,但又因高并发也会导致 IO 过多的影响,所以这次可以借助 FileSwitchDirectory 发挥他们两的优点。
CompoundFileDirectory
用于访问一个组合的数据流。仅适用于读操作。对于同一段内扩展名不同但文件名相同的所有文件合并到一个统一的 .cfs 文件和一个对应的 .cfe 文件内。.cfs 文件由 Header,FileData 和 FileCount 组成。.cfe 文件由 Header,FileCount,FileName,DataOffset,DataLength组成。.cfs 文件中存储着索引的概要信息及组合文件的数目(FileCount)。.cfe 文件存储文件目录的条目内容,内容中包括文件数据扇区的起始位置,文件的长度及文件的名称。
TrackingDirectoryWrapper
Directory 的代理类,用于记录哪些文件被写入和删除。
RateLimitedDirectoryWrapper
通过 IOContext 来限制读写速率的 Directory 封装类。
Directory 类方法
方法 | 描述 |
---|---|
close() |
关闭存储 |
copyFrom() |
复制索引目录中的指定文件到指定的另一个文件 |
createOutput() |
创建在给定名称的目录中一个新的空文件 |
createTempOutput() |
创建在给定前缀及后缀名称的目录中一个新的空文件,以 .tmp 为扩展名 |
deleteFile() |
删除目录中的指定名称的文件 |
ensureOpen() |
确保目录是否关闭 |
fileLength() |
返回目录中的指定文件的长度 |
listAll() |
返回目录中的所有文件文件名称 |
obtainLock() |
返回目录中指定锁文件的锁 |
openChecksumInput() |
返回目录中指定文件的Checksum输入流 |
openInput() |
返回目录中指定文件的输入流 |
rename() |
给目录中的指定文件重命名 |
renameFile() |
不推荐 Deprecated。给目录中的指定文件重命名(原子操作,且在重命名的文件不存在时) |
sync() |
给目录中指定文件列表同步持久化 |
syncMetaData() |
确保目录的metadata是否持久化 |