就像我们知道的一样,nutch是一个架构在lucene之上的网络爬虫+搜索引擎.

是由lucene的作者在lucene基础之上开发,并整合了hadoop,实现在分布式云计算,使用google标准的HFDS文件系统作为存储结构,是一款高伸缩性能与高效高并发的网络爬虫+搜索引擎.

FaceYe在后台已经整合了nutch,在适当的时候,就可以开始为用户提供高质量的知识索引服务.顺便说一下,nutch在生产环境中,并不能在windows下运行,需要在liux下运行,这其中主要是hadoop采用了一些shello脚本,当然,开发平台还是可以搭建在window下,但需要安装cygwin,来模拟shell环境.废话少说,入nutch正题

正像上面说到的,nutch使用HFDS来存储索引文件,并没有将爬取来的数据存储入数据库,这是因为HFDS是一种比数据库更高效,更容易实现负载均衡的结构,对于像搜索引擎这样的应用,使用数据库将对严重制约性能,所以,使用HFDS再加上倒派索引,会取理满意的性能,HFDS也是目前搜索巨头google,以及yahoo所正在使用的文件格式.

虽然有了HFDS,但在进行网络爬取的时候,我们还是希望,可以将爬取的一些个数据,比如网页url,比如网页标题等关键信息存储到数据库中,但nutch并没有提供这样的功能,怎么办?动手发明轮子~

nutch支持强大 的plugin 机制,这种机制与eclipse中的plugin机制同出一辙,一样可以方便的进行插拔.

开发将爬取记录存入数据库的nutch plugin过程如下.

1.定义这一nutch plugin要实现的主要功能:

在使用nutch爬取网络资源的同时,将网络资源的主要信息存储入数据库.

2.新建plugin 包:

org.apache.nutch.indexer.store

并开发StoreIndexingFilter工具类如下:

public class StoreIndexingFilter implements IndexingFilter
{
public static final Log LOG = LogFactory.getLog(StoreIndexingFilter.class);

/** A flag that tells if magic resolution must be performed */
private boolean MAGIC;

/** Get the MimeTypes resolver instance. */
private MimeUtil MIME;

public NutchDocument filter(NutchDocument doc, Parse parse, Text url, CrawlDatum datum, Inlinks inlinks) throws IndexingException
{

IResourceEntityService resourceEntityService = (IResourceEntityService) SpringUtil.getInstance().getBean(“resourceEntityService”);

String _url = doc.getFieldValue(“url”);
String _title = doc.getFieldValue(“title”);
if (StringUtils.isNotEmpty(_url))
{
if (!resourceEntityService.isExists(ResourceEntity.class, “url”, _url))
{
ResourceEntity resourceEntity = new ResourceEntity();
resourceEntity.setUrl(_url);
if (StringUtils.isNotEmpty(_title))
{
if (_title.length() > 255)
{
_title = _title.substring(0, 254);
}
}
resourceEntity.setName(_title);
resourceEntityService.saveResourceEntity(resourceEntity);
}
}
return doc;
}
private NutchDocument addTime(NutchDocument doc, ParseData data, String url, CrawlDatum datum)
{
long time = -1;

String lastModified = data.getMeta(Metadata.LAST_MODIFIED);
if (lastModified != null)
{ // try parse last-modified
time = getTime(lastModified, url); // use as time
// store as string
doc.add(“lastModified”, Long.toString(time));
}

if (time == -1)
{ // if no last-modified
time = datum.getFetchTime(); // use fetch time
}

SimpleDateFormat sdf = new SimpleDateFormat(“yyyyMMdd”);
sdf.setTimeZone(TimeZone.getTimeZone(“GMT”));
String dateString = sdf.format(new Date(time));

// un-stored, indexed and un-tokenized
doc.add(“date”, dateString);

return doc;
}

private long getTime(String date, String url)
{
long time = -1;
try
{
time = HttpDateFormat.toLong(date);
} catch (ParseException e)
{
// try to parse it as date in alternative format
try
{
Date parsedDate = DateUtils.parseDate(date, new String[] { “EEE MMM dd HH:mm:ss yyyy”, “EEE MMM dd HH:mm:ss yyyy zzz”,
“EEE, MMM dd HH:mm:ss yyyy zzz”, “EEE, dd MMM yyyy HH:mm:ss zzz”, “EEE,dd MMM yyyy HH:mm:ss zzz”, “EEE, dd MMM yyyy HH:mm:sszzz”,
“EEE, dd MMM yyyy HH:mm:ss”, “EEE, dd-MMM-yy HH:mm:ss zzz”, “yyyy/MM/dd HH:mm:ss.SSS zzz”, “yyyy/MM/dd HH:mm:ss.SSS”,
“yyyy/MM/dd HH:mm:ss zzz”, “yyyy/MM/dd”, “yyyy.MM.dd HH:mm:ss”, “yyyy-MM-dd HH:mm”, “MMM dd yyyy HH:mm:ss. zzz”,
“MMM dd yyyy HH:mm:ss zzz”, “dd.MM.yyyy HH:mm:ss zzz”, “dd MM yyyy HH:mm:ss zzz”, “dd.MM.yyyy; HH:mm:ss”, “dd.MM.yyyy HH:mm:ss”,
“dd.MM.yyyy zzz” });
time = parsedDate.getTime();
// if (LOG.isWarnEnabled()) {
// LOG.warn(url + “: parsed date: ” + date +” to:”+time);
// }
} catch (Exception e2)
{
if (LOG.isWarnEnabled())
{
LOG.warn(url + “: can’t parse erroneous date: ” + date);
}
}
}
return time;
}

// Add Content-Length
private NutchDocument addLength(NutchDocument doc, ParseData data, String url)
{
String contentLength = data.getMeta(Response.CONTENT_LENGTH);

if (contentLength != null)
doc.add(“contentLength”, contentLength);

return doc;
}
private NutchDocument addType(NutchDocument doc, ParseData data, String url)
{
MimeType mimeType = null;
String contentType = data.getMeta(Response.CONTENT_TYPE);
if (contentType == null)
{
mimeType = MIME.getMimeType(url);
} else
{
mimeType = MIME.forName(MimeUtil.cleanMimeType(contentType));
}

// Checks if we solved the content-type.
if (mimeType == null)
{
return doc;
}

contentType = mimeType.getName();

doc.add(“type”, contentType);

String[] parts = getParts(contentType);

for (String part : parts)
{
doc.add(“type”, part);
}

return doc;
}

static String[] getParts(String mimeType)
{
return mimeType.split(“/”);
}

private PatternMatcher matcher = new Perl5Matcher();

private Configuration conf;
static Perl5Pattern patterns[] = { null, null };
static
{
Perl5Compiler compiler = new Perl5Compiler();
try
{
// order here is important
patterns[0] = (Perl5Pattern) compiler.compile(“//bfilename=['/"](.+)['/"]“);
patterns[1] = (Perl5Pattern) compiler.compile(“//bfilename=(//S+)//b”);
} catch (MalformedPatternException e)
{
// just ignore
}
}

private NutchDocument resetTitle(NutchDocument doc, ParseData data, String url)
{
String contentDisposition = data.getMeta(Metadata.CONTENT_DISPOSITION);
if (contentDisposition == null)
return doc;

MatchResult result;
for (int i = 0; i < patterns.length; i++)
{
if (matcher.contains(contentDisposition, patterns[i]))
{
result = matcher.getMatch();
doc.add("title", result.group(1));
break;
}
}

return doc;
}

public void addIndexBackendOptions(Configuration conf)
{

LuceneWriter.addFieldOptions("type", LuceneWriter.STORE.NO, LuceneWriter.INDEX.UNTOKENIZED, conf);

LuceneWriter.addFieldOptions("primaryType", LuceneWriter.STORE.YES, LuceneWriter.INDEX.UNTOKENIZED, conf);
LuceneWriter.addFieldOptions("subType", LuceneWriter.STORE.YES, LuceneWriter.INDEX.UNTOKENIZED, conf);

LuceneWriter.addFieldOptions("contentLength", LuceneWriter.STORE.YES, LuceneWriter.INDEX.NO, conf);

LuceneWriter.addFieldOptions("lastModified", LuceneWriter.STORE.YES, LuceneWriter.INDEX.NO, conf);

// un-stored, indexed and un-tokenized
LuceneWriter.addFieldOptions("date", LuceneWriter.STORE.NO, LuceneWriter.INDEX.UNTOKENIZED, conf);
}

public void setConf(Configuration conf)
{
this.conf = conf;
MIME = new MimeUtil(conf);
}

public Configuration getConf()
{
return this.conf;
}

}

其中最主要的方法为:

public NutchDocument filter(NutchDocument doc, Parse parse, Text url, CrawlDatum datum, Inlinks inlinks) throws IndexingException
{

IResourceEntityService resourceEntityService = (IResourceEntityService) SpringUtil.getInstance().getBean("resourceEntityService");
String _url = doc.getFieldValue("url");
String _title = doc.getFieldValue("title");
if (StringUtils.isNotEmpty(_url))
{
if (!resourceEntityService.isExists(ResourceEntity.class, "url", _url))
{
ResourceEntity resourceEntity = new ResourceEntity();
resourceEntity.setUrl(_url);
if (StringUtils.isNotEmpty(_title))
{
if (_title.length() > 255)
{
_title = _title.substring(0, 254);
}
}
resourceEntity.setName(_title);
resourceEntityService.saveResourceEntity(resourceEntity);
}
}
return doc;
}
也就是说,要在使用nutch构建document文档的同时,这一资源,存入数据库.

存入数据库的代码resourceEntityService.saveResourceEntity(resourceEntity);不再详细给出,有兴趣的可以查看FaceYe的开源项目相关信息.

接下来需要做的事情是配置本插件的plugin文件,整体配置如下:

provider-name="nutch.org">

point="org.apache.nutch.indexer.IndexingFilter">
class="org.apache.nutch.indexer.store.StoreIndexingFilter" />

这个xml文件的主要含义是告诉nutch加载哪个jar,使用哪个类.文件中有清晰的描述.

nutch数据存数据库的插件开发完毕了,接下来要做的是使用ant将本插件编译为jar文件,为启用本插件做准备.

编译nutch源码及配置文件为jar主要通过修改ant编译文件来完成.

操作步骤为:打开nutch/src/plugin/文件,找到build.xml中的"deploy”任务,添加

即可.

到些,将nutch爬取的数据存储入数据库的开发工作可以基本完成,接下来是要启用本插件,这就很简单了,

打开nutch/conf/nutch-site.xml.

找到plugin-include接点,在value中使用"index-(basic|anchor|store)"代替index-(basic|anchor);就完成了將nutch爬取数据存储入数据库插件的启用.

nutch 存储到数据库的更多相关文章

  1. Java实现购物车功能:方式一:存放在session中.方式二:存储在数据库中

    //将购物车产品加入到cookie中,方式同浏览记录.Java实现购物车,方式一(简易版):存储在session中.这种方式实现还不严谨,大家看的时候看思路即可.(1). JSP页面中,选择某一款产品 ...

  2. Web安全--使用Salt + Hash将密码加密后再存储进数据库

    转载原地址 http://www.bozhiyue.com/mianshiti/_net/2016/0728/314239.html (一) 为什么要用哈希函数来加密密码 如果你需要保存密码(比如网站 ...

  3. runtime实现对象存储型数据库——LHDB

    前言 最近在GitHub上看了一份关于基于runtime封装的对象存储型数据库的开源代码,觉得非常值得分享记录一下,在IOS中对数据库的操作一般通过CoreData和SQLite,CoreData 虽 ...

  4. DevOps之存储和数据库

    唠叨话 关于德语噢屁事的知识点,仅提供专业性的精华汇总,具体知识点细节,参考教程网址,如需帮助,请留言. <数据(Data)> 了解有关数据部分.涉及存储及数据库的概念:知识与技能的层次( ...

  5. RDLC报表显示存储于数据库的图片

    图片以二进制存储于数据库表中.在显示RDLC报表时,把图片呈现出来. 好吧. 把存储过程写好: CREATE PROCEDURE [dbo].[usp_File_Select] AS SELECT [ ...

  6. emoji表情存储到数据库的方法

    方案1:修改数据库编码 为什么我们设置表的的字符类型为utf8却不能存放emoji呢?原来utf8可能是2或3或4个字节,而mysql的utf8是3个字节,存放一个emoji是需要4个字节的,自然不够 ...

  7. js上传文件带参数,并且,返回给前台文件路径,解析上传的xml文件,存储到数据库中

    ajaxfileupload.js jQuery.extend({ createUploadIframe: function(id, uri) { //create frame var frameId ...

  8. Django中从本地上传excel文件并将数据存储到数据库

    Django中从本地上传excel文件并将数据存储到数据库 一.前端界面 <div class="page-container"> <form action=&q ...

  9. 特殊字符,如Emoji表情Base64存储到数据库

    有些特殊字符,如Emoji,存储到oracle数据库就会变成乱码,解决方案就是Base64转码后存储到数据库,取出后再解码传输,经过验证是可以的. 编码存储,接收参数转json再.ToString() ...

随机推荐

  1. windows 批处理-重命名

    从数字1递增批量重命名ren.bat: @echo off SETLOCAL ENABLEDELAYEDEXPANSION set /A num= FOR /F "tokens=*" ...

  2. JavaScrip——练习(做悬浮框再进一步:悬浮窗后缀悬浮窗——用this.className)

    对悬浮窗进一步改进: 用this.className 可以省略script <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitio ...

  3. jquery-ajax-php(内容点赞并进行cookie限制实现)

    1.模板页html例如以下: 2.模板页的jquery里的ajax实现例如以下: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T ...

  4. linux 获取随机数的办法

    1.1.1 inux随机数的办法  http://www.2cto.com/kf/201410/342717.html 方法一.[root@ob ~]# date +%N  %N纳秒  随机获取的九位 ...

  5. php 抽象 继承 多态

    1.继承和重载 !!!php中使用extends单一继承的方法 被继承的类  父类(基类) 继承者   子类(派生类) 如果说我们需要将父类方法重载(方法覆盖),在派生类里使用与基类方法重名的方法名称 ...

  6. 如果你不知道这11款常见的Web应用程序框架 就说明你out了

    本文推荐了11款常见的Web应用程序框架,并列出了相关的学习资料和下载文档.如果对这些项目还不熟悉,就赶紧学起来吧~ Rails Rails是Ruby on Rails的简称,是一款开源的Web应用框 ...

  7. java基础复习二——面向对象一

    面向对象三大特性:封装,继承,多态 类:对象的蓝图,生成对象的模板,是对一类事物的描述,是抽象的概念上的定义 对象:是实际存在的该类事物的每个个体,也称为实例 类之间三种关系:依赖关系(uses-a) ...

  8. 【转】WebService 的创建,部署和使用

    WebService,即Web服务,能使得运行在不同机器上的不同应用无须借助,专门的第三方软件或硬件,就可相互交换数据或集成. 第一次选择WebService,是为了替代数据库远程连接.我们都知道当S ...

  9. 使用什么工具连接MySQL Server

    字符界面:命令行终端(需MySQL Client) GUI界面:Navicat.MySQL Workbench 开发语言:使用相应语言的MySQL数据库驱动包或模块连接MySQL 我一般用的是命令行, ...

  10. linux gzip 命令详解

    减少文件大小有两个明显的好处,一是可以减少存储空间,二是通过网络传输文件时,可以减少传输的时间.gzip是在Linux系统中经常使用的一个对文件进行压缩和解压缩的命令,既方便又好用. 语法:gzip  ...