Lucene5学习之Directory理解

简介:

Directory即Lucene中对索引目录的一个抽象,体现到API上,它被设计为一个抽象类,类里面定义了一些抽象方法,如listAll列出目录下所有文件,deleteFile(String name) 根据文件名称删除索引文件,这个都是文件的基本操作,其中比较重要的一个接口方法是makeLock,为什么要为索引目录加锁?其实就跟你上厕所为什么要锁门是一样一样滴?我没拉完你就给我乖乖等着。

 BaseDirectory是Directory的一个子类,它默认实现了makeLock方法,

 

Java代码   收藏代码
  1. @Override  
  2.   public final Lock makeLock(String name) {  
  3.     return lockFactory.makeLock(this, name);  
  4.   }  

 这里的lockFactory仍然是一个抽象类,由子类传入传入具体的lockFactory工厂实现来创建不同的Lock实例FSDirectory是针对文件系统的一个Directory实现,即使用这个Directory就可以把索引文件存储到我们的文件系统里了。FSDirectory下面又有3个子类,分别是SimpleFSDirectory,NIOFSDirectory,MMapDirectory,

 

SimpleFSDirectory:它是基于文件系统的索引目录的一个简单实现,它在多线程环境下性能表现很差,不支持并发读写索引文件。

NIOFSDirectory:顾名思义,它就是使用NIO里的FileChannel文件通道来解决并发读写索引文件的,但它在windows平台下有个致命的BUG,官方建议在windows平台下使用RAFDirectory来代替NIOFSDirectory。

MMapDirectory:即基于内存映射的方式把文件load到内存来减少与IO的交互次数,从而提高IO性能,但这部分内存也存在隐患,因为JDK存在一个BUG,就是当IndexInput.close()时并不能有效的交还文件系统里索引文件的文件句柄,这就直接导致索引lock无法释放,一直直到GC回收这部分内存中潜在的对象时该句柄才会释放。由于文件句柄不能有效的立即释放,可能会导致你的硬盘空间得不到立即的释放,所以如果你的应用对于硬盘状况很敏感,这将是一个致命的定时炸蛋(连个zha弹都不让写,ITEye这是怎么了?),放在心里就行,反正暂时这个BUG未解决。(现在硬盘这么廉价,多浪费点硬盘空间也没啥)不过在linux系统上,即使句柄没有释放,当你删除索引文件时会提示是否在delete on last close,当你close时候还是会删除成功的,但索引文件还是会文件系统上占硬盘空间,而在windows平台上你只会得到一个Error,所以又是Windows,你懂的。

上面简单说了下各种FSDirectory的作用,下面简单说下各个Directory中比较重要的一些接口方法:

 

Java代码   收藏代码
  1. /** Just like {@link #open(Path)}, but allows you to 
  2.    *  also specify a custom {@link LockFactory}. */  
  3.   public static FSDirectory open(Path path, LockFactory lockFactory) throws IOException {  
  4.     if (Constants.JRE_IS_64BIT && MMapDirectory.UNMAP_SUPPORTED) {  
  5.       return new MMapDirectory(path, lockFactory);  
  6.     } else if (Constants.WINDOWS) {  
  7.       return new SimpleFSDirectory(path, lockFactory);  
  8.     } else {  
  9.       return new NIOFSDirectory(path, lockFactory);  
  10.     }  
  11.   }  

 FSDirectory类里的open方法是使用比较频繁的方法之一,其实内部就是根据用户的操作系统环境和使用的JDK来选择合适的Directory,

 

Constants.JRE_IS_64BIT即表示是否是64位的JDK,

MMapDirectory.UNMAP_SUPPORTED即表示是否支持Direct Buffer,什么叫Direct Buffer?其实Direct Buffer并不是直接分配在堆上的,Direct Buffer不受GC管理,即Direct Buffer是有操作系统来销毁的,但Direct Buffer上对象是由GC负责回收的,Direct Buffer读写之所以快,是因为减少数据拷贝到内核缓冲区的操作,但Direct Buffer是由操作系统负责销毁,所以代价也是很高的。那我们看看Lucene是如何判断是否支持Direct Buffer的?

Java代码   收藏代码
  1. /** 
  2.    * <code>true</code>, if this platform supports unmapping mmapped files. 
  3.    */  
  4.   public static final boolean UNMAP_SUPPORTED;  
  5.   static {  
  6.     boolean v;  
  7.     try {  
  8.       Class.forName("sun.misc.Cleaner");  
  9.       Class.forName("java.nio.DirectByteBuffer")  
  10.         .getMethod("cleaner");  
  11.       v = true;  
  12.     } catch (Exception e) {  
  13.       v = false;  
  14.     }  
  15.     UNMAP_SUPPORTED = v;  
  16.   }  

 其实就是判断JDK里是否有sun.misc.Cleaner这个类,以及Java.nio.DirectByteBuffer类是否有cleaner方法。

这两个类都是用于Direct buffer里对象清理工作的。

Oracle/Sun JDK 6中的HotSpot VM只会在年老代GC(full GC/major GC或者concurrent GC都算)的时候才会做reference processing,而在young GC/minor GC时不做。 也就是说,做full GC的话会做reference processing,进而能触发Cleaner对已死的DirectByteBuffer对象做清理工作。而如果很长一段时间里没做过GC或者只做了young GC的话则不会触发Cleaner的工作,那么就可能让本来已经死了的DirectByteBuffer关联的native memory得不到及时释放。 

之所以要保证有上述两个类,就是确保DirectByteBuffer里的内存能得到释放以保证性能,这样你使用MMapDirectory才能体现它的优势又能避免它潜在的隐患。

还有一个比较重要的Directory就是RAMDirectory,就是内存索引目录,即把索引文件数据load到堆中,内部就是用new byte[1024]来缓存索引数据的,这适合于小量的索引文件,RAMDirectory设计之初就不是为百万级别的大数量的索引而设计的,因为它会在你的内存产生数以百万的byte[1024],从而导致频繁GC回收,影响性能,而且它在多线程并发环境下表现也很糟糕,官方建议是:大数据量的索引请使用MMapDirectory,RAMDirectory的使用场景是当你创建索引时可以先把少量的索引放入内存,再switch到FSDirectory flush到file system,利用内存减少与File System访问次数。

另外一个比较重要的Directory就是FileSwitchDirectory,它就是集NIODirectory与MMapDirectory优点与一身的Directory,NIODirectory是直接把文件放入heap buffer中,而MMapDirectory是把文件直接映射到Direct buffer,由于Heap buffer可使用量大而Direct buffer虽然读写速度快,但它受操作系统调度,开辟和销毁的代价太高,不宜过多使用,所以一般我们需要使用NIODirectory来读写比较大的索引文件,而用MMapDirectory来读写相对比较小的文件,两者结合互补你懂的。

同理Lock也有对应的3种实现,就不赘述了。

一般我们使用FSDirectory.open由api自动帮我们来选择合适的Directory即可,特殊情况下可以使用FileSwitchDirectory结合下两种Directory的优点。关于Directory就说这么多了,如果有哪里说的不正确,还望你提出来,谢谢!

 

如果你还有什么问题请加我Q-Q:7-3-6-0-3-1-3-0-5,

或者加裙
一起交流学习!

转载:http://iamyida.iteye.com/blog/2194394

目录
相关文章
|
XML 存储 JSON
Solr学习总结
Solr学习总结
127 0
Solr学习总结
|
缓存 Java 索引
Solr&Lucene cache简要汇总
假期重新把之前在新浪博客里面的文字梳理了下,搬到这里。本文汇总Solr Lucene cache相关内容。撇开系统结构、架构这些整体性的分析,纯粹从使用方面做梳理。
187 0
Solr&Lucene cache简要汇总
|
存储 算法 Java
Lucene/Solr Optimize相关总结
假期重新把之前在新浪博客里面的文字梳理了下,搬到这里。
155 0
|
算法 前端开发 数据建模
Solr&lucene 默认的spatial search性能总结
假期重新把之前在新浪博客里面的文字梳理了下,搬到这里。介绍地理搜索性能优化的一些经验。
142 0
|
自然语言处理 Java API
Lucene&solr 4 实践(1)
假期重新把之前在新浪博客里面的文字梳理了下,搬到这里。Solr&Lucene 4.0 好,很好,很强大。对于从lucene2.0 solr0.9 就关注,一直过来的人来讲, 4.X序列除了的架构、风格、API改变了很多很多,更重要的是业务的优化口子更多了,专业知识要求更高。整个架子的容量、包容性、以及适应信息检索的科研,直接上来demo运行easy、深入会很难。需要整理了解的知识点太多了。
78 0
|
自然语言处理 算法 架构师
Lucene&solr 4 实践(8)
假期重新把之前在新浪博客里面的文字梳理了下,搬到这里。Lucene 5 有哪些点对大数据倒排索引和检索有优势 1.索引懒加载lazy加载,意味着按时间段或者其他分割的数据可以按需加载 2.FST词典结构以及基于图的索引、查询,使得内存消耗更低 3.异步合并,使得增量索引合并时的“索引整理”开销或者对查询影响更小 4.commitpoint 视图下reader自动更新,使得大规模数据的虚拟分组、全量切换更加方便。
117 0
|
自然语言处理 算法 Apache
Lucene&solr 4 实践(5)
假期重新把之前在新浪博客里面的文字梳理了下,搬到这里。这部分先通透FST的原理和构造方法,方便理解lucene FST、Builder两个核心对象,从而彻底看清基于图的lucene4索引、查询的发展脉络。至于读懂后有神马用,自个琢磨啊! 看懂估计要死伤不少脑细胞哦!
197 0
|
编解码 缓存 自然语言处理
Lucene&Solr 4 实践(2)
假期重新把之前在新浪博客里面的文字梳理了下,搬到这里。在第一部分,还不完善基础上,进入第二部分吧。结合源码来认识lucene! 重点是:从需求到方案到实践编码到结果、从原理到实现、从结构到细节、从总体认识到西部深入。
82 0
|
算法 Java Maven
Lucene&solr 4 实践(4)
假期重新把之前在新浪博客里面的文字梳理了下,搬到这里。本部分主要分析FST,快乐理解lucene fst包的源码细节和来龙去脉。
120 0
|
自然语言处理 索引
Lucene&solr 4 实践(3)
假期重新把之前在新浪博客里面的文字梳理了下,搬到这里。本部分主要是针对FSA FST做前期知识储备和基本概念扫盲。FST是lucene4 solr4 的索引和查询的核心! 下面的内容来自多个出去,出去就不一一列举。
89 0
Lucene&solr 4 实践(3)