Analysis包分析

算法和数据结构分析:

由于Analysis包比较简单,不详述了!

算法:基于机械分词 1-gram,2-gram,HMM(如果使用ICTCLAS接口的话)

数据结构:部分源码用到了Set ,HashTable,HashMap

认真理解Token

Lucene中的Analysis包专门用于完成对于索引文件的分词.Lucene中的Token是一个非常重要的概念.

看一下其源码实现:

public final class Token {

String termText;                       // the text of the term

int startOffset;                          // start in source text

int endOffset;                           // end in source text

String type = "word";                       // lexical type

private int positionIncrement = 1;

public Token(String text, int start, int end)

public Token(String text, int start, int end, String typ)

public void setPositionIncrement(int positionIncrement)

public int getPositionIncrement() { return positionIncrement; }

public final String termText() { return termText; }

public final int startOffset() { return startOffset; }

public void setStartOffset(int givenStartOffset)

public final int endOffset() { return endOffset; }

public void setEndOffset(int givenEndOffset)

public final String type() { return type; }

public String toString()

}

下面编一段代码来看一下

TestToken.java

package org.apache.lucene.analysis.test;

import org.apache.lucene.analysis.*;

import org.apache.lucene.analysis.standard.StandardAnalyzer;

import java.io.*;

public class TestToken

{

public static void main(String[] args)

{

String string = new String("我爱天大,但我更爱中国");

//Analyzer analyzer = new StandardAnalyzer();

Analyzer analyzer = new TjuChineseAnalyzer();

//Analyzer analyzer= new StopAnalyzer();

TokenStream ts = analyzer.tokenStream("dummy",new StringReader(string));

Token token;

try

{

int n=0;

while ( (token = ts.next()) != null)

{

System.out.println((n++)+"->"+token.toString());

}

}

catch(IOException ioe)

{

ioe.printStackTrace();

}

}

}注意看其结果如下所示

0->Token's (termText,startOffset,endOffset,type,positionIncrement) is:(我,0,1,<CJK>,1)

1->Token's (termText,startOffset,endOffset,type,positionIncrement) is:(爱,1,2,<CJK>,1)

2->Token's (termText,startOffset,endOffset,type,positionIncrement) is:(天,2,3,<CJK>,1)

3->Token's (termText,startOffset,endOffset,type,positionIncrement) is:(大,3,4,<CJK>,1)

4->Token's (termText,startOffset,endOffset,type,positionIncrement) is:(但,5,6,<CJK>,1)

5->Token's (termText,startOffset,endOffset,type,positionIncrement) is:(我,6,7,<CJK>,1)

6->Token's (termText,startOffset,endOffset,type,positionIncrement) is:(更,7,8,<CJK>,1)

7->Token's (termText,startOffset,endOffset,type,positionIncrement) is:(爱,8,9,<CJK>,1)

8->Token's (termText,startOffset,endOffset,type,positionIncrement) is:(中,9,10,<CJK>,1)

9->Token's (termText,startOffset,endOffset,type,positionIncrement) is:(国,10,11,<CJK>,1)

注意:其中”,”被StandardAnalyzer给过滤掉了,所以大家注意第4个Token直接startOffset从5开始.

如果改用StopAnalyzer()

0->Token's (termText,startOffset,endOffset,type,positionIncrement) is:(我爱天大,0,4,word,1)

1->Token's (termText,startOffset,endOffset,type,positionIncrement) is:(但我更爱中国,5,11,word,1)

改用TjuChineseAnalyzer(我写的,下文会讲到如何去写)

0->Token's (termText,startOffset,endOffset,type,positionIncrement) is:(爱,3,4,word,1)

1->Token's (termText,startOffset,endOffset,type,positionIncrement) is:(天大,6,8,word,1)

2->Token's (termText,startOffset,endOffset,type,positionIncrement) is:(更,19,20,word,1)

3->Token's (termText,startOffset,endOffset,type,positionIncrement) is:(爱,22,23,word,1)

4->Token's (termText,startOffset,endOffset,type,positionIncrement) is:(中国,25,27,word,1)

讲明白了Token,咱们来看以下其他的东西

一个TokenStream是用来走访Token的iterator(迭代器)

看一下其源代码:

public abstract class TokenStream {

public abstract Token next() throws IOException;

public void close() throws IOException {}

}

一个Tokenizer,is-a TokenStream(派生自TokenStream),其输入为Reader

看一下其源码如下:

public abstract class Tokenizer extends TokenStream {

protected Reader input;

protected Tokenizer() {}

protected Tokenizer(Reader input) {

this.input = input;

}

public void close() throws IOException {

input.close();

}

}

一个TokenFilter is–a TokenStream(派生自TokenStream),其义如名就是用来完成对TokenStream的过滤操作,譬如

去StopWords,将Token变为小写等。

源码如下:

public abstract class TokenFilter extends TokenStream {

protected TokenStream input;

protected TokenFilter() {}

protected TokenFilter(TokenStream input) {

this.input = input;

}

public void close() throws IOException {

input.close();

}

}

一个Analyzer就是一个TokenStream工厂

看一下其源码就:

public abstract class Analyzer {

public TokenStream tokenStream(String fieldName, Reader reader)

{

return tokenStream(reader);

}

public TokenStream tokenStream(Reader reader)

{

return tokenStream(null, reader);

}

}

好,现在咱们来看一下Lucene的Analysis包下面的各个类文件都是用来干什么的。按照字典排序。

Analysis包中的源码详解

Analyzer.java 上文已经讲过。

CharTokenizer.java 此类为简单一个抽象类,用来对基于字符的进行简单分词(tokenizer)

LetterTokenizer.java两个非字符之间的字符串定义为token(举例来说英文单词由空白隔开,那个两个空白之间的字符串即被定义为一个token。备注:对于绝大多数欧洲语言来说,这个类工作效能很好。当时对于不用空白符分割的亚洲语言,效能极差(譬如中日韩)。)

LowerCaseFilter.java is-a TokenFilter用于将字母小写化

LowerCaseTokenizer is-a Tokenizer功能上等价于LetterTokenizer+LowerCaseFilter

PerFieldAnalyzerWrapper是一个Analyzer,因为继承自Analyzer当不同的域(Field)需要不同的语言分析器(Analyzer)时,这个Analyzer就派上了用场。使用成员函数addAnalyzer可以增加一个非缺省的基于某个Field的analyzer。很少使用。

PorterStemFilter.java使用词干抽取算法对每一个token流进行词干抽取。

PorterStemmer.java 有名的P-stemming算法

SimpleAnalyzer.java

StopAnalyzer.java   具有过滤停用词的功能

StopFilter.java     StopFilter为一个Filter,主要用于从token流中去除StopWords

Token.java       上面已讲.

TokenFilter.java   上面已经讲了

Tokenizer.java     上面已经讲了

TokenStream.java   上面已经讲了

WhitespaceAnalyzer.java

WhitespaceTokenizer.java 只是按照space区分Token.

由于Lucene的analyisis包下的Standard包下的StandardAnalyzer()功能很强大,而且支持CJK分词,我们简要说一下.

此包下的文件是有StandardTokenizer.jj经过javac命令生成的.由于是机器自动生成的代码,可能可读性很差,想了解的话好好看看那个StandardTokenizer.jj文件就会比较明了了.

Lucene常用的Analyzer功能概述.

WhitespaceAnalyzer:仅仅是去除空格,对字符没有lowcase化,不支持中文

SimpleAnalyzer:功能强于WhitespaceAnalyzer,将除去letter之外的符号全部过滤掉,并且将所有的字符lowcase化,不支持中文

StopAnalyzer:StopAnalyzer的功能超越了SimpleAnalyzer,在SimpleAnalyzer的基础上
    增加了去除StopWords的功能,不支持中文

StandardAnalyzer:英文的处理能力同于StopAnalyzer.支持中文采用的方法为单字切分.

ChineseAnalyzer:来自于Lucene的sand box.性能类似于StandardAnalyzer,缺点是不支持中英文混和分词.

CJKAnalyzer:chedong写的CJKAnalyzer的功能在英文处理上的功能和StandardAnalyzer相同
    但是在汉语的分词上,不能过滤掉标点符号,即使用二元切分

TjuChineseAnalyzer:我写的,功能最为强大.TjuChineseAnlyzer的功能相当强大,在中文分词方面由于其调用的为ICTCLAS的java接口.所以其在中文方面性能上同与ICTCLAS.其在英文分词上采用了Lucene的StopAnalyzer,可以去除 stopWords,而且可以不区分大小写,过滤掉各类标点符号.

各个Analyzer的功能已经比较介绍完毕了,现在咱们应该学写Analyzer,如何diy自己的analyzer呢??

如何DIY一个Analyzer

咱们写一个Analyzer,要求有一下功能

(1)    可以处理中文和英文,对于中文实现的是单字切分,对于英文实现的是以空格切分.

(2)    对于英文部分要进行小写化.

(3)    具有过滤功能,可以人工设定StopWords列表.如果不是人工设定,系统会给出默认的StopWords列表.

(4)    使用P-stemming算法对于英文部分进行词缀处理.

代码如下:

public final class DiyAnalyzer

extends Analyzer

{

private Set stopWords;

public static final String[] CHINESE_ENGLISH_STOP_WORDS =

{

"a", "an", "and", "are", "as", "at", "be", "but", "by",

"for", "if", "in", "into", "is", "it",

"no", "not", "of", "on", "or", "s", "such",

"t", "that", "the", "their", "then", "there", "these",

"they", "this", "to", "was", "will", "with",

"我", "我们"

};

public DiyAnalyzer()

{

this.stopWords=StopFilter.makeStopSet(CHINESE_ENGLISH_STOP_WORDS);

}

public DiyAnalyzer(String[] stopWordList)

{

this.stopWords=StopFilter.makeStopSet(stopWordList);

}

public TokenStream tokenStream(String fieldName, Reader reader)

{

TokenStream result = new StandardTokenizer(reader);

result = new LowerCaseFilter(result);

result = new StopFilter(result, stopWords);

result = new PorterStemFilter(result);

return result;

}

public static void main(String[] args)

{

//好像英文的结束符号标点.,StandardAnalyzer不能识别

String string = new String("我爱中国,我爱天津大学!I love China!Tianjin is a City");

Analyzer analyzer = new DiyAnalyzer();

TokenStream ts = analyzer.tokenStream("dummy", new StringReader(string));

Token token;

try

{

while ( (token = ts.next()) != null)

{

System.out.println(token.toString());

}

}

catch (IOException ioe)

{

ioe.printStackTrace();

}

}

}

可以看见其后的结果如下:

Token's (termText,startOffset,endOffset,type,positionIncrement) is:(爱,1,2,<CJK>,1)

Token's (termText,startOffset,endOffset,type,positionIncrement) is:(中,2,3,<CJK>,1)

Token's (termText,startOffset,endOffset,type,positionIncrement) is:(国,3,4,<CJK>,1)

Token's (termText,startOffset,endOffset,type,positionIncrement) is:(爱,6,7,<CJK>,1)

Token's (termText,startOffset,endOffset,type,positionIncrement) is:(天,7,8,<CJK>,1)

Token's (termText,startOffset,endOffset,type,positionIncrement) is:(津,8,9,<CJK>,1)

Token's (termText,startOffset,endOffset,type,positionIncrement) is:(大,9,10,<CJK>,1)

Token's (termText,startOffset,endOffset,type,positionIncrement) is:(学,10,11,<CJK>,1)

Token's (termText,startOffset,endOffset,type,positionIncrement) is:(i,12,13,<ALPHANUM>,1)

Token's (termText,startOffset,endOffset,type,positionIncrement) is:(love,14,18,<ALPHANUM>,1)

Token's (termText,startOffset,endOffset,type,positionIncrement) is:(china,19,24,<ALPHANUM>,1)

Token's (termText,startOffset,endOffset,type,positionIncrement) is:(tianjin,25,32,<ALPHANUM>,1)

Token's (termText,startOffset,endOffset,type,positionIncrement) is:(citi,39,43,<ALPHANUM>,1)

到此为止这个简单的但是功能强大的分词器就写完了,下面咱们可以尝试写一个功能更强大的分词器.

如何DIY一个功能更加强大Analyzer

譬如你有词典,然后你根据正向最大匹配法或者逆向最大匹配法写了一个分词方法,却想在Lucene中应用,很简单

你只要把他们包装成Lucene的TokenStream就好了.下边我以调用中科院写的ICTCLAS接口为例,进行演示.你去中科院

网站可以拿到此接口的free版本,谁叫你没钱呢,有钱,你就可以购买了.哈哈

好,由于ICTCLAS进行分词之后,在Java中,中间会以两个空格隔开!too easy,我们直接使用继承Lucene的

WhiteSpaceTokenizer就好了.

所以TjuChineseTokenizer 看起来像是这样.

public class TjuChineseTokenizer extends WhitespaceTokenizer

{

public TjuChineseTokenizer(Reader readerInput)

{

super(readerInput);

}

}

而TjuChineseAnalyzer看起来象是这样

public final class TjuChineseAnalyzer

extends Analyzer

{

private Set stopWords;

/** An array containing some common English words that are not usually useful

for searching. */

/*

public static final String[] CHINESE_ENGLISH_STOP_WORDS =

{

"a", "an", "and", "are", "as", "at", "be", "but", "by",

"for", "if", "in", "into", "is", "it",

"no", "not", "of", "on", "or", "s", "such",

"t", "that", "the", "their", "then", "there", "these",

"they", "this", "to", "was", "will", "with",

"我", "我们"

};

*/

/** Builds an analyzer which removes words in ENGLISH_STOP_WORDS. */

public TjuChineseAnalyzer()

{

stopWords = StopFilter.makeStopSet(StopWords.SMART_CHINESE_ENGLISH_STOP_WORDS);

}

/** Builds an analyzer which removes words in the provided array. */

//提供独自的stopwords

public TjuChineseAnalyzer(String[] stopWords)

{

this.stopWords = StopFilter.makeStopSet(stopWords);

}

/** Filters LowerCaseTokenizer with StopFilter. */

public TokenStream tokenStream(String fieldName, Reader reader)

{

try

{

ICTCLAS splitWord = new ICTCLAS();

String inputString = FileIO.readerToString(reader);

//分词中间加入了空格

String resultString = splitWord.paragraphProcess(inputString);

System.out.println(resultString);

TokenStream result = new TjuChineseTokenizer(new StringReader(resultString));

result = new LowerCaseFilter(result);

//使用stopWords进行过滤

result = new StopFilter(result, stopWords);

//使用p-stemming算法进行过滤

result = new PorterStemFilter(result);

return result;

}

catch (IOException e)

{

System.out.println("转换出错");

return null;

}

}

public static void main(String[] args)

{

String string = "我爱中国人民";

Analyzer analyzer = new TjuChineseAnalyzer();

TokenStream ts = analyzer.tokenStream("dummy", new StringReader(string));

Token token;

System.out.println("Tokens:");

try

{

int n=0;

while ( (token = ts.next()) != null)

{

System.out.println((n++)+"->"+token.toString());

}

}

catch (IOException ioe)

{

ioe.printStackTrace();

}

}

}对于此程序的输出接口可以看一下

0->Token's (termText,startOffset,endOffset,type,positionIncrement) is:(爱,3,4,word,1)

1->Token's (termText,startOffset,endOffset,type,positionIncrement) is:(中国,6,8,word,1)

2->Token's (termText,startOffset,endOffset,type,positionIncrement) is:(人民,10,12,word,1)

OK,经过这样一番讲解,你已经对Lucene的Analysis包认识的比较好了,当然如果你想更加了解,还是认真读读源码才好,

呵呵,源码说明一切!

转载于:https://www.cnblogs.com/cy163/archive/2008/06/07/1215500.html

Lucene于搜索引擎技术(Analysis包详解)相关推荐

  1. lucene.NET详细使用与优化详解

    lucene.NET详细使用与优化详解 http://www.cnblogs.com/qq4004229/archive/2010/05/21/1741025.html http://www.shan ...

  2. 技术揭秘之详解回收站删除文件恢复

    |=------------------------------------------------------------------------=| |=--------------=[技术揭秘之 ...

  3. java me基础教程 pdf_Java ME手机应用开发技术与案例详解 PDF

    资源名称:Java ME手机应用开发技术与案例详解 PDF Java ME手机应用开发技术与案例详解基于Java ME,系统描述了Java ME手机应用开发的各个方面.全书按照Java ME程序的开发 ...

  4. <Zhuuu_ZZ>大数据技术之Flume详解

    大数据技术之Flume详解 一 Flume配置 Flume安装地址 环境配置 验证 二 Flume基础架构 1.定义 2.Flume组成架构 3.Flume组件 Agent Source Channe ...

  5. R语言机器学习之caret包详解(一)

    R语言机器学习caret包trainControl函数详解 R语言机器学习之caret包详解(一) 简介 数据预处理 各种数据变换 近零方差变量 创建虚拟变量 重抽样技术 k折交叉验证 留一交叉验证 ...

  6. scapy定制数据包详解

    今天继续给大家介绍渗透测试相关知识,本文主要内容是scapy定制数据包详解. 免责声明: 本文所介绍的内容仅做学习交流使用,严禁利用文中技术进行非法行为,否则造成一切严重后果自负! 一.scapy介绍 ...

  7. android jar 包 意见反馈功能,android重点jar包详解.docx

    android重点jar包详解 深入理解View(一):从setContentView谈起 我们都知道?MVC,在Android中,这个?V?即指View,那我们今天就来探探View的究竟.在onCr ...

  8. java axis2 jar_Java axis2.jar包详解及缺少jar包错误分析

    Java  axis2.jar包详解及缺少jar包错误分析 一.最小开发jar集 axis2 开发最小jar包集: activation-1.1.jar axiom-api-1.2.13.jar ax ...

  9. spring2.0和spring2.5及以上版本的jar包区别 spring jar 包详解

    spring jar 包详解 spring.jar是包含有完整发布的单个jar包,spring.jar中包含除了 spring-mock.jar里所包含的内容外其它所有jar包的内容,因为只有在开发环 ...

最新文章

  1. 人脸对齐--Face Alignment by Explicit Shape Regression
  2. Windows Forms Programming In C# 读书笔记 - 第三章 Dialogs
  3. html台风路径,常用气象网站功能简介
  4. 反向传播(Back propagation)算法推导具体过程
  5. 【每日一题】4月7日题目精讲 树
  6. python123第七周小测验_python+request+untitest的接口自动化测试
  7. 17.判断一个整数是否是回文数
  8. getdatatable mysql_C# 自定义MySqlHelp类,包含了获取DataTable的方法,但是调用时总是提示“类型初始值设定项引发异常”...
  9. 在线985,211高校查询
  10. mysql命令:set sql_log_bin=on/off
  11. 如何给网站添加支付宝支付功能
  12. 使用Bitvise SSH代理访问
  13. 如何在DOS系统下删除隐藏的文件
  14. 数据预处理--无量纲化
  15. 在centos上安装vmware14
  16. 【更新】关于VMware虚拟机无法正常获取IP地址问题的解决方法及思路
  17. matlab 一些函数的用法
  18. 秒杀99.99%大学生!看看清华的学霸到底有多牛?
  19. 如何检测家里的WIFI网络信号?
  20. 信号与系统填空题、简答题(应试)

热门文章

  1. [BEC][hujiang] Lesson02 Unit1:Working life ---Reading
  2. 加速你的Hibernate引擎(下)
  3. SMS部署操作系统后记
  4. 解决ufw下pptp客户端连接问题
  5. 大工18秋计算机文化基础在线测试2,大工18秋《计算机文化基础》在线测试2【答案】...
  6. sql累计求和时间太长_(七)SQL知识点--窗口函数
  7. Mongo集群分片部署实践(4.2版本)
  8. Mysql梳理(单表查询)
  9. bash脚本创建变量_创建一个Bash脚本模板
  10. es6 Class 的 name 属性