搜索引擎+B2B平台+SNS网站=?, 一个三不像网站。偏偏投资人需要这样一个三不像网站。从4月份开始组建团队。时间一瞬2个月过去了。做B2B需要的就是大工作量和时间,而做搜索引擎光分词这块就搞的头大。在此结合开源数据写个一二,已备后用。

搜索引擎需要的就是数据,抓取海量数据、然后存储、分析、建立索引、计算,最终根据用户需求快速检索出结果。存储分析和建立索引的过程开源项目中有个Hadoop是不二之选。这里分析的不是hadoop,而是搜索引擎中最后一步,也是至关重要的一步:中文分词。因为程序员基本是写java为主,故在考虑搜索引擎时,就采用了搜索领域影响颇深的基于纯java语言开发的Nutch搜索引擎。搜索引擎处理英文文档时,几乎不需要特殊的加工处理,英文文档本身就是以词为单位的组织,词个词之间是靠空格或标点符号显式地表示词的边界。我们采用的庖丁解牛正是为中文的分词提供了技术基础。首先,用wget下载了细胞词库,哇,太棒了,数据大的惊人。加上paoding自带的22M词库,基本可以满足我们词典库。

第一步是建立两个文件,在nutch目录的src/plugin目录下建立两个文件夹分别命名为analysis-zh,lib-paoding-analyzers。然后在这两个文件夹下建立plugin.xml和build.xml。
analysis-zh文件夹下plugin.xml内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<plugin id="analysis-zh" name="Chinese Analysis Plug-in" version="1.0.0"
provider-name="net.paoding.analysis">
<runtime>
<library name="analysis-zh.jar">
<export name="*"/>
</library>
</runtime>
<requires>
<import plugin="nutch-extensionpoints"/>
<import plugin="lib-paoding-analyzers"/>
</requires>
<extension id="org.apache.nutch.analysis.zh"
name="Chinese Analyzer"
point="org.apache.nutch.analysis.NutchAnalyzer">
<implementation id="ChineseAnalyzer"
class="org.apache.nutch.analysis.zh.ChineseAnalyzer">
<parameter name="lang" value="zh"/>
</implementation>
</extension>
</plugin>

analysis-zh文件夹下build.xml的内容如下:
<project name="analysis-zh" default="jar-core">
<import file="../build-plugin.xml"/>
<!-- Build compilation dependencies -->
<target name="deps-jar">
<ant target="jar" inheritall="false" dir="../lib-paoding-analyzers"/>
</target>
<!-- Add compilation dependencies to classpath -->
<path id="plugin.deps">
<fileset dir="${nutch.root}/build">
<include name="**/lib-paoding-analyzers
package org.apache.nutch.analysis.zh;
// JDK imports
import java.io.Reader;
// Lucene imports
import net.paoding.analysis.analyzer.PaodingAnalyzer;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
// Nutch imports
import org.apache.nutch.analysis.NutchAnalyzer;

public class ChineseAnalyzer extends NutchAnalyzer {
private final static Analyzer ANALYZER = new PaodingAnalyzer();

public ChineseAnalyzer() { }

public TokenStream tokenStream(String fieldName, Reader reader)
{
return ANALYZER.tokenStream(fieldName, reader);
}
}
lib-paoding-analyzers文件夹下plugin.xml的内容如下:
<plugin
id="lib-paoding-analyzers"
name="paoding Analysers"
version="2.4.0"
provider-name="net.paoding">

<runtime>
<library name="lib-paoding-analyzers.jar">
<export name="*"/>
</library>
</runtime>

</plugin>
lib-paoding-analyzers文件夹下build.xml内容如下:
<?xml version="1.0"?>
<project name="lib-paoding-analyzers" default="jar">

<import file="../build-plugin.xml"/>

<!--
! Override the compile and jar targets,
! since there is nothing to compile here.
! -->
<target name="compile" depends="init"/>

<target name="jar" depends="compile">
<copy todir="${build.dir}" verbose="true">
<fileset dir="./lib" includes="**
analyzer=PAODING_ANALYZER;
return analyzer.tokenStream(fieldName, reader);
}

修改NutchAnalysis.jj,把130行的| <SIGRAM: <CJK> >修改成| <SIGRAM: (<CJK>)+ >
修改org.apache.nutch.indexer.lucene.LuceneWriter
把public void write(NutchDocument doc) throws IOException {
final Document luceneDoc = createLuceneDoc(doc);
........
}
改成public void write(NutchDocument doc) throws IOException {
final Document luceneDoc = createLuceneDoc(doc);
String lang = null;
if(luceneDoc.get("lang") == null) {
lang = "zh";
}
final NutchAnalyzer analyzer = analyzerFactory.get(lang);
if (Indexer.LOG.isDebugEnabled()) {
Indexer.LOG.debug("Indexing [" + luceneDoc.get("url")
+ "] with analyzer " + analyzer + " (" + luceneDoc.get("lang")
+ ")");
}
writer.addDocument(luceneDoc, analyzer);

}
修改org.apache.nutch.analysis.NutchAnalysis,加上方法:
final public Query parseByLucene(Configuration conf) throws ParseException {

Query query = new Query(conf);

if (queryString.length() > 0) {
// lucene分词
org.apache.lucene.queryParser.QueryParser parserLucene =
new org.apache.lucene.queryParser.QueryParser("", analyzer);
org.apache.lucene.search.Query q = null;
try {
q = parserLucene.parse(queryString);
} catch (org.apache.lucene.queryParser.ParseException e) {
e.printStackTrace();
}

String termStrings = q.toString();
if (termStrings.indexOf(" ") > -1)
termStrings = termStrings.substring(1, termStrings.length()-1);
String[] terms = termStrings.split(" ");

for (int i = 0; i < terms.length; i++) {
String[] tems = {terms[i]};
query.addRequiredPhrase(tems, Clause.DEFAULT_FIELD);
}
}

return query;
}
然后修改这个类的方法blic static Query parseQuery(){}里面的return parser.parse(conf); 修改为return parser.parseByLucene(conf);

第四步,修改Nutch的build.xml文件
修改根目录的build.xml,在target war的<lib> </lib>里加上
<include name="paoding-analysis.jar"/>
修改150行处的<target name="job" depends="compile">,改为<target name="job" depends="compile,war"> 这样编译后能自动在bulid文件夹下生成nutch -1.0.job,nutch-1.0.war,nutch-1.0.jar文件了。
修改nutch-1.0\src\plugin下的build.xml文件,加上
<target name="deploy">
<ant dir="analysis-zh" target="deploy"/>
<ant dir="lib-paoding-analyzers" target="deploy"/>
.......
</target>

<target name="clean">
<ant dir="analysis-zh" target="clean"/>
<ant dir="lib-paoding-analyzers" target="clean"/>
.......
</target>

最后就可以用 ant进行编译了,编译后的结果测试:http://www.huisou.com
编译后把\nutch-1.0\build下出现的analysis-zh和lib-paoding-analyzers两文件夹复制到\nutch-1.0\plugins下面,删掉里面的classes和test文件。并把\nutch-1.0\src\plugin下相同文件夹下的plugin.xml复制过去。在用ant编译一次。把\nutch-1.0\build下的nutch -1.0.job,nutch-1.0.war,nutch-1.0.jar复制到nutch的根目录下替代原来的文件。

用Nutch抓取来的1T数据,通过hadoop的MapReduce进行存储实现,然后建立倒索引,配置Tomcat,就可以体验分词带来的搜索效果了。

山寨级别的搜索引擎自然不能与Google、百度相提并论。在搜索引擎实现的每一个步骤(数据抓取、存储、索引、分词系统、分布式查询等)每一个都是巨大的课题,值得我们去深入研究。同时欢迎更多的搜索引擎互联网爱好者加入我们的团队,一起学习进步。

posted on 2011-07-21 15:31  伤寒泪  阅读(1548)  评论(0编辑  收藏  举报