本文共 4720 字,大约阅读时间需要 15 分钟。
介绍了Lucene检索的一系列流程,本篇来看下Lucene中一个特殊的Directory的实现之FileSwitchDirectory,顾名思义,从字面上的意思来理解是一个基于文件目录切换的一个实现,实际上也正是如此。 那么,此类的作用是什么呢? 我们都知道lucene的索引文件是非常松散灵活的,各个文件格式之间相互独立而又有联系,在Lucenen检索的时候,会并行的打开所有的段文件,然后合并结果集至一个公共队列里返回。 Lucene的Directory基类,提供了非常丰富的子类实现,为什么如此呢,其实跟不同的操作系统和平台有紧密的联系,所以在我们的代码里,经常会使用FSDirectory的静态方法来打开一个能在我们所使用的平台上发挥最大优势的Directory,在源码里我们可以发现这个方法里面是对主流的操作系统进行了判断和选择后,会给我们返回一个合适的Directory,可能这个方法在不同的操作平台上返回不一样的Directory的实现,这一点是很正常的。 Java代码 复制代码 收藏代码 1.public static FSDirectory open(File path, LockFactory lockFactory) throws IOException { 2. if ((Constants.WINDOWS || Constants.SUN_OS || Constants.LINUX) 3. && Constants.JRE_IS_64BIT && MMapDirectory.UNMAP_SUPPORTED) { 4. return new MMapDirectory(path, lockFactory); 5. } else if (Constants.WINDOWS) { 6. return new SimpleFSDirectory(path, lockFactory); 7. } else { 8. return new NIOFSDirectory(path, lockFactory); 9. } 10. } FileSwitchDirectory的出现,可以使我们组合不同Directory的优点,来充分利用我们的系统资源,我们都知道使用内存索引RAMDirectory来访问索引其速度和效率都是非常优异的,然后,有时候我们的数据量大的惊人,以至于内存中根本放不下这个索引文件,那么这时候我们既想获取高效的索引访问性能,又想获取读取和检索大索引的优异的并发性能,这时候我们怎么做呢? 这时候就是该FileSwitchDirectory大显身手的时候了,利用这个类,我们可以轻而易举的结合任意2个Directory的优异点,来为我们所用,下面我们先来看下FileSwitchDirectory在源码里的构造实现。 Java代码 复制代码 收藏代码 1./** 2. * @param primaryExtensions 由主索引负责打开的文件 3. * @param primaryDir 主索引目录 4. * @param secondaryDir 从索引目录 5. * @param doClose 是否在关闭时关闭所有Directory的资源 6. * **/ 7. public FileSwitchDirectory(Set<String> primaryExtensions, Directory primaryDir, Directory secondaryDir, boolean doClose) { 8. this.primaryExtensions = primaryExtensions; 9. this.primaryDir = primaryDir; 10. this.secondaryDir = secondaryDir; 11. this.doClose = doClose; 12. this.lockFactory = primaryDir.getLockFactory(); 13. } 由构造方法可以看出FileSwitchDirectory是需要2个Directory的实现才可以组装起来,而通过第一个参数我们可以指定主索引需要加载的索引文件,其它的将会由从Directory来实现,由此达到,快速切换不同的Directory来获取他们各自的优点。 一般情况下我们会将fdt和fdx文件放在NIODirectory里,因为这两个文件分别存储的是文档的正向信息包含具体的term,fdx文件是fdt文件的一个索引文件,实际上在后来,所有的文本数据都会保存在fdt里,索引在索引非常大的时候,这两个文件是最占容量的,所以我们选择将此放入NIO中,由此来访问大索引信息,其他的一些段信息文件,字典文件,放入内存索引中由此来获取更高的检索效率。 下面是散仙的一个示例的索引截图: 注意上图中可能大家会发现tim的项词典文件,也挺大的,散仙在这里解释一下,散仙在索引只索引了2个非常短的字段,然后循环添加了1万次,在实际项目中,肯定是多个字段组成且文本内容会比较多,那个时候索引出来的数据fdt文件一般都是最大的数据文件。 实现切换索引的代码如下: Java代码 复制代码 收藏代码 1.String path="E:\\1111111111111111111\\1\\"; 2. try{ 3. //添加放置在nio文件里的索引文件 4. Set<String> files=new HashSet<>(); 5. files.add("fdt"); 6. files.add("fdx"); 7. 8. Directory d1=FSDirectory.open(new File(path));//装载磁盘索引 9. RAMDirectory map=new RAMDirectory(d1,IOContext.READ);//放置内存索引 10. NIOFSDirectory nio=new NIOFSDirectory(new File(path));//基于并发大文件的NIO索引 11. FileSwitchDirectory fsd=new FileSwitchDirectory(files,nio,map,true); //切换实现 12. for(String s:fsd.listAll()){ 13. //System.out.println(s); 14. System.out.println("文件:"+s+" 读取类型: "+fsd.getDirectory(s)); 15. 16. } 运行效果如下所示: Java代码 复制代码 收藏代码 1.文件:_2.si 读取类型: org.apache.lucene.store.RAMDirectory@6a059fa4 lockFactory=org.apache.lucene.store.SingleInstanceLockFactory@1733fe5d 2.文件:_2_Lucene41_0.tim 读取类型: org.apache.lucene.store.RAMDirectory@6a059fa4 lockFactory=org.apache.lucene.store.SingleInstanceLockFactory@1733fe5d 3.文件:segments.gen 读取类型: org.apache.lucene.store.RAMDirectory@6a059fa4 lockFactory=org.apache.lucene.store.SingleInstanceLockFactory@1733fe5d 4.文件:_2.fdt 读取类型: org.apache.lucene.store.NIOFSDirectory@E:\1111111111111111111\1 lockFactory=org.apache.lucene.store.NativeFSLockFactory@37263a93 5.文件:segments_2 读取类型: org.apache.lucene.store.RAMDirectory@6a059fa4 lockFactory=org.apache.lucene.store.SingleInstanceLockFactory@1733fe5d 6.文件:_2_Lucene41_0.doc 读取类型: org.apache.lucene.store.RAMDirectory@6a059fa4 lockFactory=org.apache.lucene.store.SingleInstanceLockFactory@1733fe5d 7.文件:_2_Lucene41_0.tip 读取类型: org.apache.lucene.store.RAMDirectory@6a059fa4 lockFactory=org.apache.lucene.store.SingleInstanceLockFactory@1733fe5d 8.文件:_2.fdx 读取类型: org.apache.lucene.store.NIOFSDirectory@E:\1111111111111111111\1 lockFactory=org.apache.lucene.store.NativeFSLockFactory@37263a93 9.文件:_2.fnm 读取类型: org.apache.lucene.store.RAMDirectory@6a059fa4 lockFactory=org.apache.lucene.store.SingleInstanceLockFactory@1733fe5d 由输出结果,我们可以看出除了fdt文件和fdx文件是从NIO里打开的,其他的都会被加载到RAM里,与我们预期的假设是一致的。 最后我们来简单分析下,Lucene是如何实现索引的动态的切换? 实际上在程序一开始启动时,是打开了2个Directory,然后通过FileSwitchDirectory 组装在了一起,在一个检索请求发来时,会选择具体的索引文件打开并读取,此时就是切换目录的时候,我们可以在FileSwitchDirectory 的源码里找到如下的一段代码: Java代码 复制代码 收藏代码 1./** 2. * 切换目录的核心代码 3. * @param name 具体的索引文件名 4. * @return 返回的具体Directory 5. * ***/ 6. public Directory getDirectory(String name) { 7. String ext = getExtension(name); 8. if (primaryExtensions.contains(ext)) {//在初始化的集合里判断 9. return primaryDir;//true,将会从主索引加载 10. } else { 11. return secondaryDir;//false将会从从索引加载 12. } 13. } 其实,就是在启动的时候打开了同一份索引的2个不同的Directory的实现,然后通过FileSwitchDirectory 这个类,来动态的完成的索引切换的过程转载地址:http://dwnoi.baihongyu.com/