开春大礼《华为云技术精选集》大厂100+前沿技术实战分享!>>>
本文主要叙述如何通过引入Commons-VFS项目来扩展Lucene的索引文件存储方式。在阅读本 文之前,您必须对Lucene有一定的了解,最好是有编写过Lucene代码。另外文章中所提到的Lucene如果不做特殊说明指的是Lucene的Java版本。
使用过Lucene来做为搜索引擎的朋友知道,Lucene默认的使用文件系统来存储索引 文件。一般我们需要指定一个路径做为参数来初始化索引的读写类。例如下面语句准备在D盘的lucene_idx目录下写索引信息。
IndexWriter idx_writer = new IndexWriter(“D:/lucene_idx”,new StandardAnalyzer(),false); |
因此整个系统的索引一般就会集中在某台服务 器的某个目录。为了保证写索引不会产生冲突,经常我们只运行一个负责写索引的进程,其他的应用可以访问索引目录进行查询。当应用程序是集群环境下的不同机 器时,其他的机器如何访问到索引服务器上的索引数据目录呢?你肯定已经想到很多种方法来访问其他机器的目录:例如Windows机器可以通过网上邻居;Linux服务器之间可以通过NFS访问;或者Linux和Windows服务器之间可以通过SAMBA来相互访问各自的文件系统。还有 没有其他更加灵活的解决方案吗?
当然有,通过扩展Lucene的索引存储接口,你可以通过FTP、HTTP来读写索引文件,你甚至可以将Lucene的索引数据保存在数据库中,虽 然我不知道这到底是不是一个好主意,但起码技术上是可行的。
为了使我们对Lucene的扩展有着实际的意义,我们将引 入另外一个Apache组织新的开源项目—— Commons-VFS,我们简称为VFS。VFS项目把对各种各样的文件系统的访问封装成统一的应用程序接口,这大大的简化了应用程序本身代码的复杂 度。目前VFS支 持下面一些文件系统,而这个列表会越来越多,当然你也可以自行进行扩展。
FTP
Local Files
HTTP and HTTPS
SFTP
Temporary Files
Zip, Jar and Tar (uncompressed, tgz or tbz2)
gzip and bzip2
res
ram
或许你已经猜出来了引入VFS项目的目的:我们要利用VFS 项目和Lucene结合,使Lucene的索引文件可以存放在VFS所支持的各种可读写的文件系统中。
因此接下来我们的任务就是让Lucene使用VFS来存取索引数据,至于这些数据放在哪 里,是放在数据库、文件系统还是其他地方,这个问题就交给VFS的配置去处理了。
你准备好了嘛?下面我们要深入到Lucene的代码中去探个究竟了。首先我 们注意到了IndexReader、IndexWriter、IndexSearcher等这几个索引数据的读写类的构造函数都可以接受名为org.apache.lucene.store.Directory 的类做为参数。再查看api文档发现Directory有两个子类分别是:FSDirectory和RAMDirectory,从类名上可以猜出FSDirectory是基于文件系统的,而RAMDirectory是基于内存的。再读一下IndexWriter类的源码后证实了这个猜想,当我们传递路径字符串而不是Directory对象给IndexXxxxx类时,Lucene会初始化一个FSDirectory对象来处理索引数据 的读写操作。
而另外一个RAMDirectory类是基于内存的索引 数据存取,它是Lucene所提供的第二种索引数据存取方式。它可以接受一个FSDirectory做为构造函数的参数,相当于把存放在磁盘中的索引数据全部加载到内存中,以提高索引搜索的性能,我 们暂不理会这种方式。但我们已经了解到org.apache.lucene.store包中的类便是Lucene存储的核心,我们可以通过扩展Directory类来实现存储自定义。姑且把所要扩展的这个类命名为VFSDirectory。
先来看看Directory都有什么方法:
abstract void |
close() 关闭存储. |
abstract IndexOutput |
createOutput(String name) 使用给定的名字创建一个新的空文件. |
abstract void |
deleteFile(String name) 删除指定名字的文件. |
abstract boolean |
fileExists(String name) 判断文件是否存 在. |
abstract long |
fileLength(String name) 获取文件长度. |
abstract long |
fileModified(String name) 返回文件最近修改的时间. |
abstract String[] |
list() 列出所有的文件. |
abstract Lock |
|
abstract IndexInput |
|
abstract void |
renameFile(String from, String to) 文件重命名. |
abstract void |
上面这些都是跟文件操作密切相关的方法,应 该也是大家天天要打交道的文件操作方法。为了不至于误解这些方法的意思,我们不妨看看FSDirectory的源码。以下VFSDirectory类的完整代码,该类已经在实际的应用中测试无误。此类的构造函数接受两个uri做为参数,分别是存放索引文件的URI以及锁文件的URI,关于URI的格式请参考VFS项目的文档。性能方面由于采用了跟FSDirectory一致的BufferedIndexInput和BufferedIndexOuput,因 此二者并没有太大区别。
package dlog.common.search; import java.io.IOException; import org.apache.commons.io.IOUtils; /**
public VFSDirectory(String repository_uri, String lock_uri) throws IOException { @Override protected void finalize() throws IOException { @Override @Override
@Override @Override @Override @Override @Override for(int i=0;i @Override final StringBuffer buf = getLockPrefix();
try{ final FileObject lockFile = this.fileManager.resolveFile(locker, buf.toString()); return new Lock() { public void release() { public boolean isLocked() { public String toString() {
private static MessageDigest DIGESTER; /** static { private StringBuffer getLockPrefix() { String dirName; // name to be hashed try { byte digest[]; synchronized (DIGESTER) { StringBuffer buf = new StringBuffer();
@Override
@Override
private void close(FileObject file){
private static class VFSIndexInput extends BufferedIndexInput { private long length; public VFSIndexInput(FileObject file) throws IOException { @Override @Override @Override @Override private static class VFSIndexOutput throws BufferedIndexOutput { private RandomAccessContent content; public VFSIndexOutput(FileObject file) throws IOException{ @Override @Override @Override @Override protected void finalize() throws IOException { |
有了VFSDirectory这个类后,使用就非 常方便了。我们只需要构造一个VFSDirectory对象,并传递给IndexReader、IndexWriter、IndexSearcher等即可。为了方便各位读者进行测试,本文中的所有代码请看参考资料中的源码下载。
完成了VFSDirectory后,就相当于给Lucene注入更多的功力。任何VFSDirectory所支持的可读写文 件系统都可以被Lucene用来存放索引数据。如果是VFS本身不支持的文件系统我们也可以通过扩展VFS来实现对Lucene的扩展。
最后补充一点关于本文所涉及的源码的使用说 明,编译源码需要lucene以及vfs包的支持,编译成功后直接运行TestLuceneVFS类即可进行测试。
参考资料:
(Lucene 2.0)源码下载地址:/uploads/files/lucene_and_vfs.zip
(Lucene 2.1)源码下载地址:/uploads/files/lucene_2_1_and_vfs.jar
Lucene官方网站:http://lucene.apache.org
Commons-VFS项目网站:http://jakarta.apache.org/commons/vfs
08年的呀呀呀,我今天才看到。正在研究Apache VFS的API用法。
红薯老师真棒。