文本分析器Analyzer原理及常用Analyzer的功能

Analyzer,或者说文本分析的过程,实质上是将输入文本转化为文本特征向量的过程。这里所说的文本特征,可以是词或者是短语。它主要包括以下四个步骤:
  • 分词,将文本解析为单词或短语
  • 归一化,将文本转化为小写
  • 停用词处理,去除一些常用的、无意义的词
  • 提取词干,解决单复数、时态语态等问题

Lucene Analyzer包含两个核心组件,Tokenizer以及TokenFilter。两者的区别在于,前者在字符级别处理流,而后者则在词语级别处理流。Tokenizer是Analyzer的第一步,其构造函数接收一个Reader作为参数,而TokenFilter则是一个类似拦截器的东东,其参数可以使TokenStream、Tokenizer,甚至是另一个TokenFilter。整个Lucene Analyzer的过程如下图所示:



上图中的一些名词的解释如下表所示:
说明
Token表示文中出现的一个词,它包含了词在文本中的位置信息
Analyzer将文本转化为TokenStream的工具
TokenStream文本符号的流
Tokenizer在字符级别处理输入符号流
TokenFilter在字符级别处理输入符号流,其输入可以是TokenStream、Tokenizer或者TokenFilter



Lucene Analyzer中,Tokenizer和TokenFilter的组织架构如下图所示:



Lucene提供了数十种内置的Tokenizer、TokenFilter以及Analyzer供开发人员使用,事实上大部分时候我们只会需要使用其中的某几种,比如标准分词器StandardTokenizer、空格分词器WhitespaceTokenizer、转化为小写格式的LowCaseFilter、提取词干的PoterStemFilter以及组合使用StandardTokenizer和多种TokenFilter的StandardAnalyzer,有关这些的资料网上很多了,这里就不再详细介绍了。

有些时候,Lucene内置提供的Analyzer或许不能满足我们的需求。下面一个例子叙述了如何使用定制的Analyzer。它的功能是提取词干、将输入规范化为小写并且使用指定的停用词表: 

 

public class PorterStemStopWordAnalyzer extends Analyzer {
	public static final String[] stopWords = { "and", "of", "the", "to", "is",
			"their", "can", "all", "i", "in" };

	public TokenStream tokenStream(String fieldName, Reader reader) {
		Tokenizer tokenizer = new StandardTokenizer(reader);
		TokenFilter lowerCaseFilter = new LowerCaseFilter(tokenizer);
		TokenFilter stopFilter = new StopFilter(lowerCaseFilter, stopWords);
		TokenFilter stemFilter = new PorterStemFilter(stopFilter);
		return stemFilter;
	}

	public static void main(String[] args) throws IOException {
		Analyzer analyzer = new PorterStemStopWordAnalyzer();
		String text = "Holmes, who first appeared in publication in 1887, was featured in four novels and 56 short stories. The first story, A Study in Scarlet, appeared in Beeton's Christmas Annual in 1887 and the second, The Sign of the Four, in Lippincott's Monthly Magazine in 1890. The character grew tremendously in popularity with the beginning of the first series of short stories in Strand Magazine in 1891; further series of short stories and two novels published in serial form appeared between then and 1927. The stories cover a period from around 1880 up to 1914.";
		Reader reader = new StringReader(text);
		TokenStream ts = analyzer.tokenStream(null, reader);
		Token token = ts.next();
		while (token != null) {
			System.out.println(token.termText());
			token = ts.next();
		}

	}
}


从结果我们可以看出:
  • StandardTokenizer将文本按照空格或标点分成词语
  • LowerCaseFilter所有的输入都被转化为小写
  • StopFilter消除了文中的停用词,比如"appeared between then and 1927"中的"and"
  • PorterStemFilter提取了文中的词根,比如story和stories都被转化为stori



之后的文章,会介绍一下如何在这个个Analyzer中引入短语检测和同义词检测。

=====================================================================================================

下面看一下lucene 中常用Analyzer的使用及作用:

package cn.zqh.lucene.analyzer;

import java.io.IOException;
import java.io.StringReader;

import jeasy.analysis.MMAnalyzer;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.SimpleAnalyzer;
import org.apache.lucene.analysis.Token;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.cjk.CJKAnalyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.junit.Test;

/**   **/
public class AnalyzerTest {

String text="IndexWriter addDocument's a javadoc.txt";
String zhText="我们是中国人";

Analyzer an1 = new StandardAnalyzer();//支持英文分词器
Analyzer an2 = new SimpleAnalyzer(); //支持英文 点 分词器
Analyzer an3 = new CJKAnalyzer();   //二分法分词
Analyzer an4 = new MMAnalyzer();     //词库分词 使用词库分词时要导入je-analyzer-1.5.1jar

@Test
public void test() throws IOException{
   //analyzer(an2,text);
   analyzer(an4,zhText);
}

public void analyzer(Analyzer analyzer,String text) throws IOException{
 
   System.out.println("----当前使用的分词器-------"+analyzer.getClass());
   System.out.println("----------被分词的文本---"+text);
   System.out.println("----------分词后如下---");
   TokenStream tokenStream = analyzer.tokenStream("content", new StringReader(text));
   for(Token token = new Token();(token =tokenStream.next()) !=null; ){
    System.out.println(token);
   }
}

/**
* 打印结果:
*     an1分词器:
    ----当前使用的分词器-------class org.apache.lucene.analysis.standard.StandardAnalyzer
    ----------被分词的文本---IndexWriter addDocument's a javadoc.txt
    ----------分词后如下---
    (indexwriter,0,11,type=<ALPHANUM>)
    (adddocument,12,25,type=<APOSTROPHE>)
    (javadoc.txt,28,39,type=<HOST>)
    
     an2分词器:
     ----当前使用的分词器-------class org.apache.lucene.analysis.SimpleAnalyzer
    ----------被分词的文本---IndexWriter addDocument's a javadoc.txt
    ----------分词后如下---
    (indexwriter,0,11)
    (adddocument,12,23)
    (s,24,25)
    (a,26,27)
    (javadoc,28,35)
    (txt,36,39)
  
    an1分词器,zhText
     ----当前使用的分词器-------class org.apache.lucene.analysis.standard.StandardAnalyzer
    ----------被分词的文本---我们是中国人
    ----------分词后如下---
    (我,0,1,type=<CJ>)
    (们,1,2,type=<CJ>)
    (是,2,3,type=<CJ>)
    (中,3,4,type=<CJ>)
    (国,4,5,type=<CJ>)
    (人,5,6,type=<CJ>)
  
    an3分词器:zhText
     ----当前使用的分词器-------class org.apache.lucene.analysis.cjk.CJKAnalyzer
    ----------被分词的文本---我们是中国人
    ----------分词后如下---
    (我们,0,2,type=double)
    (们是,1,3,type=double)
    (是中,2,4,type=double)
    (中国,3,5,type=double)
    (国人,4,6,type=double)
  
    an4分词器:zhText
    ----当前使用的分词器-------class jeasy.analysis.MMAnalyzer
    ----------被分词的文本---我们是中国人
    ----------分词后如下---
    (我们,0,2)                       解释:从0开始到第2个字符(不包含2) 0/1
    (中国人,3,6)                          从3开始到第六个字符

  
    */
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值