ansj源码浅析1

来源:互联网 发布:全球数据交换中心 编辑:程序博客网 时间:2024/06/05 15:20

开始之前先盗个图,下图是lucene分词结构的类关系图,可以看出所有的分词流都是基于TokenStream来做的。它下面有两个继承类,一个是

来分词的(Tokenizer),一个是来过滤的(TokenFilter)。我们主要来分析分词的类。

ansj分词器的构造函数如下

public AnsjTokenizer(Analysis ta,String stopwordsDir, boolean pstemming) {this.ta = ta;this.pstemming = pstemming;}

这里面ta是比较重要的。ansj常用的是IndexAnalysis。回到AnsjTokenizer,这个类的核心方法如下

public final boolean incrementToken() throws IOException {clearAttributes();int position = 0;Term term = null;String name = null;int length = 0;boolean flag = true;do {term = ta.next();<span></span>//利用Analysis获取下一个termif (term == null) {break;}name = term.getName();length = name.length();if (pstemming && term.termNatures() == TermNatures.EN) {name = stemmer.stem(name);term.setName(name);}if (filter != null && filter.contains(name)) {continue;} else {position++;flag = false;}} while (flag);if (term != null) {positionAttr.setPositionIncrement(position);termAtt.setEmpty().append(term.getName());offsetAtt.setOffset(term.getOffe(), term.getOffe() + length);return true;} else {return false;}}
下面看看Analysis的next函数

public Term next() throws IOException {Term term = null;if (!terms.isEmpty()) {<span></span>//当前terms不为空则直接返回第一个termterm = terms.poll();term.updateOffe(offe);return term;}String temp = br.readLine();<span></span>//当前terms为空,则需要从输入流中读出下一条数据offe = br.getStart();while (StringUtil.isBlank(temp)) {<span></span>//判断当前的读入是否为空,若是则继续读入下一条if (temp == null) {return null;} else {temp = br.readLine();}}// 歧异处理字符串analysisStr(temp);<span></span>//利用temp构造termsif (!terms.isEmpty()) {term = terms.poll();term.updateOffe(offe);return term;}return null;}
下面继续看analysisStr(temp)

private void analysisStr(String temp) {Graph gp = new Graph(temp);<span></span>//构造分词图int startOffe = 0;if (this.ambiguityForest != null) {<span></span>//将近义词加入图GetWord gw = new GetWord(this.ambiguityForest, gp.chars);String[] params = null;while ((gw.getFrontWords()) != null) {if (gw.offe > startOffe) {analysis(gp, startOffe, gw.offe);}params = gw.getParams();startOffe = gw.offe;for (int i = 0; i < params.length; i += 2) {gp.addTerm(new Term(params[i], startOffe, new TermNatures(new TermNature(params[i + 1], 1))));startOffe += params[i].length();}}}if (startOffe < gp.chars.length - 1) {analysis(gp, startOffe, gp.chars.length);}List<Term> result = this.getResult(gp);<span></span>//根据图得到分词后的term集合terms.addAll(result);<span></span>//将temp分出的所有term加入}

这里的graph主要是把句子根据词典切分构成一个有向完全图。这里会将用户定义的近义词加入图的对应位置,以方便分词。下面盗一张别人的图来看看:

图1是没加入近义词的图,图2是加入近义词的图。



接下来的List<Term> result = this.getResult(gp);就会通过图选一条最优路径,并把路径上所有的term得到加入terms数组。并返回给上层调用。至此一句话的分词过程就结束了。

这里,这里面图的构造涉及的算法比较复杂,getResult涉及的东西也比较多,接下来一篇我们来进行分析。



有不对的地方请不吝指正,谢谢





0 0
原创粉丝点击