zoukankan      html  css  js  c++  java
  • 【lucene系列学习四】使用IKAnalyzer分词器实现敏感词和停用词过滤

    Lucene自带的中文分词器SmartChineseAnalyzer不太好扩展,于是我用了IKAnalyzer来进行敏感词和停用词的过滤。

    首先,下载IKAnalyzer,我下载了

    然后,由于IKAnalyzer已经很久不更新了,不兼容现在的Lucene6版本,所以我参考网上的资料,重写了IKTokenizer和IKAnalyzer两个类。

     1 package kidsearch;
     2 import java.io.IOException;
     3 import java.io.Reader;
     4 
     5 import org.apache.lucene.analysis.Tokenizer;
     6 import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
     7 import org.apache.lucene.analysis.tokenattributes.OffsetAttribute;
     8 import org.apache.lucene.analysis.tokenattributes.TypeAttribute;
     9 import org.wltea.analyzer.core.IKSegmenter;
    10 import org.wltea.analyzer.core.Lexeme;
    11 
    12 public class MyIKTokenizer extends Tokenizer {
    13     // IK分词器实现
    14     private IKSegmenter _IKImplement;
    15 
    16     // 词元文本属性
    17     private final CharTermAttribute termAtt;
    18     // 词元位移属性
    19     private final OffsetAttribute offsetAtt;
    20     // 词元分类属性(该属性分类参考org.wltea.analyzer.core.Lexeme中的分类常量)
    21     private final TypeAttribute typeAtt;
    22     // 记录最后一个词元的结束位置
    23     private int endPosition;
    24 
    25     public MyIKTokenizer(Reader in) {
    26         this(in, true);
    27     }
    28 
    29     public MyIKTokenizer(Reader in, boolean useSmart) {
    30         offsetAtt = addAttribute(OffsetAttribute.class);
    31         termAtt = addAttribute(CharTermAttribute.class);
    32         typeAtt = addAttribute(TypeAttribute.class);
    33         _IKImplement = new IKSegmenter(input, useSmart);
    34     }
    35 
    36     @Override
    37     public boolean incrementToken() throws IOException {
    38         // 清除所有的词元属性
    39         clearAttributes();
    40         Lexeme nextLexeme = _IKImplement.next();
    41         if (nextLexeme != null) {
    42             // 将Lexeme转成Attributes
    43             // 设置词元文本
    44             termAtt.append(nextLexeme.getLexemeText());
    45             // 设置词元长度
    46             termAtt.setLength(nextLexeme.getLength());
    47             // 设置词元位移
    48             offsetAtt.setOffset(nextLexeme.getBeginPosition(),
    49                     nextLexeme.getEndPosition());
    50             // 记录分词的最后位置
    51             endPosition = nextLexeme.getEndPosition();
    52             // 记录词元分类
    53             typeAtt.setType(String.valueOf(nextLexeme.getLexemeType()));
    54             // 返会true告知还有下个词元
    55             return true;
    56         }
    57         // 返会false告知词元输出完毕
    58         return false;
    59     }
    60 
    61     public void reset() throws IOException {
    62         super.reset();
    63         _IKImplement.reset(input);
    64     }
    65 
    66     @Override
    67     public final void end() {
    68         // set final offset
    69         int finalOffset = correctOffset(this.endPosition);
    70         offsetAtt.setOffset(finalOffset, finalOffset);
    71     }
    72 
    73 }
    MyIKTokenizer
     1 package kidsearch;
     2 import java.io.Reader;
     3 import java.io.StringReader;
     4 
     5 import org.apache.lucene.analysis.Analyzer;
     6 import org.apache.lucene.util.IOUtils;
     7 import kidsearch.MyIKTokenizer;
     8 public class MyIkAnalyzer extends Analyzer {
     9 
    10     @Override
    11     protected TokenStreamComponents createComponents(String arg0) {
    12         Reader reader=null;
    13         try{
    14             reader=new StringReader(arg0);
    15             MyIKTokenizer it = new MyIKTokenizer(reader);
    16             return new Analyzer.TokenStreamComponents(it);
    17         }finally {
    18             IOUtils.closeWhileHandlingException(reader);
    19         }
    20     }
    21 
    22 }
    MyIKAnalyzer

    参考的博客里有一部分是错误的

    于是我又下载了IKAnalyzer的源码,仔细看了一下Lexeme.java,发现没有这个方法,只有getLexemeType,而且返回值是int,于是自己做了点小改动,终于编译通过了!

    值得注意的是,MyIKTokenizer里

    1 public MyIKTokenizer(Reader in) {
    2         this(in, true);
    3     }
    View Code

    true为选择智能划分(北京师范大学),而false为最细粒度划分(北京师范大学,北京,京师,师范大学,师范,大学)。

    最后,要配置自己的停用词和敏感词。

    自定义词典一定要使用UTF-8无BOM编码,否则不能实现过滤功能。

    然后,在配置文件IKAnalyzer.cfg.xml里配置自定义词典

    最后,分别把所有的自定义词典和IKAnalyzer.cfg.xml加到工程里的src(为了保险起见,我又把他们加到了bin里,IK的jar包里也加了)。

    为了测试停用词的效果,可以自己写几个小程序。

     1 import java.io.IOException;
     2 import java.io.StringReader;
     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.wltea.analyzer.cfg.Configuration;
     8 import org.wltea.analyzer.cfg.DefaultConfig;
     9 import org.wltea.analyzer.core.IKSegmenter;
    10 import org.wltea.analyzer.core.Lexeme;
    11 import org.wltea.analyzer.lucene.IKAnalyzer;
    12 
    13 public class OwnIKAnalyzer {
    14     public static void main(String[] args) throws IOException {  
    15         String text="我有一个红红的苹果";
    16         StringReader sr=new StringReader(text);  
    17     //    IKSegmenter ik=new IKSegmenter(sr, true);  
    18         IKSegmenter ik=new IKSegmenter(sr,true); 
    19         Lexeme lex=null;  
    20         while((lex=ik.next())!=null){  
    21             System.out.print(lex.getLexemeText()+",");  
    22         }  
    23 //        String text = "这是一个红红的苹果";  
    24 //        Configuration configuration = DefaultConfig.getInstance();  
    25 //        configuration.setUseSmart(true);  
    26 //        IKSegmenter ik = new IKSegmenter(new StringReader(text), configuration);  
    27 //        Lexeme lexeme = null;  
    28 //        while ((lexeme = ik.next()) != null) {  
    29 //            System.out.println(lexeme.getLexemeText());  
    30         }  
    31     }  
    View Code

    测试结果为:(词典里并没有过滤“我”)

    另外,IKAnalyzer可以配置自己的扩展词典,比如“你的名字”本来会被分词为“你,的,名字”,但是在ext.dic里加入“你的名字”后就是一个完整的整体,不会被切分了!

    关于IKAnalyzer词语过滤的功能今天就做了多,以后还会继续补充~

  • 相关阅读:
    leetcode 155. Min Stack 、232. Implement Queue using Stacks 、225. Implement Stack using Queues
    leetcode 557. Reverse Words in a String III 、151. Reverse Words in a String
    leetcode 153. Find Minimum in Rotated Sorted Array 、154. Find Minimum in Rotated Sorted Array II 、33. Search in Rotated Sorted Array 、81. Search in Rotated Sorted Array II 、704. Binary Search
    leetcode 344. Reverse String 、541. Reverse String II 、796. Rotate String
    leetcode 162. Find Peak Element
    leetcode 88. Merge Sorted Array
    leetcode 74. Search a 2D Matrix 、240. Search a 2D Matrix II
    Android的API版本和名称对应关系
    spring 定时任务执行两次解决办法
    解析字符串为泛型的方法
  • 原文地址:https://www.cnblogs.com/itcsl/p/6595766.html
Copyright © 2011-2022 走看看