对于中国用户,最早遇到的棘手问题可能就是中文分词了。由于nutch对中文的支持默认是单字分词,所以很多人在一拿到nutch后要解决的第二件事情 (第一件事情当然是让nutch跑起来了)往往是要加入一个可行的中文分词模块。所以对这个包研究的人也是最多的,在网上关于nutch的中文分词的文章 也是人气很高的。那么就让我们一起来走近它看看它到底是怎么一回事,也让我们来做个中文分词器让中文在nutch上跑得更好。
首选一点, nutch的中文分词主要是在两个地方用到,一个是索引时,一个是在搜索时。由于nutch是基于lucene的,所以nutch的分词是继承 lucene的,所以基本原理大家就明白一二了。如果你对lucene不清楚请你先对它了解一下,不然在nutch里你是不能深入的。
在lucene里,它的分词模块抽象出来了一个抽象类--Analyzer.java。这个类包含这个抽象方法public abstract TokenStream tokenStream(String fieldName, Reader reader);用户自定义的Analyzer主要就是实现这个方法。这个方法要返回一个token流。而要返回一个分词的完成的token流又要写另一 个类的子类它就是--Tokenizer.java,而它又是继承自TokenStream.java的。用户自定义的Tokenizer类要写的一个关 键方法是next().这个方法就是返回一个个的中文词语。对于中文要进行完美的分词是有很大难度的,当然也有比较机械比较简单的方法比如二元分词。分词 算法对于中文是很重要也很复杂的,在这里三言两语也不能讲清楚。可以推荐大家试一下的是中科院的ICTCLAS,还有台湾一个人写的字典分词的jar包。 看了这些就知道其实lucene里的分词器是可以拿到nutch里用的了。在nutch的德语和法语的分词插件都是直接把lucene的分词器包装一下就 拿过来用了。所以你也可以试试中文的哦。
还有相关的概念:n-Grams
ngram的大意:
将输入的语料,分词成基本的单元,(可以用切词程序或者直接就是一个字)
a, b, c, d, e,......
然后按照相邻原则统计各种词出现的频度:
------------------------------------------
one gram :
a,
b,
c,
d,
e,
...
------------------------------------------
two gram :
ab,
bc,
cd,
de,
...
------------------------------------------
three gram :
abc,
bcd,
cde,
...
-------------------------------------------
设定频度阈值,除掉频度过低的新词
最后比照词库进行一定的过滤,得到可能的新词。
ngram的难度在于统计和甄别,统计的时候,往往是n倍于语料的大小,内存一次是装不下的,
甄别,如何最终判断一个词是否真的是新词,或者只是无意义的组合。
统计的时候可以用的 trick:
1. 对词组合,做签名, mod签名,每次只对签名的mod值相同的做统计。
2. 长度。
以上算是对nutch--Analysis包介绍前的背景知识。
在nutch里,默认的词汇分词和查询分析是用javacc--Java Compiler Compiler来 做的。javacc编译后会生气java代码,用生成的java代码来执行。所以它生成的代码是很难看懂的,因为是机器写的嘛。所以如果你要更好理解或想 改造nutch的默认分词模块,就得好好地学习一下javacc咯。Nutch是基于插件的,所以分词模块你可以很容易地自己加一个插件就可以了。就像前 面所说的那样就可以实现自己的中文分词了。
当然nutch自身的分词是相当高效和优秀的,如果你想在它的基础之上修改一个可以处理所有语言的分词器那就要把这个包里的代码好好研究研究了。
现在开始研究它的代码,在org.apache.nutch.analysis这个包里定义了nutch分析器的基本接口NutchAnalyzer
NutchDocumentAnalyzer这个类里面有两个子分析器AnchorAnalyzer和ContentAnalyzer。 AnchorAnalyzer是为锚文本专用的分析器,它是NutchDocumentAnalyzer的内部类,其实它也是 ContentAnalyzer,只是在域名为"anchor"时,加入了一个过滤器--AnchorFilter,它的作用就是设置这个类中定义的 INTER_ANCHOR_GAP(positionsIncreament是Token的一个属性,此处设为4,增加查询的模糊度)。另一个分器就是 ContentAnalyzer了,这个分析分两部分,一部分是过滤器--CommonGrams,k另一部分是切分器 NutchDocumentTokenizer。以下类图可以很清楚地把这个包内主要的几个类的关系展示出来了。而这其中由 NatchAnalysis.jj生成的文件有NutchAanlysisConstants,NutchAnalysisTokenManager, NutchAnalysis。在lucene里一个分词器包括两部分,一个analyzer一个tokenizer。同样在nutch里也是一致的,所以 在这的默认分词器由NutchDocumentAnalyzer和NutchDocumentTokenizer两部分组成,由类图也可以看出来。另外在 NutchDocumentAnalyzer里有一个常用gram的过滤器。
JavaCC是一个java语言分析器,就是按照“模版”,“装配”不同的语言分析程序的源代码。 复杂语言的语法通常都是使用 BNF(巴科斯-诺尔范式,Backus-Naur Form)表示法或者其“近亲”― EBNF(扩展的 BNF)描述的。自动化工具可以使用那些描述(我将使用通用的术语 BNF来 指代这两种变体)或与它们近似的描述来为你生成解析代码。另外上图还有两个类CharStream(接口)和FastCharStream(实现类), CharStream是javaCC的输入接口,但FastCharStream不作行号计数,却保存着在输入(input)中Token内的位置信息, 这也是lucene要求的。还有一个类需要介绍的是AnalyzerFactory,这个是nutch和插件体系配合的工厂类,用于得到一个分词器。
转自:http://blog.csdn.net/kauu/archive/2007/10/23/1839705.aspx 作者:吴志敏