基于ICTCLAS分词器实现自己的Lucene Analyzer

      首先要说明了是,本文采用的ICTCLAS分词器为:2011版本的windows 32位JNI,Lucene版本为3.6.1.

   众所周知的是做中文信息处理时,Lucene自带的分词器往往是不被我们所采用的,这时候,我们就需要实现自己的分词器。而现在中文处理采用最多的分词器就是ICTCLAS了。本着没必要重复造轮子的原则,当然分词器这个轮子也没那么容易造,我用ICTCLAS实现了Lucene的analyzer。这个分词器的大部分代码是看视频的Demo 直接copy过来的,并不是我自己写的。(这里对Lucene大牛觉先表示感谢)我实现的功能就是:

一、在分词的同时过滤停用词。

二、可以得到每个词的词性。

    用Lucene实现自己的分词器只需要extends Analyzer类就可以了。代码如下:

 

  
  
  
  
  1. package com.xh.analyzer; 
  2.  
  3. import java.io.IOException; 
  4. import java.io.Reader; 
  5. import java.io.UnsupportedEncodingException; 
  6. import java.util.ArrayList; 
  7. import java.util.List; 
  8.  
  9. import org.apache.lucene.analysis.Analyzer; 
  10. import org.apache.lucene.analysis.TokenStream; 
  11. import org.apache.lucene.analysis.Tokenizer; 
  12.  
  13. import ICTCLAS.I3S.AC.ICTCLAS50; 
  14.  
  15. public class ICTCLASAnalyzer extends Analyzer { 
  16.   private ICTCLAS50 icta; 
  17.   private volatile boolean initialized = false
  18.   public ICTCLASAnalyzer() throws UnsupportedEncodingException { 
  19.     icta = new ICTCLAS50(); 
  20.     String initPath="."
  21.     // 初始化 
  22.     if (icta.ICTCLAS_Init(initPath.getBytes("GB2312")) == false) { 
  23.       System.out.println("Init Fail!"); 
  24.       return
  25.     } 
  26.  
  27.     // 设置词性标注集(0 计算所二级标注集,1 计算所一级标注集,2 北大二级标注集,3 北大一级标注集) 
  28.     icta.ICTCLAS_SetPOSmap(2); 
  29.  
  30.     // 导入用户字典 
  31.     int nCount = 0
  32.     String usrdir = "userdict.txt"// 用户字典路径 
  33.     byte[] usrdirb = usrdir.getBytes();// 将string转化为byte类型 
  34.     // 导入用户字典,返回导入用户词语个数第一个参数为用户字典路径,第二个参数为用户字典的编码类型 
  35.     nCount = icta.ICTCLAS_ImportUserDictFile(usrdirb, 0); 
  36.     //System.out.println("导入用户词个数" + nCount); 
  37.     initialized = true
  38.   } 
  39.  
  40.   public List<String> tokenizeReader(Reader reader) { 
  41.     List<String> result = new ArrayList<String>(1000); 
  42.     try { 
  43.       StringBuffer contentbuffer = new StringBuffer(); 
  44.       char[] temp = new char[1024]; 
  45.       int size = 0
  46.       while ((size = reader.read(temp, 01024)) != -1) { 
  47.         String tempstr = new String(temp, 0, size); 
  48.         contentbuffer.append(tempstr); 
  49.       } 
  50.       byte nativeBytes[] = icta.ICTCLAS_ParagraphProcess(contentbuffer.toString().getBytes("GB2312"), 21); 
  51.       String nativeStr = new String(nativeBytes, 0, nativeBytes.length, "GB2312"); 
  52.       System.out.println("分词结果: " + nativeStr); 
  53.         //进行词用词过滤 
  54.      String[] terms=nativeStr.split("\\s+"); 
  55.      int pos; 
  56.      String term,type; 
  57.      for (String string : terms) { 
  58.          pos=string.lastIndexOf('/'); 
  59.          if(pos==-1)continue
  60.          term=string.substring(0,pos); 
  61.          type=string.substring(pos+1, string.length()); 
  62.          if(accept(term,type)){ 
  63.              result.add(string); 
  64.          } 
  65.      } 
  66.     } catch (Throwable e) { 
  67.       e.printStackTrace(); 
  68.     } 
  69.     return result; 
  70.   } 
  71.   private boolean accept(String term,String type){ 
  72.       boolean accept=false
  73.     //对词的要求 
  74. //    if(term.length()>1){ 
  75. //        accept=true; 
  76. //    } 
  77. //    if(!accept)return accept; 
  78.       //对词性的要求 
  79.       if(type.startsWith("n")   //名词 
  80.             ||type.startsWith("t")  //时间词 
  81.             ||type.startsWith("s")  //处所词 
  82.             ||type.startsWith("f")  //方位词 
  83.             ||type.startsWith("a")  //形容词 
  84.             ||type.startsWith("v")  //动词 
  85.             ||type.startsWith("b")  //区别词 
  86.             ||type.startsWith("z")  //状态词 
  87. //          ||type.startsWith("r")  //代词 
  88. //          ||type.startsWith("m")  //数词 
  89.             ||type.startsWith("q")  //量词 
  90. //          ||type.startsWith("d")  //副词 
  91.             ||type.startsWith("p")  //介词 
  92.             ||type.startsWith("c")  //连词 
  93. //          ||type.startsWith("u")  //助词 
  94. //          ||type.startsWith("e")  //叹词 
  95. //          ||type.startsWith("y")  //语气词 
  96.             ||type.startsWith("o")  //拟声词 
  97.             ||type.startsWith("h")  //前缀 
  98.             ||type.startsWith("k")  //后缀 
  99.             ||type.startsWith("x")  //网址URL 
  100. //          ||type.startsWith("w")  //标点符号 
  101.                 ){ 
  102.           return true
  103.       } 
  104.        
  105.       return accept; 
  106.   } 
  107.   @Override 
  108.   public TokenStream tokenStream(String fieldName, Reader reader) { 
  109.     if(!initialized) 
  110.       return null
  111.     List<String> tokens = tokenizeReader(reader); 
  112.     return new ICTCLASTokenizer(tokens); 
  113.   } 
  114.  
  115.   @Override 
  116.   public TokenStream reusableTokenStream(String fieldName, Reader reader) throws IOException { 
  117.     Tokenizer tokenizer = (Tokenizer) getPreviousTokenStream(); 
  118.     if (tokenizer == null) { 
  119.       List<String> tokens = tokenizeReader(reader); 
  120.       tokenizer = new ICTCLASTokenizer(tokens); 
  121.       setPreviousTokenStream(tokenizer); 
  122.     } else
  123.       tokenizer.reset(reader); 
  124.       ICTCLASTokenizer t = (ICTCLASTokenizer)tokenizer; 
  125.       List<String> tokens = tokenizeReader(reader); 
  126.       t.reset(tokens); 
  127.     } 
  128.     return tokenizer; 
  129.   } 
  130.    
  131.   @Override 
  132.   public void close() { 
  133.     icta.ICTCLAS_SaveTheUsrDic(); 
  134.     icta.ICTCLAS_Exit(); 
  135.     initialized = false
  136.   } 

同时我们还需要自己写Tokenizer,方法也很简单,extends Lucene的Tokenizer就OK了。

 

  
  
  
  
  1. package com.xh.analyzer; 
  2.  
  3. import java.io.IOException; 
  4. import java.io.Reader; 
  5. import java.util.Iterator; 
  6. import java.util.List; 
  7.  
  8. import org.apache.lucene.analysis.Tokenizer; 
  9. import org.apache.lucene.analysis.tokenattributes.CharTermAttribute; 
  10. import org.apache.lucene.analysis.tokenattributes.TypeAttribute; 
  11.  
  12. public class ICTCLASTokenizer extends Tokenizer { 
  13.   private List<String> tokens; 
  14.   private Iterator<String> tokenIter; 
  15.   private CharTermAttribute termAtt; 
  16.   private TypeAttribute typeAtt; 
  17.   public ICTCLASTokenizer(List<String> tokens) { 
  18.     this.tokens = tokens; 
  19.     this.tokenIter = tokens.iterator(); 
  20.     termAtt = addAttribute( CharTermAttribute.class); 
  21.     typeAtt=addAttribute(TypeAttribute.class); 
  22.   } 
  23.   @Override 
  24.   public boolean incrementToken() throws IOException { 
  25.     clearAttributes(); 
  26.     if(tokenIter.hasNext()){ 
  27.       String tokenstring = tokenIter.next(); 
  28.       int pos=tokenstring.lastIndexOf('/'); 
  29.       typeAtt.setType(tokenstring.substring(pos,tokenstring.length())); 
  30.       termAtt.append(tokenstring.substring(0, pos)); 
  31.       termAtt.setLength(pos); 
  32.       return true
  33.     } 
  34.     return false
  35.   } 
  36.  
  37.   @Override 
  38.   public void reset() throws IOException { 
  39.     tokenIter = tokens.iterator(); 
  40.   } 
  41.    
  42.   @Override 
  43.   public void reset(Reader input) throws IOException { 
  44.      
  45.   } 
  46.    
  47.   public void reset(List<String> tokens) { 
  48.     this.tokens = tokens; 
  49.     this.tokenIter = tokens.iterator(); 
  50.   } 

  这样的话,一个能在Lucene中使用的分词器就构造好了。测试一下吧:

测试的语句为(程序根目录下的text.txt文件里):

  
  
  
  
  1. 随后温总理就离开了舟曲县城,预计温总理今天下午就回到北京。以上就是今天上午的最新动态。 
  2. 美丽的姑娘,你在哪里?http//:www.baidu.com 
  3. 两位青年工人协助民警抓住了一伙歹徒。 
  4. 公元二零一零年十二月,抓住了一只兔子。 

测试的代码如下:

  
  
  
  
  1. import java.io.File; 
  2. import java.io.FileReader; 
  3.  
  4. import org.apache.lucene.analysis.Analyzer; 
  5. import org.apache.lucene.analysis.TokenStream; 
  6. import org.apache.lucene.analysis.tokenattributes.CharTermAttribute; 
  7. import org.apache.lucene.analysis.tokenattributes.TypeAttribute; 
  8.  
  9. import com.xh.analyzer.ICTCLASAnalyzer; 
  10.  
  11.  
  12. class TestMain 
  13. {   //主函数 
  14.     public static void main(String[] args) throws Exception 
  15.     { 
  16.         Analyzer analyzer = new ICTCLASAnalyzer(); 
  17.         TokenStream ts=analyzer.tokenStream("contents"new FileReader(new File("text.txt"))); 
  18.         while(ts.incrementToken()){ 
  19.             System.out.print(ts.getAttribute(CharTermAttribute.class)+""+ts.getAttribute(TypeAttribute.class).type()+" "); 
  20.         } 
  21.         
  22.     } 

测试结果如下:

温/nr 总理/n 离开/v 预计/v 温/nr 总理/n 今天/t 下午/t 回到/v 北京/ns 以上/f 是/v 今天/t 上午/t 最新/a 动态/n 美丽/a 姑娘/n 在/p http/x :/x www/x baidu/x com/x 位/q 青年/n 工人/n 协助/v 民警/n 抓住/v 伙/q 歹徒/n 公元/n 十二月/t 抓住/v 只/q 兔子/n

如果不输出词性:则TestMain代码改为:

  
  
  
  
  1. import java.io.File; 
  2. import java.io.FileReader; 
  3.  
  4. import org.apache.lucene.analysis.Analyzer; 
  5. import org.apache.lucene.analysis.TokenStream; 
  6. import org.apache.lucene.analysis.tokenattributes.CharTermAttribute; 
  7. import org.apache.lucene.analysis.tokenattributes.TypeAttribute; 
  8.  
  9. import com.xh.analyzer.ICTCLASAnalyzer; 
  10.  
  11.  
  12. class TestMain 
  13. {   //主函数 
  14.     public static void main(String[] args) throws Exception 
  15.     { 
  16.         Analyzer analyzer = new ICTCLASAnalyzer(); 
  17.         TokenStream ts=analyzer.tokenStream("contents"new FileReader(new File("text.txt"))); 
  18.         while(ts.incrementToken()){ 
  19.             System.out.print(ts.getAttribute(CharTermAttribute.class)+" "); 
  20.         } 
  21.         
  22.     } 

温 总理 离开 预计 温 总理 今天 下午 回到 北京 以上 是 今天 上午 最新 动态 美丽 姑娘 在 http : www baidu com 位 青年 工人 协助 民警 抓住 伙 歹徒 公元 十二月 抓住 只 兔子 

 项目本来想直接上传,但是不支持2M以上的,上传到我的下载去吧。链接为:http://down.51cto.com/data/724179

你可能感兴趣的:(Lucene,analyzer,ictclas)