• 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);

    程序运行结果

    位置增量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>
    View Code

     

    自定义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获取分词详细信息]

    在线交谈

  • 相关阅读:
    css兼容性大坑
    JS获取元素CSS值
    calendar的一些操作
    java日期工具类
    redis的一些操作
    webstorm ES6 转 ES5
    基于时间的动画算法
    3434
    MySQL登陆知识
    MySQL密码知识点
  • 原文地址:https://www.cnblogs.com/dennisit/p/3258664.html
Copyright © 2020-2023  润新知