zoukankan      html  css  js  c++  java
  • Lucene学习-深入Lucene分词器,TokenStream获取分词详细信息

    Lucene学习-深入Lucene分词器,TokenStream获取分词详细信息

    在此回复牛妞的关于程序中分词器的问题,其实可以直接很简单的在词库中配置就好了,Lucene中分词的所有信息我们都可以从TokenStream流中获取.

    分词器的核心类Analyzer,TokenStream,Tokenizer,TokenFilter.

    Analyzer

    Lucene中的分词器有StandardAnalyzer,StopAnalyzer,SimpleAnalyzer,WhitespaceAnalyzer.

    TokenStream

    分词器做好处理之后得到的一个流,这个流中存储了分词的各种信息.可以通过TokenStream有效的获取到分词单元

    Tokenizer

    主要负责接收字符流Reader,将Reader进行分词操作.有如下一些实现类

    KeywordTokenizer,

    standardTokenizer,

    CharTokenizer

    |----WhitespaceTokenizer

    |----LetterTokenizer

    |----LowerCaseTokenizer

    TokenFilter

    将分好词的语汇单元进行各种各样的过滤.

    查看分词器的分词信息

    复制代码
    package com.icreate.analyzer.luence;
    
    import java.io.IOException;
    import java.io.StringReader;
    
    import org.apache.lucene.analysis.Analyzer;
    import org.apache.lucene.analysis.SimpleAnalyzer;
    import org.apache.lucene.analysis.StopAnalyzer;
    import org.apache.lucene.analysis.TokenStream;
    import org.apache.lucene.analysis.WhitespaceAnalyzer;
    import org.apache.lucene.analysis.standard.StandardAnalyzer;
    import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
    import org.apache.lucene.util.Version;
    
    /**
     *
     *  AnalyzerUtil.java   
     *
     *  @version : 1.1
     *  
     *  @author  : 苏若年    <a href="mailto:DennisIT@163.com">发送邮件</a>
     *    
     *  @since   : 1.0        创建时间:    2013-4-14  上午11:05:45
     *     
     *  TODO     : 
     *
     */
    public class AnalyzerUtil {
    
        /**
         *
         * Description:         查看分词信息
         * @param str        待分词的字符串
         * @param analyzer    分词器
         *
         */
        public static void displayToken(String str,Analyzer analyzer){
            try {
                //将一个字符串创建成Token流
                TokenStream stream  = analyzer.tokenStream("", new StringReader(str));
                //保存相应词汇
                CharTermAttribute cta = stream.addAttribute(CharTermAttribute.class);
                while(stream.incrementToken()){
                    System.out.print("[" + cta + "]");
                }
                System.out.println();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        
        public static void main(String[] args) {
            Analyzer aly1 = new StandardAnalyzer(Version.LUCENE_36);
            Analyzer aly2 = new StopAnalyzer(Version.LUCENE_36);
            Analyzer aly3 = new SimpleAnalyzer(Version.LUCENE_36);
            Analyzer aly4 = new WhitespaceAnalyzer(Version.LUCENE_36);
            
            String str = "hello kim,I am dennisit,我是 中国人,my email is dennisit@163.com, and my QQ is 1325103287";
            
            AnalyzerUtil.displayToken(str, aly1);
            AnalyzerUtil.displayToken(str, aly2);
            AnalyzerUtil.displayToken(str, aly3);
            AnalyzerUtil.displayToken(str, aly4);
        }
    }
    复制代码

    程序执行结果

    复制代码
    [hello][kim][i][am][dennisit][我][是][中][国][人][my][email][dennisit][163][com][my][qq][1325103287]
    [hello][kim][i][am][dennisit][我是][中国人][my][email][dennisit][com][my][qq]
    [hello][kim][i][am][dennisit][我是][中国人][my][email][is][dennisit][com][and][my][qq][is]
    [hello][kim,I][am][dennisit,我是][中国人,my][email][is][dennisit@163.com,][and][my][QQ][is][1325103287]
    复制代码

    standardanalyzer将数字作为一个整体,每个单词都进行分隔

    stopanalyzer将数字停用 中文不起作用,只坐空格分割

    simpleanalyzer将数字停用 中文不起作用,只按照空格分割

    whitespaceanalyzer按照空格分隔,中文不起作用

     

    展示分词的详细信息

    复制代码
        /**
         * 
         * Description:        显示分词的全部信息
         * @param str
         * @param analyzer
         *
         */
        public static void displayAllTokenInfo(String str, Analyzer analyzer){
            try {
                //第一个参数只是标识性没有实际作用
                TokenStream stream = analyzer.tokenStream("", new StringReader(str));
                //获取词与词之间的位置增量
                PositionIncrementAttribute postiona = stream.addAttribute(PositionIncrementAttribute.class);
                //获取各个单词之间的偏移量
                OffsetAttribute offseta = stream.addAttribute(OffsetAttribute.class);
                //获取每个单词信息
                CharTermAttribute chara = stream.addAttribute(CharTermAttribute.class);
                //获取当前分词的类型
                TypeAttribute typea = stream.addAttribute(TypeAttribute.class);
                while(stream.incrementToken()){
                    System.out.print("位置增量" +postiona.getPositionIncrement()+":	");
                    System.out.println(chara+"	[" + offseta.startOffset()+" - " + offseta.endOffset() + "]	<" + typea +">");
                }
                System.out.println();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    复制代码

    测试代码

    复制代码
            Analyzer aly1 = new StandardAnalyzer(Version.LUCENE_36);
            Analyzer aly2 = new StopAnalyzer(Version.LUCENE_36);
            Analyzer aly3 = new SimpleAnalyzer(Version.LUCENE_36);
            Analyzer aly4 = new WhitespaceAnalyzer(Version.LUCENE_36);
            
            String str = "hello kim,I am dennisit,我是 中国人,my email is dennisit@163.com, and my QQ is 1325103287";
            
            AnalyzerUtil.displayAllTokenInfo(str, aly1);
            AnalyzerUtil.displayAllTokenInfo(str, aly2);
            AnalyzerUtil.displayAllTokenInfo(str, aly3);
            AnalyzerUtil.displayAllTokenInfo(str, aly4);
    复制代码

    程序运行结果

    复制代码
     View Code

    位置增量1: hello [0 - 5] <type=<ALPHANUM>>
    位置增量1: kim [6 - 9] <type=<ALPHANUM>>
    位置增量1: i [10 - 11] <type=<ALPHANUM>>
    位置增量1: am [12 - 14] <type=<ALPHANUM>>
    位置增量1: dennisit [15 - 23] <type=<ALPHANUM>>
    位置增量1: 我 [24 - 25] <type=<IDEOGRAPHIC>>
    位置增量1: 是 [25 - 26] <type=<IDEOGRAPHIC>>
    位置增量1: 中 [27 - 28] <type=<IDEOGRAPHIC>>
    位置增量1: 国 [28 - 29] <type=<IDEOGRAPHIC>>
    位置增量1: 人 [29 - 30] <type=<IDEOGRAPHIC>>
    位置增量1: my [31 - 33] <type=<ALPHANUM>>
    位置增量1: email [34 - 39] <type=<ALPHANUM>>
    位置增量2: dennisit [43 - 51] <type=<ALPHANUM>>
    位置增量1: 163 [52 - 55] <type=<NUM>>
    位置增量1: com [56 - 59] <type=<ALPHANUM>>
    位置增量2: my [65 - 67] <type=<ALPHANUM>>
    位置增量1: qq [68 - 70] <type=<ALPHANUM>>
    位置增量2: 1325103287 [74 - 84] <type=<NUM>>

    位置增量1: hello [0 - 5] <type=word>
    位置增量1: kim [6 - 9] <type=word>
    位置增量1: i [10 - 11] <type=word>
    位置增量1: am [12 - 14] <type=word>
    位置增量1: dennisit [15 - 23] <type=word>
    位置增量1: 我是 [24 - 26] <type=word>
    位置增量1: 中国人 [27 - 30] <type=word>
    位置增量1: my [31 - 33] <type=word>
    位置增量1: email [34 - 39] <type=word>
    位置增量2: dennisit [43 - 51] <type=word>
    位置增量1: com [56 - 59] <type=word>
    位置增量2: my [65 - 67] <type=word>
    位置增量1: qq [68 - 70] <type=word>

    位置增量1: hello [0 - 5] <type=word>
    位置增量1: kim [6 - 9] <type=word>
    位置增量1: i [10 - 11] <type=word>
    位置增量1: am [12 - 14] <type=word>
    位置增量1: dennisit [15 - 23] <type=word>
    位置增量1: 我是 [24 - 26] <type=word>
    位置增量1: 中国人 [27 - 30] <type=word>
    位置增量1: my [31 - 33] <type=word>
    位置增量1: email [34 - 39] <type=word>
    位置增量1: is [40 - 42] <type=word>
    位置增量1: dennisit [43 - 51] <type=word>
    位置增量1: com [56 - 59] <type=word>
    位置增量1: and [61 - 64] <type=word>
    位置增量1: my [65 - 67] <type=word>
    位置增量1: qq [68 - 70] <type=word>
    位置增量1: is [71 - 73] <type=word>

    位置增量1: hello [0 - 5] <type=word>
    位置增量1: kim,I [6 - 11] <type=word>
    位置增量1: am [12 - 14] <type=word>
    位置增量1: dennisit,我是 [15 - 26] <type=word>
    位置增量1: 中国人,my [27 - 33] <type=word>
    位置增量1: email [34 - 39] <type=word>
    位置增量1: is [40 - 42] <type=word>
    位置增量1: dennisit@163.com, [43 - 60] <type=word>
    位置增量1: and [61 - 64] <type=word>
    位置增量1: my [65 - 67] <type=word>
    位置增量1: QQ [68 - 70] <type=word>
    位置增量1: is [71 - 73] <type=word>
    位置增量1: 1325103287 [74 - 84] <type=word>

    复制代码

     

    自定义stop分词器

    继承Analyzer复写public TokenStream tokenStream(String filename,Reader reader)方法

    复制代码
    package org.dennisit.lucene.util;
    import java.io.IOException;
    import java.io.Reader;
    import java.io.StringReader;
    import java.util.Set;
    
    import org.apache.lucene.analysis.Analyzer;
    import org.apache.lucene.analysis.LetterTokenizer;
    import org.apache.lucene.analysis.LowerCaseFilter;
    import org.apache.lucene.analysis.StopAnalyzer;
    import org.apache.lucene.analysis.StopFilter;
    import org.apache.lucene.analysis.TokenStream;
    import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
    import org.apache.lucene.util.Version;
    
    /**
     *
     *  org.dennisit.lucene.utilMyStopAnalyzer.java   
     *
     *  @version : 1.1
     *  
     *  @author  : 苏若年         <a href="mailto:DennisIT@163.com">发送邮件</a>
     *    
     *  @since   : 1.0      创建时间:    2013-4-14  下午12:06:08
     *     
     *  TODO     : 
     *
     */
    public class MyStopAnalyzer extends Analyzer{
        
        private Set stops;
        
        /**
         * 在原来停用词基础上增加自己的停用词
         * @param stopwords    自定义停用词采用数组传递
         */
        public MyStopAnalyzer(String[] stopwords){
            //会自动将字符串数组转换为Set
            stops = StopFilter.makeStopSet(Version.LUCENE_36,stopwords,true);
            //将原有的停用词加入到现在的停用词
            stops.addAll(StopAnalyzer.ENGLISH_STOP_WORDS_SET);
        }
        
        /**
         * 不传入参数表示使用原来默认的停用词
         */
        public MyStopAnalyzer(){
            //获取原有的停用词
            stops = StopAnalyzer.ENGLISH_STOP_WORDS_SET;
        }
        
        @Override
        public TokenStream tokenStream(String filename,Reader reader){
            //为自定义分词器设定过滤链和Tokenizer
            return  new StopFilter(Version.LUCENE_36, 
                    new LowerCaseFilter(Version.LUCENE_36, 
                    new LetterTokenizer(Version.LUCENE_36,reader)),
                    stops);
        }
        
        
        /**
         *
         * Description:         查看分词信息
         * @param str        待分词的字符串
         * @param analyzer    分词器
         *
         */
        public static void displayToken(String str,Analyzer analyzer){
            try {
                //将一个字符串创建成Token流
                TokenStream stream  = analyzer.tokenStream("", new StringReader(str));
                //保存相应词汇
                CharTermAttribute cta = stream.addAttribute(CharTermAttribute.class);
                while(stream.incrementToken()){
                    System.out.print("[" + cta + "]");
                }
                System.out.println();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        
        public static void main(String[] args) {
            //获取原来的停用词
            Analyzer myAnalyzer1 = new MyStopAnalyzer();
            //追加自己的停用词
            Analyzer myAnalyzer2 = new MyStopAnalyzer(new String[]{"hate","fuck"});
            //分词处理的句子
            String text = "fuck! I hate you very much";
            
            displayToken(text, myAnalyzer1);
            displayToken(text, myAnalyzer2);
        }
    }
    复制代码

    程序运行结果

    复制代码
    [fuck][i][hate][you][very][much]
    [i][you][very][much]
    复制代码


    在此感谢孔浩老师,关于Lucene的深入,孔老师的教程讲的不错![Lucene学习-深入Lucene分词器,TokenStream获取分词详细信息]

    在线交谈

    热爱生活,热爱Coding,敢于挑战,用于探索 ...
     
    分类: JavaEE数据挖掘
    标签: lucene
  • 相关阅读:
    [CF846E]Chemistry in Berland题解
    [CF846D]Monitor题解
    [CF846B]Math Show题解
    [CF846A]Curriculum Vitae题解
    斜率优化 学习笔记
    【CF115E】Linear Kingdom Races 题解(线段树优化DP)
    【洛谷P3802】小魔女帕琪 题解(概率期望)
    7月13日考试 题解(DFS序+期望+线段树优化建图)
    【BZOJ1426】收集邮票 题解 (期望)
    【HNOI2010】弹飞绵羊 题解(分块)
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3259337.html
Copyright © 2011-2022 走看看