用lucene做一个站内搜索引擎(一):用ictclas4j做Lucene系统的分词器:(1)提高词典加载速度.

这一系列的文章不是系统的介绍Lucene的, 只是在若干个点对Lucene的使用进行说明.需要系统的了解可以看
1) <<Lucene in Action>>
2) 车东写的Lucene教程
3) TJU某人写的如何加入分词
4) 3) 的相关代码

 关于lucene用作站内搜索引擎的方案可以参见上面三个网站, 虽然它们是针对lucene2.3前的某些版本的,  代码中的接口函数可能跟lucene2.3有所不同(比如Field类), 但对lucene的介绍及一些代码会给你很大的帮助.

汉语的搜索离不开分词, 本想用ictclas+jni来做,结果找不到ictclas的源码, 在计算所也无从下载, 不过就在无助之时,看到有个ictclas4j, 用visio写的文档不错(算法框加应该是没问题的), 代码写得也很清楚(只是后来发现代码中的bug真是不少), 下来一试, 效果还不错, 词典那些以后都可以扩充.

这篇文章只讲对 ictclas4j词典加载的改进,改后的加载速度是改前的五倍.

首先, 为什么词典加载慢, 读了源码后就会发现: 在读取词典文件的时候都是若干字节读取的, 这样浪费了IO的带宽,增加了IO的次数, 所以速度慢, 解决方法就是加Buffer, 以前没用过Java的读写文件buffer之类的功能,google了一下,发现JDK中就有现成的类: BufferedInputStream.下面是在Dictionary.java中增加的函数和在Dictionary.java中修改的函数
/**
 * 修改的函数
 
*/

 
public   boolean  load(String filename)  {
  
// return load(filename, false);
  return quickLoad(filename, false);
 }


/**
 * 新增的函数: 加速加载
 
*/

 
public   boolean  quickLoad(String filename,  boolean  isReset)  {
  File file;

  
int[] nBuffer = new int[3];

  file 
= new File(filename);
  
if (!file.canRead())
   
return false;// fail while opening the file

  
try {
   delModified();

   DataInputStream fis 
= new DataInputStream(new FileInputStream(file));
// 在写入文件之前加入一个buffer,大小为8192(=32*256)
   BufferedInputStream in = new BufferedInputStream(fis); 
   
for (int i = 0; i < Utility.CC_NUM; i++{
    
// logger.debug("块" + i);
    
// 词典库在写二进制数据时采用低位优先(小头在前)方式,需要转换一下
    int count = GFCommon.bytes2int(Utility.readBytes(in, 4), false);
    
// logger.debug(" count:" + count);
    wts.get(i).setCount(count);
    
if (count <= 0)
     
continue;

    WordItem[] wis 
= new WordItem[count];
    
for (int j = 0; j < count; j++{
     nBuffer[
0= GFCommon.bytes2int(Utility.readBytes(in, 4), false);
     nBuffer[
1= GFCommon.bytes2int(Utility.readBytes(in, 4), false);
     nBuffer[
2= GFCommon.bytes2int(Utility.readBytes(in, 4), false);

     
// String print = " wordLen:" + nBuffer[1] + " frequency:" +
     
// nBuffer[0] + " handle:" + nBuffer[2];

     WordItem ti 
= new WordItem();
     
if (nBuffer[1> 0)// String length is more than 0
     {
      
byte[] word = Utility.readBytes(in, nBuffer[1]);
      ti.setWord(
new String(word, "GBK"));

     }
 else
      ti.setWord(
"");

     
// print += " word:(" + Utility.getGB(i) + ")" +
     
// ti.getWord();
     
// logger.debug(print);

     
if (isReset)// Reset the frequency
      ti.setFreq(0);
     
else
      ti.setFreq(nBuffer[
0]);
     ti.setLen(nBuffer[
1/ 2);
     ti.setHandle(nBuffer[
2]);
     wis[j] 
= ti;
    }

    wts.get(i).setWords(wis);
   }


   in.close();
  }
 catch (FileNotFoundException e) {
   logger.error(e);
  }
 catch (IOException e) {
   logger.error(e);
  }

  
return true;  
 }

 

在Utility.java中加入以下函数:
  public   static   byte [] readBytes(BufferedInputStream in,  int  len)  {
  
if (in != null && len > 0{
   
byte[] b = new byte[len];
   
try {
    in.read(b, 
0, len);
   }
 catch (IOException e) {
    e.printStackTrace();
   }

   
return b;
  }

  
return null;
 }
 

就是这么简单, 另外 " 低位优先 "的方式, 应该可以变成高位优先, 这个我并没有修改.

这里讲加载词典, 之后会词做成的分词器出现的问题及解决方法.

你可能感兴趣的:(搜索引擎,File,Lucene,buffer,byte,visio)