`
weitao1026
  • 浏览: 1055605 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

子类FSDirectory

阅读更多
介绍了lucene的存储根基Directory的一些原理,以及也给出了Directory家族的继承分布图,那么本篇呢,将重点介绍下Directory的一个很重要的子类FSDirectory,为什么说此类非常重要呢?如果你是正在使用lucene的开发者,那么你就知道,我们经常使用的一行代码:



Java代码 复制代码 收藏代码
1.Directory directory=FSDirectory.open(new File(indexPath)) 


通过这行代码,我们可以获取一个Directory的子类文件存储目录,然后我们对索引的一些操作,都是以这个子类的文件目录为基础的,

下面我们从源码的角度来详细剖析下FSDirectory这个类的作用,在此之前,散仙先用一个表格来介绍下lucene存储索引的几种方式:


序号 方式
1 将索引存储在内存中
2 将索引通过JDBC存储在数据库中
3 将索引存储在一般的文件系统上,如Windows,Linux,Solaris
4 将索引存储在分布式文件系统上,如HDFS


上面的几种存储方式是lucene目前为止,能够支持良好的的格式,那么今天,散仙要介绍的FSDirectory这类方式,就是上图表格中,第三类基于文件系统存储方式的根基,FSDirectory并不是一个具体的文件目录,通常情况下,我们使用的是FSDirectory下某一个具体的子类(MMapDirectory,SimpleFSDirectory,NIOFSDirectory)来作为我们的索引目录,那么我们可能有个很大的疑惑,我们在实际开发中大部分时候并没有直接指定具体使用的是那个目录,为什么我们还能正常使用它呢?
别着急,下面散仙,会给大家详细解说的,我们先来看下我们经常使用的那个FSDirectory的open()方法源码是怎么实现的:



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


这段代码,还是比较通俗易懂的,相信各位朋友,已经看出来它是怎么实现的,那么散仙就来分析一下这段代码的含义,事实上我们通过open方法,lucene底层通常情况下,会给我们选择一个最适合我们当前操作系统用的索引目录,当然这种选择通常跟我们的JRE的位数是直接相关的,大多数的Solaris,Linux和windows64位系统的jre会返回MMapDirectory,而其他的一些位数的JRE,如32位的JRE在Windows上会返回SimpleFSDirectory,剩余的部分则会直接使用NIOFSDirectory来存储索引。那么这三种方式有什么不同呢?散仙总结如下:

1,SimpleFSDirectory,这个类简单的实现使用RandomAccessFile来完成索引的存储,读写速度一般,并发性很差,在多个线程同时访问索引时,会造成线程同步,从而大大降低了性能,当然,如果我们并发性不是很大的话,使用它也是一个不错的选择

2,MMapDirectory使用内存映射IO的方式来操作索引,在性能上是非常优秀的,读写速度非常快,并发性支持一般,当然这种情况仅仅局限于,你的索引的大小小于系统内存的时候,这才是一个好的选择,否则,使用不当,将常常会造成内存溢出的异常。

3,NIOFSDirectory使用的是JAVA NIO的 FileChannel的来操作索引的,读写速度快,对并发支持非常优秀,因为它利用NIO的特性,避免了同步的读取,所以在高并发的场景下,这个目录往往是最佳的选择。



下面,我们来分析下FSDirectory的另外一个重要的方法sysc()。



Java代码 复制代码 收藏代码
1. protected final Set<String> staleFiles = synchronizedSet(new HashSet<String>()); // Files written, but not yet sync'ed 
2. 
3. @Override 
4. public void sync(Collection<String> names) throws IOException { 
5.   ensureOpen(); 
6.   Set<String> toSync = new HashSet<String>(names);//需要持久化的一些元数据标识 
7.   toSync.retainAll(staleFiles);//此方法会与staleFiles里面的数据求交集 
8. 
9.   for (String name : toSync) 
10.     fsync(name);//把内存中或缓冲区的数据,强制写到磁盘上,确保数据不会流失 
11. 
12.   staleFiles.removeAll(toSync);//在staleFiles中移除已经持久化到磁盘的数据,等待下一次的数据添加 
13. } 
14. 
15.protected void fsync(String name) throws IOException { 
16.   File fullFile = new File(directory, name); 
17.   boolean success = false; 
18.   int retryCount = 0; 
19.   IOException exc = null; 
20.   while (!success && retryCount < 5) { 
21.     retryCount++; 
22.     RandomAccessFile file = null; 
23.     try { 
24.       try { 
25.         file = new RandomAccessFile(fullFile, "rw"); 
26.         file.getFD().sync();//写入磁盘上 
27.         success = true; 
28.       } finally { 
29.         if (file != null) 
30.           file.close(); 
31.       } 
32.     } catch (IOException ioe) { 
33.       if (exc == null) 
34.         exc = ioe; 
35.       try { 
36.         // Pause 5 msec 
37.         Thread.sleep(5); 
38.       } catch (InterruptedException ie) { 
39.         throw new ThreadInterruptedException(ie); 
40.       } 
41.     } 
42.   } 
43.   if (!success) 
44.     // Throw original exception 
45.     throw exc; 
46. } 


其实,sysc这个方法,是从Directory这个顶级父类,继承过来的,由FSDirectory这个类,对其进行了重写,这个方法的目的,就是定期根据某些条件,来将我们内存或缓冲区的数据持久化到磁盘上,以确保我们已经索引的数据是非常安全的,不会因为一些意外情况,如系统崩溃,或突然宕机,停电的情况下,对索引结构造成破坏或一些影响。

一个简单的工作流程是这样的,当我们进行添加操作时,文件目录通常会打开一个或几个特定的文件格式来存储我们的数据,比如索引正文的存储,向量的存储,位置增量的存储,不同的索引格式负责存储不同的内容,当一些数据添加完毕后,通过某些条件触发持久化操作,比如超出了设置的缓冲区大小,或者超出了默认的Doc数,或者我们调用了commit方法,这时lucene会调用sysc方法,来把已经添加的数据,存储到磁盘上,以确保数据的安全存储,当然这些工作,lucene底层已经给我们实现好了,我们并不需要显示的调用这个方法来完成数据持久操作,就能绝大多数情况下,安全可靠的完成存储,而这一切正是sysc发挥的关键作用。
分享到:
评论

相关推荐

    lucence 索引合并 汇总

    FSDirectory fsdir = new FSDirectory(); ``` 这里分别创建了一个基于内存的`RAMDirectory`和基于文件系统的`FSDirectory`对象。 2. **创建IndexWriter实例**: ```java IndexWriter ramWriter = new ...

    Lucene使用代码实例之搜索文档

    FSDirectory directory = FSDirectory.getDirectory(indexDir,false); IndexSearcher searcher = new IndexSearcher(directory); // 检查索引是否存在 if(!indexDir.exists()){ System.out.println("The ...

    Hadoop源代码分析(二三)

    ### Hadoop源代码分析——FSDirectory深入解析 #### 一、引言 在深入了解Hadoop内部机制的过程中,源代码的分析是不可或缺的一环。本文将聚焦于Hadoop中的`FSDirectory`类,它是HDFS(Hadoop分布式文件系统)核心...

    Hadoop源代码分析(三一)

    这个操作首先通过调用`FSNamesystem`的`renameTo`方法开始,接着由`renameToInternal`处理,最终由`FSDirectory`的`renameTo`实现。如果操作成功,还会更新文件的租约名称,确保数据的一致性。 2. 文件删除: `...

    lucene学习笔记

    具体步骤包括获取两个或多个目录对象,如通过`FSDirectory.getDirectory()`方法指定索引路径;然后创建`ParallelReader`实例,并通过`add()`方法添加每个目录对应的`IndexReader`实例。最后,基于`ParallelReader`...

    lucene 简单例子

    FSDirectory directory = FSDirectory.open(Paths.get("index")); // 创建分析器 Analyzer analyzer = new StandardAnalyzer(); // 创建 IndexWriter 配置并打开 IndexWriter IndexWriterConfig config = new...

    lucene搜索过程代码详解

    1.1. `FSDirectory.GetDirectory(path, false)`:这个方法创建一个指向索引文件的`FSDirectory`实例,`create`参数决定是否创建新目录。 1.1.1. `GetDirectory(new System.IO.FileInfo(path), create)`:这是获取...

    lucene练习代码

    1. 使用合适的数据结构:例如,使用`FSDirectory`存储索引,而非内存中的`RAMDirectory`。 2. 分片和分布式搜索:对于大型数据集,可以将索引分成多个分片,并在多台机器上分布式存储和搜索。 3. 倒排索引:这是...

    lucene-3.0.2-dev-src

    Lucene支持两种存储方式:内存索引(RAMDirectory)和磁盘索引(如FSDirectory)。内存索引适用于临时或测试环境,而磁盘索引适合大规模数据持久化存储。`Directory`类及其子类封装了对索引文件的读写操作。 6. **...

    lucene.net基本应用(doc)

    - 在生产环境中,通常会使用 `FSDirectory` 而不是 `RAMDirectory`,因为后者只适合测试,不适合大型或持久化的索引。 通过以上步骤,你可以了解如何使用 Lucene.NET 创建和搜索简单的文本索引。在实际应用中,...

    lucene3.6 的源代码

    在`src/java/org/apache/lucene/search`目录中,`Query`类及其子类定义了各种查询类型,如`TermQuery`、`BooleanQuery`和`WildcardQuery`。查询构造器如`QueryParser`将用户的自然语言输入转换为对应的查询对象,...

    lucene2.9.1所有最新开发包及源码及文档

    a) 文件系统:FSDirectory: FSDirectory.open(File file); b) 内存RAMDirectory: new RAMDirectory(); 3) Analyzer: 分词器。 a) StandardAnalyzer: 标准分词器。对英文采用空白, 标点符号进行分词。对中文采用...

    Lucene建立索引及查询包含“java”关键字 示例代码

    1. **创建一个Directory对象**:这是Lucene用来存储索引的接口,可以是内存中的RAMDirectory,也可以是磁盘上的FSDirectory。 2. **创建Analyzer**:Analyzer负责将文本分词,如英文单词。这里我们可以使用...

    获取全部Luence数据

    IndexSearcher searcher = new IndexSearcher(FSDirectory.Open(new System.IO.DirectoryInfo(IndexPath)), true); // 获取文档总数 int count = searcher.MaxDoc(); // 创建文档并添加到索引中 Document doc = new...

    LuceneUtils_lucenejava_全文检索_lucene_

    FSDirectory directory = FSDirectory.open(Paths.get("indexdir")); ``` 2. **配置Analyzer** Lucene对中文处理需要特殊的Analyzer,如`IKAnalyzer`或`SmartChineseAnalyzer`。这些Analyzer能对中文进行分词,...

    lucene核心资源包以及lucene的api

    - **Directory**: 存储索引的抽象接口,如FSDirectory用于在文件系统中存储,RAMDirectory则将索引存储在内存中。 - **Document**: 表示一个待索引的文档,可以包含多个Field(字段),每个Field都有特定的类型,...

    Lucene3总体图_建索引_查询_数据库索引[参考].pdf

    - Directory类:定义了索引文件的存储结构,提供了FSDirectory(磁盘存储)、RAMDirectory(内存存储)和MmapDirectory(内存映射)等不同类型的实现。 7. **Util**: - 公共工具类,包含时间转换、字符串处理等...

    Lucene.2.0.API

    5. **存储模块**:`Directory`接口和它的实现类(如`FSDirectory`、`RAMDirectory`)负责索引和文档数据的存储。`FSDirectory`使用文件系统,而`RAMDirectory`则在内存中存储,适用于测试环境。 6. **评分模块**:...

    Lucene索引的基本操作

    Directory directory = FSDirectory.open(indexLocation.toPath()); ``` ### 3. 分析器设置 分析器用于对输入的文本进行分词。Lucene提供了多种分析器,如`StandardAnalyzer`,适用于英文文本;对于中文,通常使用...

Global site tag (gtag.js) - Google Analytics