• 【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词语过滤的功能今天就做了多,以后还会继续补充~

  • 相关阅读:
    实现非父子之间通信,兄弟组件之间的数据传递--eventBus
    Vue的核心思想是什么..........
    Vue——核心思想--mvvm
    高效遍历匹配Json数据,避免嵌套循环
    js 报错(intermediate value)(...) is not a function
    【Three.js】three.js 中的矩阵变换及两种旋转表达方式
    【Vue源码】将二维数组变为一维数组
    【移动端】cordova实现退出app功能
    【移动端】ionic cordova 打包debug调试版、release发布版
    【Vue源码】document.querySelector()方法
  • 原文地址:https://www.cnblogs.com/itcsl/p/6595766.html
Copyright © 2020-2023  润新知