Lucene5学习之Directory理解

2023-11-02 01:48

本文主要是介绍Lucene5学习之Directory理解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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

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

 

@Overridepublic final Lock makeLock(String name) {return lockFactory.makeLock(this, name);}

 这里的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中比较重要的一些接口方法:

 

/** Just like {@link #open(Path)}, but allows you to*  also specify a custom {@link LockFactory}. */public static FSDirectory open(Path path, LockFactory lockFactory) throws IOException {if (Constants.JRE_IS_64BIT && MMapDirectory.UNMAP_SUPPORTED) {return new MMapDirectory(path, lockFactory);} else if (Constants.WINDOWS) {return new SimpleFSDirectory(path, lockFactory);} else {return new NIOFSDirectory(path, lockFactory);}}

 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的?

/*** <code>true</code>, if this platform supports unmapping mmapped files.*/public static final boolean UNMAP_SUPPORTED;static {boolean v;try {Class.forName("sun.misc.Cleaner");Class.forName("java.nio.DirectByteBuffer").getMethod("cleaner");v = true;} catch (Exception e) {v = false;}UNMAP_SUPPORTED = v;}

 其实就是判断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,

或者加裙
一起交流学习!
 

这篇关于Lucene5学习之Directory理解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/327262

相关文章

从原理到实战深入理解Java 断言assert

《从原理到实战深入理解Java断言assert》本文深入解析Java断言机制,涵盖语法、工作原理、启用方式及与异常的区别,推荐用于开发阶段的条件检查与状态验证,并强调生产环境应使用参数验证工具类替代... 目录深入理解 Java 断言(assert):从原理到实战引言:为什么需要断言?一、断言基础1.1 语

Go学习记录之runtime包深入解析

《Go学习记录之runtime包深入解析》Go语言runtime包管理运行时环境,涵盖goroutine调度、内存分配、垃圾回收、类型信息等核心功能,:本文主要介绍Go学习记录之runtime包的... 目录前言:一、runtime包内容学习1、作用:① Goroutine和并发控制:② 垃圾回收:③ 栈和

Android学习总结之Java和kotlin区别超详细分析

《Android学习总结之Java和kotlin区别超详细分析》Java和Kotlin都是用于Android开发的编程语言,它们各自具有独特的特点和优势,:本文主要介绍Android学习总结之Ja... 目录一、空安全机制真题 1:Kotlin 如何解决 Java 的 NullPointerExceptio

重新对Java的类加载器的学习方式

《重新对Java的类加载器的学习方式》:本文主要介绍重新对Java的类加载器的学习方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、介绍1.1、简介1.2、符号引用和直接引用1、符号引用2、直接引用3、符号转直接的过程2、加载流程3、类加载的分类3.1、显示

spring IOC的理解之原理和实现过程

《springIOC的理解之原理和实现过程》:本文主要介绍springIOC的理解之原理和实现过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、IoC 核心概念二、核心原理1. 容器架构2. 核心组件3. 工作流程三、关键实现机制1. Bean生命周期2.

Java学习手册之Filter和Listener使用方法

《Java学习手册之Filter和Listener使用方法》:本文主要介绍Java学习手册之Filter和Listener使用方法的相关资料,Filter是一种拦截器,可以在请求到达Servl... 目录一、Filter(过滤器)1. Filter 的工作原理2. Filter 的配置与使用二、Listen

深入理解Apache Kafka(分布式流处理平台)

《深入理解ApacheKafka(分布式流处理平台)》ApacheKafka作为现代分布式系统中的核心中间件,为构建高吞吐量、低延迟的数据管道提供了强大支持,本文将深入探讨Kafka的核心概念、架构... 目录引言一、Apache Kafka概述1.1 什么是Kafka?1.2 Kafka的核心概念二、Ka

Java进阶学习之如何开启远程调式

《Java进阶学习之如何开启远程调式》Java开发中的远程调试是一项至关重要的技能,特别是在处理生产环境的问题或者协作开发时,:本文主要介绍Java进阶学习之如何开启远程调式的相关资料,需要的朋友... 目录概述Java远程调试的开启与底层原理开启Java远程调试底层原理JVM参数总结&nbsMbKKXJx

Java深度学习库DJL实现Python的NumPy方式

《Java深度学习库DJL实现Python的NumPy方式》本文介绍了DJL库的背景和基本功能,包括NDArray的创建、数学运算、数据获取和设置等,同时,还展示了如何使用NDArray进行数据预处理... 目录1 NDArray 的背景介绍1.1 架构2 JavaDJL使用2.1 安装DJL2.2 基本操

深入理解Apache Airflow 调度器(最新推荐)

《深入理解ApacheAirflow调度器(最新推荐)》ApacheAirflow调度器是数据管道管理系统的关键组件,负责编排dag中任务的执行,通过理解调度器的角色和工作方式,正确配置调度器,并... 目录什么是Airflow 调度器?Airflow 调度器工作机制配置Airflow调度器调优及优化建议最