Lucene与中文分词

Lucene中的Analyzer

处理英文的流程

  • WhitespaceTokenizer

  •      空格分隔

  • WordDelimiterFilter

  •      对单词进一步分隔

  •      同时合并单词(catenateWords参数)

  • LowercaseFilter

  •      小写化

Lucene与中文分词_第1张图片

实现代码如下:

public class MyAnalyzer extends Analyzer {
  @Override
  public TokenStream tokenStream(String fieldName, Reader reader) {
  //以空格方式切分Token
  TokenStream stream = new WhitespaceTokenizer(reader);
  //删除过短或过长的词,例如 in、of、it
  stream = new LengthFilter(stream, 3, Integer.MAX_VALUE);
  //给每个词标注词性
  stream = new PartOfSpeechAttributeImpl.PartOfSpeechTaggingFilter(stream);
  return stream;
  }
}

//Attribute 接口是基本属性接口,定义一个词性的接口
public interface PartOfSpeechAttribute extends Attribute {
/*
 * 用枚举类型定义词的词性
 */
public static enum PartOfSpeech {
  Noun, Verb, Adjective, Adverb, Pronoun, Preposition, Conjunction, Article, Unknown
}
§ // setter
public void setPartOfSpeech(PartOfSpeech pos);
§ // getter
public PartOfSpeech getPartOfSpeech();
}

PartOfSpeechTaggingFilter:

public static class PartOfSpeechTaggingFilter extends TokenFilter {
  PartOfSpeechAttribute posAtt;
  TermAttribute termAtt;
  public PartOfSpeechTaggingFilter(TokenStream input) {
  super(input);
  posAtt = addAttribute(PartOfSpeechAttribute.class);
  termAtt = addAttribute(TermAttribute.class);
  }
  public boolean incrementToken() throws IOException {
  if (!input.incrementToken()) {
  return false;
  }
  posAtt.setPartOfSpeech(determinePOS(termAtt.termBuffer(), 0,
  termAtt.termLength()));
  return true;
  }
  //判断term的词性
  protected PartOfSpeech determinePOS(char[] term, int offset, int length) {
  // naive implementation that tags every uppercased word as noun
  if (length > 0 && Character.isUpperCase(term[0])) {
  return PartOfSpeech.Noun;
  }
  return PartOfSpeech.Unknown;
  }
}

PerFieldAnalyzerWrapper:

    不同的索引列切分方式可能不一样。为了对不同的索引列使用不同的分析器,可以使用PerFieldAnalyzerWrapper。在PerFieldAnalyzerWrapper中,可以指定一个缺省的分析器,也可以通过addAnalyzer方法对不同的列使用不同的分析器。例如:

PerFieldAnalyzerWrapper aWrapper = new PerFieldAnalyzerWrapper(new CnAnalyzer());

//地址列使用AddAnalyzer 

aWrapper.addAnalyzer("address", new AddAnalyzer());

//公司名称列使用CompanyAnalyzer 

aWrapper.addAnalyzer("companyName", new CompanyAnalyzer());

为什么要分词:

l中文分词是理解中文的第一步

中文分词就是对中文断句,这样能消除文字的部分歧义

有个笑话:请用“天真”造句。

天真冷啊。今天天真蓝。


l分词的任务

分词:把输入的标题或者文本内容等分成词。

词性标注(POS):给分出来的词标注上名词或动词等词性。

语义标注:把每个词标注上语义编码。

分词:

l索引内容分词

切分标题列:中国一重|n  利润|n  骤减|v  有|v  玄机|n 

切分内容列:嫩江|ns  西岸|s  的|uj  富拉尔基|ns  ,|w  距离|n  齐齐哈尔市|ns  中心|n  城区|n  37|m  公里|q  。|w 

切分公司名:艾博/关键词 (国际)/行政区划 塑胶/行业词 进出口有限公司/功能词

切分地址:广西/省 南宁市/市 青秀区/区 安湖路/街道 1号/号 新锐大厦/地标建筑

切分电话号码:0371/区位号  63949884/尾号


词性标注:

词性标注可以部分消除词的歧义,例如“行”作为量词和作为形容词表示的意思不一样。

标注的类型有

l小标注集(40类左右)

l大标注集(最多可到100类左右)

小标注集代词都归为一类,大标注集可以把代词进一步分成三类:

l人称代词:你 我 他 它 你们 我们 他们

l疑问代词:哪里  什么  怎么 

l指示代词:这里 那里  这些  那些

Lucene与中文分词_第2张图片

语义:


l一词多义

  • 苹果:电脑、水果

  • 黑莓:手机、水果


l一义多词

  • 大豆、黄豆

  • 西红柿、番茄

  • 宾馆、酒店


语义标注:

l同义词词林语义编码

用树型结构表示了词的同义和上下位关系

把词汇分成大、中、小三类,大类有12个,中类有97个,小类有1,400个。例如A大类代表人、B大类代表物

Bp31B 表

Bp31B01= 表 手表

Bp31B02= 马表 跑表 停表

Bp31B03= 怀表 挂表

Bp31B04= 防水表 游泳表

Bp31B05= 表针 指针

Bp31B06= 表盘 表面

l语义标注示例:

  • 例子:我们伟大祖国在新的一年

  • 标注结果:我们/r/Aa02B01 伟大/a/Ed20A01 祖国/n/Di02A18 在/p/Jd01A01 新/a/Eb28A01 的/u/Kd01A01 一/m/Dn04A02 年/q/Ca18A01 ,/w/Dk04D02

中文分词的基本原理:

l机械匹配的方法

  • 正向最大长度匹配(Forward Maximum Match)的方法

  • 逆向最大长度匹配(Reverse Maximum Matching)的方法


l 统计的方法

  • 语言模型的分词方法

  • 条件随机场分词方法、最大熵隐马尔科夫模型等

正向最大长度匹配:

l词典

大  大学   大学生   活动   生活   中   中心  心 


l输入:“大学生活动中心”,首先匹配出“大学生”,然后匹配出“活动”,最后匹配出“中心”。切分过程如下:

Lucene与中文分词_第3张图片


正向最大长度匹配实现:

public void wordSegment(String content)//传入一个字符串作为要处理的对象
{
  int senLen = content.length();//首先计算出传入的这句话的字符长度
  int i=0;//控制匹配的起始位置
  
  while(i < senLen)//如果i小于此句话的长度就继续匹配
  {
  String word = dic.matchLong(content, i);//正向最大长度匹配
  if(word!=null)//已经匹配上
  {
  //下次匹配点在这个词之后
  i += word.length();
  //如果这个词是词库中的那么就打印出来
  System.out.print(word + " ");
  }
  else//如果在词典中没有找到匹配上的词,就按单字切分
  {
  word = content.substring(i, i+1);
  //打印一个字
  System.out.print(word + " ");
  ++i;//下次匹配点在这个字符之后
  }
  }
}



你可能感兴趣的:(中文分词,luence)