Lucene包解读之util,store

校内搜索的底层索引我是用它做的,为什么速度这么快腻,以前只是用它的查询接口,没有深入到核心去看它的索引文件结构,今天分析了以下它的源代码主要是store包和util包这两个与文件最为密切的包。

包org/apache/lucene/util包含一些数据结构如BitVector 和PriorityQueue,还有StringHelper类主要的用途是判断两个字符串是否相等。

抽象类PriorityQueue是一个优先队列的抽象类,用于后面实现各种具体的优先队列,提供常数时间内的最小元素访问能力,内部实现机制是哈希表和堆排序算法。

Constants主要定义了一些全局的常量。用System.getProperty("java.version"),System.getProperty("os.name")获得Java版本,系统的版本号。

 包org/apache/lucene/store里主要是一些对文件的操作类。其主要目的是抽象出和平台文件系统无关的存储抽象,提供诸如目录服务(增、删文件)、输入流和输出流。

主要的类的结构为:抽象类Directory类,InputStream类和OutputStream类。

其中FSDirectory,RAMDirectory继承了Directory抽象类,

FSInputStream,RAMInputStream继承了InputStream抽象类,

FSOutputStream,RAMOutputStream继承了OutputStream抽象类。

其中FS开头的是以实际的文件系统为基础的,以RAM开头的是内存中的虚拟文件系统,虚拟文件的类为:RAMFile,包含的内容为:

  Vector buffers = new Vector();

  long length;

  long lastModified = System.currentTimeMillis();

RAMFile中采用数组来表示文件的存储空间。在此的基础上,完成各项操作的实现,就形成了基于内存的虚拟文件系统。
下面具体分析这个内存的虚拟文件系统。
RAMDirectory类中:files信息存在一个Hashtable里

Hashtable files = new Hashtable();

创造文件的函数为

public final OutputStream createFile(String name)

{

    RAMFile file = new RAMFile();

    files.put(name, file);

    return new RAMOutputStream(file);

}

即将name 和RAMFile存到一个Hashtable中。

打开内存文件的方式为:

public final InputStream openFile(String name)

 {

    RAMFile file = (RAMFile)files.get(name);

    return new RAMInputStream(file);

  }

其实就是用一个Hashtable来在内存中形成一个文件系统。

再来看看RAMInputStream,继承了InputStream类的方法,并重写了readInternal和

seekInternal方法。

构造函数

public RAMInputStream(RAMFile f)

{

    file = f;

    length = file.length;

}很容易理解。

这里大量用到了抽象类InputStream的方法,先从Lucene自定义的数据类型看,

Lucene定义一个Buffer_Size的长度为1024,并定义一bufferPosition指向其在缓冲区的位置。以下是4种数据类型基本的。

数据类型一:Int表示读取4个字节的int类型。

在InputStream中:

public final int readInt() throws IOException {

    return ((readByte() & 0xFF) < < 24) | ((readByte() & 0xFF) << 16)

         | ((readByte() & 0xFF) <<  8) |  (readByte() & 0xFF);

  }

其中readByte()函数为:

public final byte readByte() throws IOException

{

    if (bufferPosition >= bufferLength)

      refill();

    return buffer[bufferPosition++];

  }

数据类型二:VInt, 可变长度的整数,最小一个字节,可以是2-4个字节,如果一个字节表示不了的话。不过通常是一个字节就够了。

以下是读取Vint的函数读取2个或3个或4个字节。

public final int readVInt() throws IOException {

    byte b = readByte();

    int i = b & 0x7F;

    for (int shift = 7; (b & 0x80) != 0; shift += 7) {

      b = readByte();

      i |= (b & 0x7F) < < shift;

    }

    return i;

  }

数据类型三:Vlong,可变长度的长整数,最小一个字节,可以是2-8个字节,如果一个字节表示不了的话。不过通常是一个字节就够了。

public final long readVLong() throws IOException {

    byte b = readByte();

    long i = b & 0x7F;

    for (int shift = 7; (b & 0x80) != 0; shift += 7) {

      b = readByte();

      i |= (b & 0x7FL) << shift;

    }

    return i;

  }

数据类型四:Long,读取8个字节的数据,

public final long readVLong() throws IOException {

    byte b = readByte();

    long i = b & 0x7F;

    for (int shift = 7; (b & 0x80) != 0; shift += 7) {

      b = readByte();

      i |= (b & 0x7FL) << shift;

    }

    return i;

  }

数据类型五:VString,java中的字符串是没有像C里面一样的’/0’的结束符的,所以在文件中记录一个字符串时,在字符串前放一个VInt表示字符串的长度。

private char[] chars;

public final String readString() throws IOException {

    int length = readVInt();

    if (chars == null || length > chars.length)

      chars = new char[length];

    readChars(chars, 0, length);

    return new String(chars, 0, length);

  }

ReadChars函数为

public final void readChars(char[] buffer, int start, int length)

       throws IOException {

    final int end = start + length;

    for (int i = start; i < end; i++) {

      byte b = readByte();

      if ((b & 0x80) == 0)

       buffer[i] = (char)(b & 0x7F);

      else if ((b & 0xE0) != 0xE0) {

       buffer[i] = (char)(((b & 0x1F) << 6)

               | (readByte() & 0x3F));

      } else

       buffer[i] = (char)(((b & 0x0F) << 12)

              | ((readByte() & 0x3F) << 6)

               |  (readByte() & 0x3F));

    }

  }

主要功能是读取一段长度的数据转换为String类型

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页