• Apache Lucene(全文检索引擎)—分词器


    目录

      返回目录:http://www.cnblogs.com/hanyinglong/p/5464604.html

      本项目Demo已上传GitHub,欢迎大家fork下载学习:https://github.com/kencery/Lucene_Compass(项目内部有很详细的注释)

    1.分词器的作用

      a. 在创建索引的时候需要用到分词器,在使用字符串搜索的时候也会用到分词器,并且这两个地方要使用同一个分词器,否则可能会搜索不出来结果。

      b. 分词器(Analyzer)的作用是把一段文本中的词按规则取出所包含的所有词,对应的是Analyzer类,这是一个抽象类(public abstract class org.apache.lucene.analysis.Analyzer),切分词的具体规则是由子类实现的,所以对于不同的语言规则,要有不同的分词器。

      c.关于分词器的详细运行代码,请在GitHub上下载,下载地址:https://github.com/kencery/Lucene_Compass/tree/master/Lucene_5.5,对应的分支为:lucene_five。

    2.英文分词器的原理

      a.英文的处理流程为:输入文本,词汇切分,词汇过滤(去除停用词),词干提取(形态还原)、大写转小写,结果输出。

      b. 何为形态还原,意思是:去除单词词尾的形态变化,将其还原为词的原形,这样做可以搜索出更多有意义的结果,比如在搜索student的时候,同事也可以搜索出students的结果。

      c. 任何一个分词法对英文的支持都是还可以的。

    3.中文分词器的原理

      a.中文分词比较复杂,并没有英文分词那么简单,这主要是因为中文的词与词之间并不是像英文那样用空格来隔开,

    因为不是一个字就是一个词,而且一个词在另外一个地方就可能不是一个词,如:"我们是中国人","是中"就不是一个词,对于中文分词,通常有三种方式:单字分词、二分法分词、词典分词。

        a.1 单字分词:就是按照中文一个字一个字的进行分词,比如:"我们是中国人",分词的效果就是"我","们","是","中","国","人",StandardAnalyzer分词法就是单字分词。

        a.2 二分法分词:按照两个字进行切分,比如:"我们是中国人",分词的效果就是:"我们","们是","是中","中国","国人",CJKAnalyzer分词法就是二分法分词

        a.3 词库分词:按照某种算法构造词,然后去匹配已建好的词库集合,如果匹配到就切分出来成为词语,通常词库分词被认为是最好的中文分词算法,如:"我们是中国人",分词的效果就是:"我们","中国人",极易分词

    MMAnalyzer、庖丁分词、IkAnalyzer等分词法就是属于词库分词。

      b.分词器还有很大,请大家自行查询,它们的实现基本一致,都是Analyzer的子类,故而可以很完美的继承到Lucene中。

    4.停用词的规则

      a. 有些词在文本中出现的频率非常高,但是对文本所携带的信息基本不产生影响,例如英文的"a、an、the、of"或中文的"的、了、着、是",以及各种标点符号等,这样的词称为停用词,文本经过分词处理后,停用词通常会被过滤掉,不会被进行索引,在检索的时候,用户的查询中如果含有停用词,检索系统也会将其过滤掉,这是因为用户输入哦查询字符串也要进行分词处理,排除停用词可以硷蒉建立索引的速度,减小索引库文件的大小。

    5.分词器的使用代码

      1 package com.lyzj.kencery.unit;
      2 import java.io.StringReader;
      3 import org.apache.lucene.analysis.Analyzer;
      4 import org.apache.lucene.analysis.TokenStream;
      5 import org.apache.lucene.analysis.cjk.CJKAnalyzer;
      6 import org.apache.lucene.analysis.standard.StandardAnalyzer;
      7 import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
      8 import org.apache.lucene.analysis.tokenattributes.OffsetAttribute;
      9 import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;
     10 import org.apache.lucene.analysis.tokenattributes.TypeAttribute;
     11 import org.junit.Test;
     12 import org.wltea.analyzer.lucene.IKAnalyzer;
     13 /**
     14  * 测试分词器
     15  * 分词器工作流程
     16  *     1.切分,将需要分词的内容进行切分成每个单词或者词语
     17  *     2.去除停用词,有些词在文本中出现的频率非常高,但是对文本所携带的信息基本不产生影响,例如英文的“a、an、the、of”,或中文的“的、了、着、是”,以及各种标点符号等,
     18  * 这样的词称为停用词(stop word)。文本经过分词之后,停用词通常被过滤掉,不会被进行索引。在检索的时候,用户的查询中如果含有停用词,
     19  * 检索系统也会将其过滤掉(因为用户输入的查询字符串也要进行分词处理)。排除停用词可以加快建立索引的速度,减小索引库文件的大小。
     20  *     3.对于英文字母,转为小写,因为搜索的时候不区分大小写
     21  * @author kencery
     22  *
     23  */
     24 public class AnalyzerTest {
     25 
     26     /**
     27      * StandardAnalyzer分词法测试,对中文支持不是很好,将中文分词成1个字(单字分词)
     28      * @throws Exception 
     29      */
     30     @Test
     31     public void StandardAnalyzerTest() throws Exception{
     32         //英文测试
     33         String text="An IndexWriter creaters and maintains an index.";
     34         Analyzer analyzer=new StandardAnalyzer();
     35         displayTokens(analyzer,text);
     36         //中文测试
     37         String text1="Lucene是全文检索框架";
     38         displayTokens(analyzer,text1);    
     39     }
     40 
     41      /**
     42       * CJKAnalyzerTest分词法测试,对中文支持不是很好,将中文分词成2个字(二分法分词)
     43       * 
     44       * @throws Exception
     45       */
     46     @Test
     47     public void CJKAnalyzerTest() throws Exception{
     48         //英文测试
     49         String text="An IndexWriter creaters and maintains an index.";
     50         Analyzer analyzer=new CJKAnalyzer();
     51         displayTokens(analyzer,text);
     52         //中文测试
     53         String text1="Lucene是全文检索框架";
     54         displayTokens(analyzer,text1);    
     55     }
     56 
     57      /**
     58       * IKAnalyzerTest分词法测试,对中文支持很好,词库分词
     59       * @throws Exception
     60       */
     61     @Test
     62     public void IKAnalyzerTest() throws Exception{
     63         //英文测试
     64         String text="An IndexWriter creaters and maintains an index.";
     65         Analyzer analyzer=new IKAnalyzer();
     66         displayTokens(analyzer,text);
     67         //中文测试
     68         String text1="韩迎龙易淘食的Lucene是全文检索框架";
     69         displayTokens(analyzer,text1);    
     70     }
     71 
     72     /**
     73      * 使用指定的分词器对指定的文本进行分词,并打印出分出的词,测试分词法的方法
     74      * 备注说明:这里注意版本问题,暂无方法解决
     75      * @param analyzer
     76      * @param text
     77      * @throws Exception
     78      */
     79     public static void displayTokens(Analyzer analyzer, String text) throws Exception {
     80         System.out.println("当前使用的分词器:" + analyzer.getClass().getName());
     81         //分词流,即将对象分词后所得的Token在内存中以流的方式存在,也说是说如果在取得Token必须从TokenStream中获取,而分词对象可以是文档文本,也可以是查询文本。
     82         TokenStream tokenStream = analyzer.tokenStream("content", new StringReader(text));
     83         //表示token的首字母和尾字母在原文本中的位置。比如I'm的位置信息就是(0,3),需要注意的是startOffset与endOffset的差值并不一定就是termText.length(),
     84         //因为可能term已经用stemmer或者其他过滤器处理过;
     85         OffsetAttribute offsetAttribute = tokenStream.addAttribute(OffsetAttribute.class);
     86         //这个有点特殊,它表示tokenStream中的当前token与前一个token在实际的原文本中相隔的词语数量,用于短语查询。比如: 在tokenStream中[2:a]的前一个token是[1:I'm ],
     87         //它们在原文本中相隔的词语数是1,则token="a"的PositionIncrementAttribute值为1;
     88         PositionIncrementAttribute positionIncrementAttribute = tokenStream.addAttribute(PositionIncrementAttribute.class);
     89 
     90         //问题说明:这里需要使用jdk1.7,如果使用jdk1.8或者jdk1.6则会出现报错信息
     91         //>>如果大家谁有相应的解决方案,请提交到git上我将会合并或者添加我的QQ我们互相讨论
     92         CharTermAttribute charTermAttribute= tokenStream.addAttribute(CharTermAttribute.class);
     93 
     94         //表示token词典类别信息,默认为“Word”,比如I'm就属于<APOSTROPHE>,有撇号的类型;
     95         TypeAttribute typeAttribute = tokenStream.addAttribute(TypeAttribute.class);
     96         tokenStream.reset();
     97 
     98         int position = 0;
     99         while (tokenStream.incrementToken()) {
    100           int increment = positionIncrementAttribute.getPositionIncrement();
    101           if(increment > 0) {
    102             position = position + increment;
    103           }
    104           int startOffset = offsetAttribute.startOffset();
    105           int endOffset = offsetAttribute.endOffset();
    106           String term ="输出结果为:"+ charTermAttribute.toString();
    107           System.out.println("第"+position+"个分词,分词内容是:[" + term + "]" + ",分词内容的开始结束位置为:(" + startOffset + "-->" + endOffset + "),类型是:" + typeAttribute.type());
    108         }
    109         tokenStream.close();
    110     }
    111 }

     

    6. Compass简单介绍(不建议使用)

      a. 已经不建议使用,因为官方已停止更新,支持的Lucene的最高版本为2.4,而当前Lucene的版本已经到了5.5。

      b. 因为是学习,所以简单写了一个Compass的Demo,下载地址:https://github.com/kencery/Lucene_Compass/tree/master/Compass_2.2,项目内部有详细的代码备注。

      c.这里有一篇别人写的Compass博客,个人感觉非常好,地址:http://yufenfei.iteye.com/blog/1683546

     

       备注:接下来将使用ElasticSearch来做搜索。

     

  • 相关阅读:
    Visual Basic 9.0 前沿播报·静态篇(二)对象初始化器和匿名类型
    Visual Basic 9.0 前沿播报内容概览
    Refactor! for VB —— VB2005的重构支持(一)
    我不知道该说什么,这里太先进了!
    Visual Basic 9.0 前沿播报·静态篇(一)局部变量类型推测和数组初始化器
    关于“就地颠倒句子里的词”面试题
    Visual Basic 9.0 前沿播报·静态篇(三)扩展方法
    《窝窝世界》视频20101025
    Silverlight 游戏开发小技巧:透明背景的Silverlight程序
    Silverlight 游戏开发小技巧:技能冷却效果2(Cooldown)2
  • 原文地址:https://www.cnblogs.com/hanyinglong/p/5395600.html
Copyright © 2020-2023  润新知