[网摘]开发基于 Nutch 的集群式搜索引擎

转载[IBM-developerWorks中国-Open source-文档库 ]
王 飞鹏 ( [email protected]), 软件工程师, EMC
李 立 ( [email protected]), 研究员, EMC
王 美华 ( [email protected]), 软件工程师, EMC
发布日期: 2008 年 10 月 16 日 
级别: 中级 
******************
本文首先介绍 Nutch 的背景知识,包括 Nutch 架构,爬虫和搜索器。然后以开发一个基于 Nutch 的实际应用为例向读者展示如何使用 Nutch 开发自己的搜索引擎。在该示例中,首先带领读者开发一个作为 Nutch 爬虫抓取的目标网站,目标网站将被部署在域名为 myNutch.com 的服务器上。然后示例说明 Nutch 爬虫如何抓取目标网站内容,产生片断和索引,并将结果存放在集群的2个节点上。最后使用 Nutch 检索器提供的 API 开发应用,为用户提供搜索接口。
简介
Nutch 是一个基于 Java 实现的开源搜索引擎,其内部使用了高性能全文索引引擎工具 Lucene。从 nutch0.8.0开始,Nutch 完全构建在 Hadoop 分布式计算平台之上。Hadoop 除了是一个分布式文件系统外,还实现了 Google 的 GFS 和 MapReduce 算法。因此基于 Hadoop 的 Nutch 搜索引擎可以部署在由成千上万计算机组成的大型集群上。由于商业搜索引擎允许竞价排名,这样导致索引结果并不完全是和站点内容相关的,而 Nutch 搜索结果能够给出一个公平的排序结果,这使得 Nutch 在垂直搜索、档案互联网搜索等领域得到了广泛应用。
前提条件
  • Rational Application Developer v6.0
  • Websphere Application Server v6.0
  • Nutch 0.8.1
  • SSH Service Package
  • 主节点RHAS3.0
  • 从节点Debian GNU/Linux 3.1
背景知识
Nutch 搜索引擎是一个基于 Java 的开放源代码的搜索引擎。Nutch 搜索引擎处理流程包括抓取流程和搜索流程,如图 1 所示。相应地 Nutch 也分为2部分,抓取器和搜索器。在抓取流程中,抓取器也叫蜘蛛或者机器人,以广度优先搜索(BFS)的方式从企业内部网或者互联网抓取网页。这个过程涉及到对 CrawlDB 和 LinkDB 数据库的操作。然后 Nutch 解析器开始解析诸如 HTML、XML、RSS、PDF等不同格式的文档。最后 Nutch 索引器针对解析结果建立索引并存储到 indexDB 和 SegmentsDB 数据库中,以供搜索器搜索使用。
在搜索流程中,搜索应用使用输入关键词调用 Nutch 搜索接口(Nutch Query Interface)。应用可通过网页上的输入框输入相应关键词。搜索接口解析搜索请求为 Lucene 全文检索引擎可以识别的格式。Nutch 索引器将会调用 Lucene 引擎来响应请求在 indexDB 上展开搜索。最后搜索接口收集从索引器返回的URL、标题、锚和从 SegmentsDB 返回的内容。所有上述内容将被提供给排序算法进行排序。排序完成后,搜索接口将返回命中的搜索结果。由于构建在 Hadoop 分布式文件系统之上, Nutch 对CrawlDB, LinkDB, SegmentsDB 和 IndexDB 数据库的操作都是通过调用 M/R(map/reduce) 函数完成的。这使得 Nutch 具有了集群扩展能力。

图 1 Nutch搜索引擎架构图
Nutch搜索引擎架构图 
开发目标网站 targetWebSite
现在将开发一个供 Nutch 爬虫抓取的目标网站应用。这个应用使用 RAD v6.0(Rational Application Developer)作为集成开发工具开发。应用开发完成后,将被部署在 WAS v6.0(Websphere Application Server)服务器上,本样例中服务器的域名设置是 myNutch.com。读者可以按照下面的步骤来开发该目标网站应用。
  1. 创建一个动态 Web 项目。打开 RAD,选择 File > New > Project,然后在向导里选择动态 Web 项目,如图 2 所示。 

    图 2 创建一个动态 Web 项目
    创建一个动态Web项目 

  2. 设计网页。在项目里面,选择 File > New > HTML/XHTML,创建 index.html, one.html,two.html 和 three.html 一共4个文件。 项目的最终结构组成如图 3 所示。 

    图 3 项目的最终结构组成
    项目的最终结构组成 

  3. 在 WAS v6.0 中运行项目。 打开 RAD, 选择 project > Run > Run on Server, 部署并在服务器上运行。如图 4 所示。 

    图 4 在服务器上运行
    在服务器上运行 

  4. 点击完成按钮。启动浏览器,在地址栏中输入 http://myNutch.com/targetWebApp。如图 5 所示。 

    图 5 在浏览器中访问
    在浏览器中访问 

定义搜索引擎
在抓取网站之前,需要定义搜索引擎。在本样例中Nutch被配置为集群方式。集群包括主节点(地址9.181.87.172,操作系统 RHAS3.0)和从节点(地址 9.181.87.176,操作系统 Debian)。如前文介绍,Nutch 的集群能力主要利用了 Hadoop 的分布式计算环境。下面介绍如何定义 Nutch 搜索引擎。
  1. 安装 Nutch。首先下载 Nutch 安装包。本示例采用 Nutch0.8.1。解压下载到的 Nutch 0.8.1包到主节点某一工作目录下。本文中的工作目录使用 /workspace 。确认主从节点上都已安装 SSH service package和 JDK1.4 或 JDK 1.5
  2. Nutch 设置。在 Nutch 的工作目录下,用文本编辑器打开 conf 目录下的文件 Nutch-site.xml,输入 http.agent.name,http.agent.description,http.agent.url 和 http.agent.email 属性集。注意 http.agent.ur 属性需要填写部署目标网站的域名地址 myNutch.com。清单 1 列出了修改完毕后的 Nutch-site.xml。 

    清单 1 Nutch-site.xml 
    <property>
      <name>http.agent.name</name>
      <value>Nutch-hadoop</value>
      <description>HTTP 'User-Agent' request header. MUST NOT be empty -
      please set this to a single word uniquely related to your organization.
      </description>
    </property>
    <property>
      <name>http.agent.description</name>
      <value>bydenver</value>
      <description>Further description of our bot- this text is used in
      the User-Agent header.  It appears in parenthesis after the agent name.
      </description>
    </property>
    <property>
      <name>http.agent.url</name>
      <value>myNutch.com</value>
      <description>A URL to advertise in the User-Agent header.  This will
       appear in parenthesis after the agent name. Custom dictates that this
       should be a URL of a page explaining the purpose and behavior of this
       crawler.
      </description>
    </property>
    <property>
      <name>http.agent.email</name>
      <value>[email protected]</value>
      <description>An email address to advertise in the HTTP 'From' request
       header and User-Agent header. A good practice is to mangle this
       address (e.g. 'info at example dot com') to avoid spamming.
      </description>
    </property>  
       

  3. Hadoop 主节点设置。 用文本编辑器打开 conf 目录下的文件 hadoop-site.xml,插入清单 2 所列出的属性集。需要注意的是属性 fs.default.name 和 mapred.job.tracker 设置为主节点的IP地址(在本例中为9.181.87.172)。 

    清单 2 hadoop-site.xml文件 
    <property>
      <name>fs.default.name</name>
      <value>9.181.87.172:9000</value>
      <description>
        The name of the default file system. </description>
    </property>
    <property>
      <name>mapred.job.tracker</name>
      <value>9.181.87.172:9001</value>
      <description>
        The host and port that the MapReduce job tracker runs at.
      </description>
    </property>
    <property> 
      <name>mapred.map.tasks</name>
      <value>2</value>
      <description>
        define mapred.map tasks to be number of slave hosts
      </description> 
    </property>
    <property> 
      <name>mapred.reduce.tasks</name>
      <value>2</value>
      <description>
        define mapred.reduce tasks to be number of slave hosts
      </description> 
    </property>
    <property>
      <name>dfs.name.dir</name>
      <value>/workspace/filesystem/name</value>
    </property>
    <property>
      <name>dfs.data.dir</name>
      <value>/workspace/filesystem/data</value>
    </property>
    <property>
      <name>mapred.system.dir</name>
      <value>/workspace/filesystem/mapreduce/system</value>
    </property>
    <property>
      <name>mapred.local.dir</name>
      <value>/workspace/filesystem/mapreduce/local</value>
    </property>
    <property>
      <name>dfs.replication</name>
      <value>2</value>
    </property>
       

  4. Hadoop 从节点设置。使用文本编辑器打开 conf 目录下的 slaves 文件,输入从节点的 IP 地址。如清单 3 所示。 

    清单 3 slaves 文件 
    9.181.87.176

  5. 抓取器设置。首先在 Nutch 工作目录下创建目录 urls,再新建文件 urllist.txt。编辑 urllist.txt文件,输入 http://myNutch.com/targetWebApp。清单 4 列出了所使用的命令。最后需要编辑 conf 目录下的 crawl-urlfilter.txt 文件,输入 +^http://([a-z0-9]*\.)*myNutch.com/,如清单 5 所示。 

    清单 4 创建 urllist 文件 
    cd /workspace/Nutch-0.8.1
    mkdir urls
    echo http://myNutch.com/targetWebApp > urls/urllist.txt
    conf/crawl-urlfilter.txt



    清单 5 编辑crawl-urlfilter.txt 文件 
    +^http://([a-z0-9]*\.)*myNutch.com/

抓取器抓取并分析
在使用 Nutch 抓取之前,首先需要启动 Hadoop 服务。清单 6 列出了启动 Hadoop 服务所采用的命令。随后使用清单 7 中的命令从 myNutch.com 抓取网页并解析,其中参数 “depth 3” 表示从网页根路径算起的链接深度;参数 “topN 10” 表示抓取器在每层需要获取的最大页面数目。开始抓取后,抓取器将在当前目录下创建新目录 crawl 作为工作目录。

清单 6 启动 Hadoop 服务 
bin/hadoop dfs -put urls urls
bin/hadoop dfs namenode �Cformat


清单 7 抓取命令 
bin/Nutch crawl urls -dir ./crawl -depth 3 -topN 10

对目标网站 targetWebApp 完成抓取后, 在 crawl 工作目录下产生了五个子目录: crawldb,linkdb,segments,indexes 和 index (见图 6)。数据库 crawldb 中包含页面的数目等;linkdb 包含页面在数据库中的链接,这是抓取器真正抓取网站时由页面的链接数目决定;Segments 数据库按照时间戳分为三个片断,每个片断的产生都经历了 generate/fetch/update 三个过程;Indexes 数据库包含了在 generate/fetch/update 过程中产生的 Lucene 索引;Index 数据库包含了经合并处理后的 Lucene 索引。

图 6 抓取器抓取结果
抓取器抓取结果 
读者也可以使用工具 Luke 去查看 Lucene 索引。 借助 Luke,可以查看索引内容以及对索引查询。图 7 列出了 index 目录下的合并后的索引。

图 7 使用 Luke 查看 Lucene 索引
使用Luke查看Lucene索引 
开发搜索应用
完成抓取后,现在将开发一个基于 Nutch 搜索 API 的应用 NutchApp,提供给用户作为搜索的接口。NutchApp 使用 Java 语言编写,其实现首先创建 NutchConfiguration 对象,然后创建 NutchBean。这个 NutchBean 实例将用来处理用户的搜索请求;根据请求参数,创建 query 对象,NutchBean 通过调用 search 方法来处理此 query 对象的请求。最终搜索结果以 Hits 集合。NutchApp 遍历此 Hits 集合并打印结果到标准输出。清单 8 列出了 NutchApp 的示例代码。

清单 8 NutchApp的示例代码 
package org.myNutch;
import java.io.IOException;
import java.io.*;
import java.util.*;
import org.apache.hadoop.conf.Configuration;
import org.apache.Nutch.searcher.*;
import org.apache.Nutch.util.*;
public class NutchApp {
  /** For debugging. */
  public static void main(String[] args) throws Exception {
    String usage = "NutchBean query";
    if (args.length == 0) {
      System.err.println(usage);
      System.exit(-1);
    }    
    Configuration conf = NutchConfiguration.create();
    NutchBean bean = new NutchBean(conf);
    Query query = Query.parse(args[0], conf);
    Hits hits = bean.search(query, 10);
    System.out.println("Total hits: " + hits.getTotal());
    int length = (int)Math.min(hits.getTotal(), 10);
    Hit[] show = hits.getHits(0, length);
    HitDetails[] details = bean.getDetails(show);
 Summary[] summaries = bean.getSummary(details, query);
 for ( int i = 0; i <hits.getLength();i++){
      System.out.println(" "+i+" "+ details[i] + "\n" + summaries[i]);
    }
  }
}

接下来我们来运行 NutchApp。首先编译 NutchApp.java 并打包。打包后的文件名为 NutchApp.jar。随后在 Nutch 命令下执行。见清单 9。

清单 9 编译、打包和执行 NutchApp
Javac -cp "Nutch-0.8.1.jar;hadoop-0.4.0-patched.jar" src/org/myNutch/NutchApp.java -d lib
cd lib
jar cvf NutchApp.jar org/myNutch/NutchApp.class
cd ../
bin/Nutch org.myNutch.NutchApp Nutch

下面我们可以验证我们开发的 Nutch 搜索引擎的使用效果。在搜索页面搜索关键字输入“Nutch”,NutchApp 返回的搜索结果如清单 10 所示。其中包括概要和详细内容。

清单 10 NutchApp输出
Total hits: 3
 0 20061104142342/http://myNutch.com/targetWebApp/two.html
 ... 8 release of Nutch is now available. This is ... first release of Nutch
 1 20061104142342/http://myNutch.com/targetWebApp/one.html
 ... 1 release of Nutch is now available. This is ...
 2 20061104142342/http://myNutch.com/targetWebApp/three.html
 ... 2 release of Nutch is now available. This is ...

小结
通过本文的介绍,现在你已经知道如何使用 Nutch 开发集群式的搜索引擎,并使用此搜索引擎对目标网站进行抓取和分析结果,以及如何提供搜索接口来响应用户的搜索请求。事实上,搭建基于 Nutch 的搜索引擎是一个具有很大挑战性的工作,因为 Nutch 本身还在不断的发展之中,另外目标网站的结构复杂度也不尽相同。所以,针对互联网站点文档格式日益复杂的需求,接下来你还需要花一些精力关注 Nutch 高级特性的进展。
参考资料
学习
  • 在 Nutch 官方网站阅读更多有关 Nutch 的在线文档

  • 在 Lucene 官方网站阅读更多有关 Lucene 的在线文档

  • 在 Hadoop 官方网站阅读更多有关 Hadoop 的在线文档

你可能感兴趣的:(Nutch,简介,示例,基础知识,抓取)