`
twh1224
  • 浏览: 95563 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

Lucene学习(13)

阅读更多
Directory抽象类比较常用的具体实现子类应该是FSDirectory类和RAMDirectory类。FSDirectory类是与文件系统的目录相关的,而RAMDirectory类是与内存相关的,即是指内存中的一个临时非永久的区域。

FSDirectory类源代码定义如下:

package org.apache.lucene.store;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Hashtable;

import org.apache.lucene.index.IndexFileNameFilter;

import org.apache.lucene.index.IndexWriter;

public class FSDirectory extends Directory {

	// DIRECTORIES需要进行同步,用于存放指定键值对<File,FSDirectory> 
	private static final Hashtable DIRECTORIES = new Hashtable();

	private static boolean disableLocks = false;

	/** 
	 * 设置锁文件是否可以使用 
	 * They should only be disabled if the index 
	 * is on a read-only medium like a CD-ROM. 
	 */
	public static void setDisableLocks(boolean doDisableLocks) {
		FSDirectory.disableLocks = doDisableLocks;
	}

	// 获取锁文件是否可以使用,返回true表示不可以使用 
	public static boolean getDisableLocks() {
		return FSDirectory.disableLocks;
	}

	// 锁目录,该属性已经废弃 
	public static final String LOCK_DIR = System.getProperty(
			"org.apache.lucene.lockDir", System.getProperty("java.io.tmpdir"));

	// 定义一个静态内部类,该类是基于文件系统的 
	private static Class IMPL;
	static {
		try {
			String name = System.getProperty(
					"org.apache.lucene.FSDirectory.class", FSDirectory.class
							.getName());
			IMPL = Class.forName(name);
		} catch (ClassNotFoundException e) {
			throw new RuntimeException("cannot load FSDirectory class: "
					+ e.toString(), e);
		} catch (SecurityException se) {
			try {
				IMPL = Class.forName(FSDirectory.class.getName());
			} catch (ClassNotFoundException e) {
				throw new RuntimeException(
						"cannot load default FSDirectory class: "
								+ e.toString(), e);
			}
		}
	}

	private static MessageDigest DIGESTER;

	static {
		try {
			DIGESTER = MessageDigest.getInstance("MD5");
		} catch (NoSuchAlgorithmException e) {
			throw new RuntimeException(e.toString(), e);
		}
	}

	/** A buffer optionally used in renameTo method */
	private byte[] buffer = null;

	// 静态方法,根据指定的路径path,返回该路径的一个FSDirectiry实例 
	public static FSDirectory getDirectory(String path) throws IOException {
		return getDirectory(new File(path), null);
	}

	// 静态方法,根据指定的路径path以及锁工厂LockFactory参数,返回该路径的一个FSDirectiry实例 
	public static FSDirectory getDirectory(String path, LockFactory lockFactory)
			throws IOException {
		return getDirectory(new File(path), lockFactory);
	}

	// 静态方法,根据指定的File对象,返回该路径的一个FSDirectiry实例 

	public static FSDirectory getDirectory(File file) throws IOException {
		return getDirectory(file, null);
	}

	// 静态方法,根据指定File对象以及锁工厂LockFactory参数,返回该路径的一个FSDirectiry实例 

	// 该方法是获取FSDirectiry实例的核心方法,其他重载的该方法都是经过转换,调用该方法实现的 
	public static FSDirectory getDirectory(File file, LockFactory lockFactory)
			throws IOException {
		file = new File(file.getCanonicalPath());

		if (file.exists() && !file.isDirectory()) // 如果file存在并且不是一个目录文件,抛出异常 
			throw new IOException(file + " not a directory");

		if (!file.exists()) // 如果file不存在 
			if (!file.mkdirs()) //   如果创建由file指定的路径名所指定的目录失败,则很可能已经存在,抛出异常 
				throw new IOException("Cannot create directory: " + file);

		FSDirectory dir;
		synchronized (DIRECTORIES) {
			dir = (FSDirectory) DIRECTORIES.get(file);
			if (dir == null) {
				try {
					dir = (FSDirectory) IMPL.newInstance(); // 调用静态内部类IMPL获取一个与文件系统目录有关的Directory类,并加载该类 
				} catch (Exception e) {
					throw new RuntimeException(
							"cannot load FSDirectory class: " + e.toString(), e); // 加载失败 
				}
				dir.init(file, lockFactory); // 根据指定的file和lockFactory,调用该类Directory的init方法,进行FSDirectory的初始化初始化工作 

				DIRECTORIES.put(file, dir);
			} else {
				// 如果该目录dir管理所用的锁工厂实例为空,或者不是同一个锁工厂实例,抛出异常 
				if (lockFactory != null && lockFactory != dir.getLockFactory()) {
					throw new IOException(
							"Directory was previously created with a different LockFactory instance; please pass null as the lockFactory instance and use setLockFactory to change it");
				}
			}
		}
		synchronized (dir) {
			dir.refCount++; //   用于记录该目录dir被引用的计数增加1 
		}
		return dir;
	}

	//   获取FSDirectory实例,该方法已经废弃 
	public static FSDirectory getDirectory(String path, boolean create)
			throws IOException {
		return getDirectory(new File(path), create);
	}

	//   获取FSDirectory实例,该方法已经废弃 
	public static FSDirectory getDirectory(File file, boolean create)
			throws IOException {
		FSDirectory dir = getDirectory(file, null);

		// This is now deprecated (creation should only be done 
		// by IndexWriter): 
		if (create) {
			dir.create();
		}

		return dir;
	}

	private void create() throws IOException {
		if (directory.exists()) { // File directory是FSDirectory类的一个成员 
			String[] files = directory.list(IndexFileNameFilter.getFilter()); // 获取经过IndexFileNameFilter过滤后的该目录文件directory下的文件列表 
			if (files == null) // 如果获取的文件列表为空 
				throw new IOException("cannot read directory "
						+ directory.getAbsolutePath()
						+ ": list() returned null");
			for (int i = 0; i < files.length; i++) { //   删除返回的文件列表中的文件 
				File file = new File(directory, files[i]);
				if (!file.delete())
					throw new IOException("Cannot delete " + file); // 删除异常 
			}
		}
		lockFactory.clearLock(IndexWriter.WRITE_LOCK_NAME); // 删除操作完成后,从锁工厂中清除锁,即释放锁 
	}

	private File directory = null; // File directory是FSDirectory类的一个成员 
	private int refCount; //   用于记录该目录dir被引用的计数增加1 

	protected FSDirectory() {
	}; // permit subclassing 

	private void init(File path, LockFactory lockFactory) throws IOException {

		// 根据指定的file和lockFactory,调用该类Directory的init方法,进行FSDirectory的初始化初始化工作 

		directory = path;

		boolean doClearLockID = false;

		if (lockFactory == null) { // 锁工厂实例为null 

			if (disableLocks) { // 如果锁不可以使用 
				lockFactory = NoLockFactory.getNoLockFactory(); // 调用NoLockFactory类,获取NoLockFactory实例,为当前的锁工厂实例。其实NoLockFactory是一个单态(singleton)模式的工厂类,应用中只能有一个锁实例,不需要进行同步 
			} else { // 如果锁可以使用,获取锁工厂类名称的字符串描述 
				String lockClassName = System
						.getProperty("org.apache.lucene.store.FSDirectoryLockFactoryClass");

				if (lockClassName != null && !lockClassName.equals("")) { // 如果获取的锁工厂类名称的字符串描述不为null,而且者不为空 
					Class c;

					try {
						c = Class.forName(lockClassName); // 加载该锁工厂类 
					} catch (ClassNotFoundException e) {
						throw new IOException("unable to find LockClass "
								+ lockClassName);
					}

					try {
						lockFactory = (LockFactory) c.newInstance(); //   获取一个锁工厂的实例         
					} catch (IllegalAccessException e) {
						throw new IOException(
								"IllegalAccessException when instantiating LockClass "
										+ lockClassName);
					} catch (InstantiationException e) {
						throw new IOException(
								"InstantiationException when instantiating LockClass "
										+ lockClassName);
					} catch (ClassCastException e) {
						throw new IOException("unable to cast LockClass "
								+ lockClassName + " instance to a LockFactory");
					}

					// 根据获取的锁工厂实例的类型来设置对文件File path加锁的方式 

					if (lockFactory instanceof NativeFSLockFactory) {
						((NativeFSLockFactory) lockFactory).setLockDir(path);
					} else if (lockFactory instanceof SimpleFSLockFactory) {
						((SimpleFSLockFactory) lockFactory).setLockDir(path);
					}
				} else {
					// 没有其他的锁工厂类可用,则使用默认的锁工厂类创建一个锁工厂实例 
					lockFactory = new SimpleFSLockFactory(path);
					doClearLockID = true;
				}
			}
		}

		setLockFactory(lockFactory); // 设置当前FSDirectory相关锁工厂实例 

		if (doClearLockID) {
			// Clear the prefix because write.lock will be 
			// stored in our directory: 
			lockFactory.setLockPrefix(null);
		}
	}

	// 返回目录文件File directory下的所有索引文件,索引文件使用文件名的字符串描述 
	public String[] list() {
		return directory.list(IndexFileNameFilter.getFilter());
	}

	// 如果文件name存在,则返回true 
	public boolean fileExists(String name) {
		File file = new File(directory, name); // 根据File directory指定的抽象路径,以及name指定的名称创建一个文件 
		return file.exists();
	}

	// 获取文件name最后修改的时间 
	public long fileModified(String name) {
		File file = new File(directory, name);
		return file.lastModified();
	}

	// 返回目录文件directory下名称为name的文件最后修改的时间 
	public static long fileModified(File directory, String name) {
		File file = new File(directory, name);
		return file.lastModified();
	}

	// 设置文件name当前修改的时间 
	public void touchFile(String name) {
		File file = new File(directory, name);
		file.setLastModified(System.currentTimeMillis());
	}

	// 获取文件name的长度 
	public long fileLength(String name) {
		File file = new File(directory, name);
		return file.length();
	}

	// 删除目录文件directory下的name文件 
	public void deleteFile(String name) throws IOException {
		File file = new File(directory, name);
		if (!file.delete())
			throw new IOException("Cannot delete " + file);
	}

	// 重新命名文件,该方法已经废弃 
	public synchronized void renameFile(String from, String to)
			throws IOException {
		File old = new File(directory, from);
		File nu = new File(directory, to);

		if (nu.exists())
			if (!nu.delete())
				throw new IOException("Cannot delete " + nu);
		if (!old.renameTo(nu)) {
			java.io.InputStream in = null;
			java.io.OutputStream out = null;
			try {
				in = new FileInputStream(old);
				out = new FileOutputStream(nu);
				if (buffer == null) {
					buffer = new byte[1024];
				}
				int len;
				while ((len = in.read(buffer)) >= 0) {
					out.write(buffer, 0, len);
				}

				old.delete();
			} catch (IOException ioe) {
				IOException newExc = new IOException("Cannot rename " + old
						+ " to " + nu);
				newExc.initCause(ioe);
				throw newExc;
			} finally {
				try {
					if (in != null) {
						try {
							in.close();
						} catch (IOException e) {
							throw new RuntimeException(
									"Cannot close input stream: "
											+ e.toString(), e);
						}
					}
				} finally {
					if (out != null) {
						try {
							out.close();
						} catch (IOException e) {
							throw new RuntimeException(
									"Cannot close output stream: "
											+ e.toString(), e);
						}
					}
				}
			}
		}
	}

	// 创建一个名称为name的文件,返回一个输出流,以便对该文件进行写入操作 
	public IndexOutput createOutput(String name) throws IOException {

		File file = new File(directory, name);
		if (file.exists() && !file.delete()) // 如果name指定文件存在,或者没有被删除掉,抛出异常 
			throw new IOException("Cannot overwrite: " + file);

		return new FSIndexOutput(file); // 返回文件File file的一个输出流 
	}

	// 读取名称为name的文件,返回一个输出流,以便定义对读取出来的内容进行操作 
	public IndexInput openInput(String name) throws IOException {
		return new FSIndexInput(new File(directory, name));
	}

	// 打开指定名称为name的文件,指定大小为缓冲区大小bufferSize,返回一个输入流 
	public IndexInput openInput(String name, int bufferSize) throws IOException {
		return new FSIndexInput(new File(directory, name), bufferSize);
	}

	// 一个字符缓冲区,将字节转换为十六进制 
	private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5',
			'6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };

	// 获取锁的标识ID 
	public String getLockID() {
		String dirName;
		try {
			dirName = directory.getCanonicalPath();
		} catch (IOException e) {
			throw new RuntimeException(e.toString(), e);
		}

		byte digest[];
		synchronized (DIGESTER) {
			digest = DIGESTER.digest(dirName.getBytes());
		}
		StringBuffer buf = new StringBuffer();
		buf.append("lucene-");
		for (int i = 0; i < digest.length; i++) {
			int b = digest[i];
			buf.append(HEX_DIGITS[(b >> 4) & 0xf]);
			buf.append(HEX_DIGITS[b & 0xf]);
		}

		return buf.toString();
	}

	// 关闭目录 
	public synchronized void close() {
		if (--refCount <= 0) {
			synchronized (DIRECTORIES) {
				DIRECTORIES.remove(directory);
			}
		}
	}

	public File getFile() {
		return directory;
	}

	/** For debug output. */
	public String toString() {
		return this.getClass().getName() + "@" + directory;
	}

	// FSIndexInput是一个静态内部类,用于管理文件系统中的索引文件输入流 

	protected static class FSIndexInput extends BufferedIndexInput {

		private static class Descriptor extends RandomAccessFile {
			// 用于记录文件打开状态的boolean型变量isOpen 
			private boolean isOpen;
			long position;
			final long length;

			public Descriptor(File file, String mode) throws IOException {
				super(file, mode);
				isOpen = true;
				length = length();
			}

			public void close() throws IOException {
				if (isOpen) {
					isOpen = false;
					super.close();
				}
			}

			protected void finalize() throws Throwable {
				try {
					close();
				} finally {
					super.finalize();
				}
			}
		}

		private final Descriptor file;
		boolean isClone;

		public FSIndexInput(File path) throws IOException {
			this(path, BufferedIndexInput.BUFFER_SIZE);
		}

		public FSIndexInput(File path, int bufferSize) throws IOException {
			super(bufferSize);
			file = new Descriptor(path, "r");
		}

		// 比较底层的读取操作,主要是对字节操作 
		protected void readInternal(byte[] b, int offset, int len)
				throws IOException {
			synchronized (file) {
				long position = getFilePointer();
				if (position != file.position) {
					file.seek(position);
					file.position = position;
				}
				int total = 0;
				do {
					int i = file.read(b, offset + total, len - total);
					if (i == -1)
						throw new IOException("read past EOF");
					file.position += i;
					total += i;
				} while (total < len);
			}
		}

		public void close() throws IOException {
			if (!isClone)
				file.close();
		}

		protected void seekInternal(long position) {
		}

		public long length() {
			return file.length;
		}

		public Object clone() {
			FSIndexInput clone = (FSIndexInput) super.clone();
			clone.isClone = true;
			return clone;
		}

		/** Method used for testing. Returns true if the underlying 
		 * file descriptor is valid. 
		 */
		boolean isFDValid() throws IOException {
			return file.getFD().valid();
		}
	}

	// FSIndexOutput是一个静态内部类,用于管理文件系统中的索引文件输出流,与FSIndexInput实现类似 

	protected static class FSIndexOutput extends BufferedIndexOutput {
		RandomAccessFile file = null;

		// 用于记录文件打开状态的boolean型变量isOpen    
		private boolean isOpen;

		public FSIndexOutput(File path) throws IOException {
			file = new RandomAccessFile(path, "rw");
			isOpen = true;
		}

		// 从缓冲区写入文件的方法 
		public void flushBuffer(byte[] b, int offset, int size)
				throws IOException {
			file.write(b, offset, size);
		}

		public void close() throws IOException {
			if (isOpen) {
				super.close();
				file.close();
				isOpen = false;
			}
		}

		// 随机访问的方法实现 
		public void seek(long pos) throws IOException {
			super.seek(pos);
			file.seek(pos);
		}

		public long length() throws IOException {
			return file.length();
		}

	}
}


上面FSDirectory类的实现挺复杂的,主要是在继承Directory抽象类的基础上,增加了文件系统目录锁特有的一些操作方式。

通过FSDirectory类源代码的阅读,关于文件系统目录FSDirectory类,总结几点:

1、锁工厂的获取及其管理;

2、对文件系统目录下索引文件的输入流和输出流的管理;

3、获取FSDirectory类实例;

4、获取锁工厂实例后,可以创建一个新的FSDirectory类实例,在此之前先要完成一些初始化工作;

5、继承自Directory抽象类,自然可以实现索引文件的的拷贝操作。

6、FSDirectory类中实现了很多静态内部类,这使得只能在FSDirectory类内部访问这些静态类,对外部透明。
分享到:
评论

相关推荐

    lucene3.0.3搜索的使用示例

    这个"lucene3.0.3搜索的使用示例"压缩包文件很可能是为了帮助用户理解并学习如何在项目中应用Lucene 3.0.3版本的功能。 在Lucene 3.0.3中,主要包含了以下核心概念和知识点: 1. **索引(Indexing)**:这是Lucene...

    【分享:lucene学习资料】---<下载不扣分,回帖加1分,欢迎下载,童叟无欺>

    1&gt; lucene学习笔记 2&gt; 全文检索的实现机制 【1】lucene学习笔记的目录如下 1. 概述 3 2. lucene 的包结构 3 3. 索引文件格式 3 4. lucene中主要的类 4 4.1. Document文档类 4 4.1.1. 常用方法 4 4.1.2. 示例 4 4.2...

    开发自己的搜索引擎lucene+heritrix(第2版)(ch13-ch15源码)

    综上所述,"开发自己的搜索引擎lucene+heritrix(第2版)"的源码涵盖了从网络数据抓取到全文检索的全过程,适合开发者深入学习和实践搜索引擎技术。通过研究ch13至ch16的源代码,可以更深入地理解这两个工具的交互和...

    搜索引擎Lucene+Heritrix(第二版)4

    7. **学习资源与社区**:除了书中的内容,学习Lucene和Heritrix还可以参考Apache官方文档、Stack Overflow上的讨论、GitHub上的开源项目以及各种技术论坛。开发者社区提供了丰富的示例代码、教程和问答资源,有助于...

    Lucene搜索引擎开发权威经典

    5. **第13章:桌面搜索引擎开发实例** - 这一章提供了一个实际的桌面搜索引擎的开发案例,通过实例教读者如何将Lucene应用到桌面搜索环境中,如何索引本地文件系统,并实现快速的文件搜索。 6. **第14章:Web搜索...

    Lucene搜索引擎开发权威经典11-14.rar

    第13章“桌面搜索引擎开发实例”提供了具体的实践案例,让读者了解如何将Lucene应用于桌面环境,其中可能涉及: 1. 文件系统的索引构建:如何遍历文件系统,提取文本内容并建立索引。 2. 实时索引更新:当文件系统...

    杨中科.net13季

    《杨中科.net13季》是一系列...通过《杨中科.net13季》的学习,学员不仅能够全面理解.NET技术体系,还能掌握实际项目开发中的最佳实践。无论是初学者还是经验丰富的开发者,都能从中受益,不断提升自己的.NET技术能力。

    杨中科老师的全13季 .NET视频教程(C#),绝对经典

    杨中科老师的全13季 .NET视频教程(C#)是一个深入学习.NET技术的宝贵资源,涵盖了从基础到高级的广泛主题。 C#,作为.NET框架的主要编程语言,由微软设计,旨在提高软件开发的生产力,同时保持类型安全性和面向对象...

    java的28个学习目标

    了解并掌握常用的外部API和框架,如Log4J(日志)、Quartz(调度)、JGroups(网络组通信)、JCache(分布式缓存)、Lucene(全文检索)等。 ### 19. 跨平台与本地接口 学习跨平台开发技巧,掌握JNI(Java Native ...

    若干vc代码1352.rar

    2012-06-13 13:38 9,178,682 Lucene 3.0 原理与代码分析完整版.pdf 2012-06-13 13:46 10,582,426 姚晨屏保(宽屏).exe 2012-06-13 13:10 23,625,694 Visual.C.系统开发实例精粹(源代码).7z 2012-06-13 13:46 25,062,...

    ES学习资料干干干干刚馕

    它基于Lucene库构建,提供了一个分布式、RESTful风格的搜索和分析引擎,能够处理海量数据并快速响应查询。 描述中的重复词汇“干干干干刚馕”可能是个玩笑或者误输入,没有提供具体的信息,但我们可以根据常见的ES...

    java培训学习大纲页.pdf

    7. **搜索引擎和工作流**:Lucene用于全文搜索,HTMLParser和Heritrix则涉及网页抓取,JBPM则是工作流程管理工具,学员将学习如何集成这些工具来提升应用功能。 8. **XML处理**:XML作为数据交换格式,学员将学习其...

    ElasticSearch中文学习教程

    当时,GitHub拥有庞大的数据量,包括13亿个文件和1300亿行代码,这些数据都需要被高效地索引和检索。GitHub使用ElasticSearch后,其搜索性能显著提升,目前的集群规模包括26个索引存储节点和8个客户端节点(负责处理...

    Java学习的30个目标

    #### 13. XML与相关API 掌握XML处理API,如JAXP、JDOM、DOM4J、JAXB、JAXM等,实现XML数据的解析和操作。 #### 14. Web服务技术 学习SOAP、REST等Web服务技术,包括JAX-RPC、SAAJ、JAX-WS等API的使用,实现跨平台的...

    JackRabbit 学习参考资料总汇

    13. 在学习资料的开头提到的运行程序需设置JVM参数,如-Djava.security.auth.login.config==jaas.config,表明了程序在运行时可能涉及到Java安全认证和授权服务(JAAS)。 学习JackRabbit对于理解内容管理系统、...

    学习java的30个目标.txt

    #### 目标13:掌握XML处理API - **API选择**:JAXP、JDOM、DOM4J、JAXR等。 - **应用案例**:XML文档解析、转换及验证。 #### 目标14:学习Web服务API - **技术要点**:JAX-RPC、SAAJ、JAXB、JAXM、JAXR、JWSDP等...

    学习Java语言的30个参考,让你坐拥别人之上的30个擦考

    - **Lucene**:学习全文检索技术的基础知识。 ### 21. 本地接口与连接器 - **JNI、JCA**:掌握Java Native Interface、Java Connector Architecture等技术,实现Java与其他语言或平台的交互。 通过以上知识点的...

    java学习目标

    #### 13. 面向切面编程与工具 熟悉面向切面编程(AOP)及其工具如AspectJ、AspectWerkz,可以帮助你更优雅地处理横切关注点。 #### 14. 日志记录与调度 了解不同日志框架如Log4J,以及任务调度工具如Quartz,可以...

Global site tag (gtag.js) - Google Analytics