当前位置: 代码迷 >> Eclipse >> eclipse+nutch-1.2+IKAnalyzer汉语言分词
  详细解决方案

eclipse+nutch-1.2+IKAnalyzer汉语言分词

热度:449   发布时间:2016-04-23 01:09:24.0
eclipse+nutch-1.2+IKAnalyzer中文分词

?

nutch-1.2导入到eclipse中运行

以手动的方式将nutch的源代码导入eclipse中,可以使目录更清晰。具体步骤如下:

1.eclipse中新建立一个Java Project. 名字自己定义(Nutch)。选择"Create New project in WorkSpace".点击完成。

2.将解压后的nutch目录下的\src\java\中的代码全部复制到新建工程中的src下。

将解压后的nutch目录下的libpluginsconf三个文件夹复制到新建工程的根目录下(与src同级)

3.右键工程properties, 切换到"Libraries"选择"Add Class Folder..." 按钮,从列表中选择"conf"。将 conf加入到classpath中。点击Add External JARs

选择工程里lib下的所有jar包,打开。

4.修改配置

?

nutch的安装目录下建立一个名为urls的文件夹(与src同级),并在文件夹下新建url.txt文件在文件中写入:http://www.sohu.com/(即要抓取网站的网址,注意最后要加斜杠)。

?

设置网站过滤规则。
编辑conf/crawl-urlfilter.txt文件,修改MY.DOMAIN.NAME部分。

# accept hosts in MY.DOMAIN.NAME
+^http://([a-z0-9]*\.)*MY.DOMAIN.NAME/
改为:
# accept hosts in MY.DOMAIN.NAME
+^http://([a-z0-9]*\.)*sohu.com/

?

设置代理信息。
编辑conf/nutch-site.xml文件。在<configuration></configuration>之间添加如下内容:

<property>

<name>http.agent.name</name>

<value>http://www.sohu.com/</value>

</property>

<property>

<name>http.agent.url</name>

<value>http://www.sohu.com/</value>

</property>

<property>

<name>http.robots.agents</name>

<value>http://www.sohu.com/</value>

</property>

?

设置代理名
编辑nutch-1.2\conf\nutch-default.xml文件,找<name>http.agent.name</name>,然后随便设置Value值。

<property>

<name>plugin.folders</name>

<value> ./plugins</value><!—这里路径变了时间-->

要成功运行程序cygwin必须在电脑上已经成功安装,关于cygwin的安装上“Win7环境下配置nutch-1.2已经详细讲述,这里不再赘述

?

右键单击项目debug asdebug configurations在左侧选中New_configurationargumentsProgram arguments 填写如下参数crawl urls -dir crawled -depth 4 -threads 3 -topN 30? 为防止内存溢出VM arguments中填写 -Xms800m -Xmx800mdebug 程序开始运行(爬虫爬取)

控制台出现crawl finished: crawled

nutch项目里就会生成一个文件夹crawled,爬取完成,索引建立成功

?

nutch添加中文分词功能IKAnalyzer中文分词

到此并没有大功告成,因为原版nutch自身所带分词只支持英文分词,对中文的处理是按字划分,而不是按词划分,我们可以为其添加一些中文分词插件,例如IKAnalyzer、庖丁分词等。

首先作以下几点说明,以方便理解:

1)目前,Nutch中文分词方式大致有两种方式:
一是修改源代码:这种方式是直接对Nutch分词处理类进行修改,调用已写好的一些分词组件进行分词。
二是编写分词插件。这种方式是按照Nutch定义的插件编写规则重新编写或者添加中文分词插件。

2NutchAnalysis.jj文件用于搜索时;NutchDocumentAnalyzer.java 用于索引时。

3)用到了javaccant两种工具。javacc用于编译NutchAnalysis.jj文件,该文件最好拷贝到其它目录编译,编译后再把生成的7个文件拷贝回原目录,如果在原目录下编译的话只会生成4个文件。

4build.xml文件是ant的配置文件

5antjavacc工具的使用方法类似,解压后把bin目录的路径加到系统目录(path)中,重启计算机即可。详看:AntJavacc 等安装与使用

?

?

?

?

?

下面是具体过程:

一、准备工作:

IKAnalyzer3.2.8.jar文件拷入nutch/lib目录下,并加到classpath

二、代码修改:

1. NutchAnalysis.jj

nutch/src/java/org/apache/nutch/analysis目录

在该文件里找到 | <SIGRAM: <CJK> >,这代表按字划分,修改为 | <SIGRAM: (<CJK>)+ >

javacc工具生成NutchAnalysis.jj的源代码,将生成的所有java源代码(7个文件)全部覆盖到 src/java/org/apache/nutch/analysis包下.

javacc的使用方法:cmd进入命令行,切换到NutchAnalysis.jj所在目录(最后把它拷贝到其它目录进行编译,如D盘),D:,输入命令

javacc NutchAnalysis.jj

就会生成7个文件了。

?

2.修改 NutchAnalysis.java

org/apache/nutch/analysis

1)在import区域加入下面的代码

import org.wltea.analyzer.lucene.IKTokenizer;
2)在两个位置加入ParseException异常捕捉命令,否则ant时会提示。下面的代码已经添加

public static Query parseQuery(String queryString, Configuration conf) throws IOException,ParseException {

??? return parseQuery(queryString, null, conf);

? }

public static Query parseQuery(String queryString, Analyzer analyzer, Configuration conf)

??? throws IOException,ParseException {

??? NutchAnalysis parser = new NutchAnalysis(

????????? queryString, (analyzer != null) ? analyzer : new NutchDocumentAnalyzer(conf));

??? parser.queryString = queryString;

??? parser.queryFilters = new QueryFilters(conf);

??? return parser.parse(conf);

? }

如果其他地方出现抛异常错误要及时catch

?

3. NutchDocumentAnalyzer.java

1)引入IK

import org.wltea.analyzer.lucene.IKAnalyzer;
import org.apache.lucene.analysis.tokenattributes.*;

2)修改public TokenStream tokenStream(String fieldName, Reader reader) {函数为:

public TokenStream tokenStream(String fieldName, Reader reader) {

?? /* Analyzer analyzer;

??? if ("anchor".equals(fieldName))

????? analyzer = ANCHOR_ANALYZER;

??? else

????? analyzer = CONTENT_ANALYZER;

??? return analyzer.tokenStream(fieldName, reader);

??? */

?? ?Analyzer analyzer = new org.wltea.analyzer.lucene.IKAnalyzer();

????? TokenStream tokenStream = analyzer.tokenStream(fieldName, reader);

????? tokenStream.addAttribute(TypeAttribute.class);

????? tokenStream.addAttribute(FlagsAttribute.class);

????? tokenStream.addAttribute(PayloadAttribute.class);

????? tokenStream.addAttribute(PositionIncrementAttribute.class);

?? return tokenStream;

? }

?

如果要将nutch源文件夹下的nutch-1.2.war导入到eclipse下运行,进行搜索,则用eclipse重新将nutch生成jar包,替换nutch-1.2下的nutch-1.2.jar,并将IKAnalyzer3.2.8.jar包放到其lib里加入classpath里。

?

到此离成功还有一步之遥,我们在搜索的时候会发现有些关键字无法正常搜索,那是因为nutch建立索引的时候出现了词元交叉充电的原因,我们要解决这一问题。

?

由于Nutch不是原生支持中文的,开发者没有考虑到中文的分词会存在token的交叉重叠的情况,导致在根据用户输入查询串的token获取页面summary时出现:StringIndexOutOfBoundsException的异常。比如:城市学院可能出现这样的分词城市学院城市学院,这几个token就交叉重叠了。

?

错误重现

java.lang.RuntimeException:java.util.concurrent.ExecutionException: java.lang.StringIndexOutOfBoundsException: String index out of range: -4 at org.apache.nutch.searcher.FetchedSegments.getSummary(FetchedSegments.java:316)

at org.apache.nutch.searcher.NutchBean.getSummary(NutchBean.java:357)

at org.apache.nutch.searcher.NutchBean.main(NutchBean.java:429)

Caused by: java.util.concurrent.ExecutionException: java.lang.StringIndexOutOfBoundsException: String index out of range: -4

at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:222)

at java.util.concurrent.FutureTask.get(FutureTask.java:83)

at org.apache.nutch.searcher.FetchedSegments.getSummary(FetchedSegments.java:311)

... 2 more

Caused by: java.lang.StringIndexOutOfBoundsException: String index out of range: -4

at java.lang.String.substring(String.java:1937)

at org.apache.nutch.summary.basic.BasicSummarizer.getSummary(BasicSummarizer.java:190)

at org.apache.nutch.searcher.FetchedSegments.getSummary(FetchedSegments.java:275)

at org.apache.nutch.searcher.FetchedSegments$SummaryTask.call(FetchedSegments.java:65)

at org.apache.nutch.searcher.FetchedSegments$SummaryTask.call(FetchedSegments.java:1)

at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)

at java.util.concurrent.FutureTask.run(FutureTask.java:138)

at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)

at java.lang.Thread.run(Thread.java:619)

?

分析:

从错误日志中可以跟踪到错误的根源为

org.apache.nutch.summary.basic.BasicSummarizer.getSummary

也就是

nutch/src/plugin/summary-basic/src/java/org/apache/nutch/summary/basic/BasicSummarizer.java

文件中的188行开始的如下代码:

if (highlight.contains(t.term())) {

excerpt.addToken(t.term());

//在连个token重叠的情况下,会使得offset>t.startOffset()

excerpt.add(newFragment(text.substring(offset, t.startOffset())));//这就是异常的地方当offset>t.startOffset()就会出错。

excerpt.add(newHighlight(text.substring(t.startOffset(),t.endOffset())));

offset = t.endOffset();

endToken = Math.min(j +sumContext, tokens.length);

所以把代码修改为:(可以将while部分全部修改,也可以改部分)

while ((j < endToken) && (j - startToken < sumLength)) {

Token t = tokens[j];

if (highlight.contains(t.term())) {

excerpt.addToken(t.term());

if(offset<t.startOffset()){

excerpt.add(new Fragment(text.substring(offset, t.startOffset())));

excerpt.add(new Highlight(text.substring(t.startOffset(),t.endOffset())));

}

if(offset>=t.startOffset()){

if(offset<t.endOffset()){

excerpt.add(new Highlight(text.substring(offset,t.endOffset())));

}

offset = Math.max(offset, t.endOffset());

endToken = Math.min(j + sumContext, tokens.length);

}

j++;

}

同时还要将下面的

if(j<tokes.length){

excerpt.add(new Fragment(text.subString(offset,tokens[j].endOffset())));

}

的修改为

if(j<tokes.length){

if(offset< tokens[j].endOffset()){

excerpt.add(new Fragment(text.subString(offset,tokens[j].endOffset())));

}

}

重新编译,在nutch/目录下运行ant,在nutch/build/summary-basic/目录下生成了

summary-basic.jar,把它复制到nutch/plugins/summary-basic/目录下覆盖原来的文件。不要忘记重新生成nutch-1.2jar文件替换搜索项目的同名文件,还要把生成的summary-basic.jar文件替换搜索项目里面的相同文件,不然会出现问题。

?

恭喜你,到此工作完成。我们自己的搜索引擎建立起来了,我们也可以在此基础上做开发。

?

  相关解决方案