replace the default Tokenizer of carrot2 lingo filter with ICTCLAS |
nutch (0.7 release) 中的clustering plugin 采用的是Dawid Weiss 主持開(kāi)發(fā)的carrot2,主要用到了其中的local controller 和 lingo filter 兩個(gè) compenent。lingo filter 缺省的Tokenizer (com.stachoodev.carrot.filter.lingo.tokenizer.Tokenizer)缺乏對中文的分詞處理,這使得用這個(gè)filter 處理中文結果時(shí)效果往往不很讓人滿(mǎn)意!于是開(kāi)始為nutch 選擇合適的中文分詞模塊,經(jīng)過(guò)一周左右的挑選、分析和比較,最終決定采用中國科學(xué)院計算技術(shù)研究所漢語(yǔ)詞法分析系統——ICTCLAS。
接下來(lái)用了一周多的學(xué)習和練習:
經(jīng)過(guò)一周多的時(shí)間終于用ICTCLAS 調換掉了lingo filter 缺省的 Tokenizer (com.stachoodev.carrot.filter.lingo.tokenizer.Tokenizer) :*)
nutch (0.7 release) 中carrot2 的版本略低于carrot2 官方網(wǎng)站對外公布的版本。
swith on the clustering plugin of nutch |
the following works for the 0.7 release
edit $NUTCH_HOME/WEB-INF/classes/nutch-default.xml
<property> <name>plugin.includes</name> <value>clustering-carrot2|protocol-httpclient|urlfilter-regex|parse-(text|html|js)|index-basic|query-(basic|site|url)</value> ... </property> <property> <name>extension.clustering.extension-name</name> <value>Carrot2-Lingo</value> ... </property> Carrot2-Lingo: see $NUTCH_HOME/plugins/clustering-carrot2/plugin.xml for detail.
Now, it‘s ok! add an parameter ‘clustering=yes‘ onto your search url and try it.
hack NutchAnalysis.jj further so as to perform third-part segmentation |
下面是我想到的一個(gè)蹩腳方法,之所以說(shuō)這個(gè)方法蹩腳是因為它在執行切分過(guò)程中產(chǎn)生了 sizeof(tokens[])次input_stream.backup(1) 操作和副作用:-(。但這個(gè)方法也還是有些可取之處的——把不同語(yǔ)言的切分工作交給不同的Tokenizer 去處理,這樣可以產(chǎn)生比較好的細粒度切分效果。
org.apache.nutch.analysis.NutchAnalysis.jj
@@ -33,6 +33,7 @@import org.apache.nutch.searcher.Query.Clause;import org.apache.lucene.analysis.StopFilter;+import org.apache.lucene.analysis.cjk.CJKTokenizer;import java.io.*;import java.util.*;@@ -81,6 +82,14 @@PARSER_END(NutchAnalysis)TOKEN_MGR_DECLS : {+ /** use CJKTokenizer to process cjk character */+ private CJKTokenizer cjkTokenizer = null;++ /** a global cjk token */+ private org.apache.lucene.analysis.Token cjkToken = null;++ /** start offset of cjk sequence */+ private int cjkStartOffset = 0;/** Constructs a token manager for the provided Reader. */public NutchAnalysisTokenManager(Reader reader) {@@ -106,7 +115,46 @@}// chinese, japanese and korean characters-| <SIGRAM: <CJK> >+| <SIGRAM: (<CJK>)+ >+ {+ /**+ * use an instance of CJKTokenizer, cjkTokenizer, hold the maximum+ * matched cjk chars, and cjkToken for the current token;+ * reset matchedToken.image use cjkToken.termText();+ * reset matchedToken.beginColumn use cjkToken.startOffset();+ * reset matchedToken.endColumn use cjkToken.endOffset();+ * backup the last char when the next cjkToken is valid.+ */+ if(cjkTokenizer == null) {+ cjkTokenizer = new CJKTokenizer(new StringReader(image.toString()));+ cjkStartOffset = matchedToken.beginColumn;+ try {+ cjkToken = cjkTokenizer.next();+ } catch(IOException ioe) {+ cjkToken = null;+ }+ }++ if(cjkToken != null && !cjkToken.termText().equals("")) {+ //sometime the cjkTokenizer returns an empty string, is it a bug?+ matchedToken.image = cjkToken.termText();+ matchedToken.beginColumn = cjkStartOffset + cjkToken.startOffset();+ matchedToken.endColumn = cjkStartOffset + cjkToken.endOffset();+ try {+ cjkToken = cjkTokenizer.next();+ } catch(IOException ioe) {+ cjkToken = null;+ }+ if(cjkToken != null && !cjkToken.termText().equals("")) {+ input_stream.backup(1);+ }+ }++ if(cjkToken == null || cjkToken.termText().equals("")) {+ cjkTokenizer = null;+ cjkStartOffset = 0;+ }+ }例子中所用的CJKTokenizer 取自Weblucene
關(guān)鍵詞:nutch, segmentation, chinese, cjk
參考:
hack NutchAnalysis.jj so as to perform bi-gram segmentation |
109,110c109,112< | <SIGRAM: <CJK> ><---> | <SIGRAM: <CJK><CJK> >> {> input_stream.backup(1);> }簡(jiǎn)單測試一下效果:
$ echo $LANG
en_US.UTF-8
$ LANG=zh_CN
$ ./bin/nutch org.apache.nutch.analysis.NutchDocumentTokenizerText: 克己服人,禮智謙讓
Tokens: 克己 己服 服人 禮智 智謙 謙讓
Text: 中華人民共和國
Tokens: 中華 華人 人民 民共 共和 和國
Text: 中文&English&英文
Tokens: 中文 &english& 英文
Text: 寫(xiě)這些內容的時(shí)候,作者運行的是nutch 的0.7 release;如果你運行的是nutch 的其他版本,那么下面的內容可能并不適合你:
Tokens: 寫(xiě)這 這些 些內 內容 容的 的時(shí) 時(shí)候 作者 者運 運行 行的 的是 nutch 0 7 release 如果 果你 你運 運行 行的 的是 nutch 的其 其他 他版 版本 那么 么下 下面 面的 的內 內容 容可 可能 能并 并不 不適 適合 合你
關(guān)鍵詞: nutch, segmentation, chinese, cjk, bi-gram
參考:
understand the tokenizer of nutch |
注:寫(xiě)這些內容的時(shí)候,作者運行的是nutch 的0.7 release;如果你運行的是nutch 的其他版本,那么下面的內容可能并不適合你:*)
$ echo $LANG
en_US.UTF-8
$ LANG=zh_CN
$ ./bin/nutch org.apache.nutch.analysis.NutchDocumentTokenizerText: I.B.M.
Tokens: ibm
Text: I.B.M
Tokens: ib m
Text: AT&T
Tokens: at&t
Text: AT_T
Tokens: at_t
Text: 中華人民共和國
Tokens: 中 華 人 民 共 和 國
Text: 中文&English&英文
Tokens: 中 文 &english& 英 文
為什么會(huì )有這種切分效果呢?看看下面的 org.apache.nutch.analysis.NutchAnalysis.jj 文件片斷也許就能明白了:
TOKEN : {// token regular expressions// basic word -- lowercase it<WORD: ((<LETTER>|<DIGIT>|<WORD_PUNCT>)+ | <IRREGULAR_WORD>)> { matchedToken.image = matchedToken.image.toLowerCase(); }// special handling for acronyms: U.S.A., I.B.M., etc: dots are removed| <ACRONYM: <LETTER> "." (<LETTER> ".")+ > {// remove dots for (int i = 0; i < image.length(); i++) { if (image.charAt(i) == ‘.‘) image.deleteCharAt(i--); } matchedToken.image = image.toString().toLowerCase(); }// chinese, japanese and korean characters| <SIGRAM: <CJK> >// irregular words| <#IRREGULAR_WORD:(<C_PLUS_PLUS>|<C_SHARP>)>......當前的tokenizer 把單個(gè)的CJK 字符當成了一個(gè)完整的Token—— 并未對連續的CJK 字符做切分詞處理,于是就出現了上面的結果。
crawl-urlfilter.txt vs. regex-urlfilter.txt in nutch |
注:寫(xiě)這些內容的時(shí)候,作者運行的是nutch 的0.7 release;如果你運行的是nutch 的其他版本,那么你可能需要自己去分析二者的區別:*)
首先有一種說(shuō)法是:crawl-urlfilter.txt 是供intranet 抓取用的,而regex-urlfilter.txt 是供internet 抓取用的——因為兩者抓取的重點(diǎn)不同,從而導致過(guò)濾規則不同。如果你只是想知道兩者的簡(jiǎn)單區別的話(huà),那么看到這里也就可以了,但是如果你想知道更多細節那么下面的內容還是值得一看的:)
crawl-urlfilter.txt 和 regex-urlfilter.txt 都是用來(lái)保存過(guò)濾url 的正則表達式的。類(lèi) RegexURLFilter(org.apache.nutch.net.RegexURLFilter) 通過(guò) NutchConf.get().get("urlfilter.regex.file") 來(lái)從中(當然如果你裝載了其他配置文件的話(huà),也可能有其他的候選者)進(jìn)行選擇。
regex-urlfilter.txt 是 urlfilter.regex.file 屬性的缺省值(1),定義在 $NUTCH_JAVA_HOME/conf/nutch-default.xml(如果你設置了環(huán)境變量NUTCH_CONF_DIR 的話(huà),那就是 $NUTCH_CONF_DIR/nutch-default.xml)中。該值可以被后續加載的配置文件所覆蓋,例如如果你裝載了類(lèi) CrawlTool(org.apache.nutch.tool.CrawlTool),那么缺省值就會(huì )被 crawl-tool.xml 中的urlfilter.regex.file 屬性覆蓋(2)。也就是說(shuō),如果你在操作過(guò)程中調用了類(lèi)CrawlTool,那么類(lèi)RegexURLFilter 將會(huì )采用crawl-tool.xml 中指定的文件,否則就用缺省的文件。
當然如果nutch-site.xml 中也定義了urlfilter.regex.file 屬性的話(huà),那么 NutchConf.get().get("urlfilter.regex.file") 返回的值就以nutch-site.xml 所指定的值為準。(關(guān)于nutch 的resource chain)
注:(1)NutchConf 初始化時(shí)會(huì )裝載nutch-default.xml 和nutch-site.xml
public class NutchConf {...... public NutchConf() { resourceNames.add("nutch-default.xml"); resourceNames.add("nutch-site.xml"); }......}(2)裝載類(lèi)CrawlTool 時(shí),crawl-tool.xml 會(huì )被插入到resource chain 中public class CrawlTool {...... static { NutchConf.get().addConfResource("crawl-tool.xml"); }......}參見(jiàn): hack URLFilters so as to test RegexURLFilter |
public static void main(String args[]) throws IOException, MalformedPatternException, Exception { BufferedReader in=new BufferedReader(new InputStreamReader(System.in)); String line; while((line=in.readLine())!=null) { String out=URLFilters.filter(line); if(out!=null) { System.out.print("+"); System.out.println(out); } else { System.out.print("-"); System.out.println(line); } }}這樣測試url filter rule 就方便多了:)$ ./bin/nutch org.apache.nutch.net.URLFilters......http://www.lhelper.org/blog/using fitler 0:org.apache.nutch.net.RegexURLFilter+http://www.lhelper.org/blog/http://www.lhelper.org/blog/?q=lhelperusing fitler 0:org.apache.nutch.net.RegexURLFilter-http://www.lhelper.org/blog/?q=lhelper
聯(lián)系客服