nutch 存储到数据库
就像我们知道的一样,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 存储到数据库的更多相关文章
- Java实现购物车功能:方式一:存放在session中.方式二:存储在数据库中
//将购物车产品加入到cookie中,方式同浏览记录.Java实现购物车,方式一(简易版):存储在session中.这种方式实现还不严谨,大家看的时候看思路即可.(1). JSP页面中,选择某一款产品 ...
- Web安全--使用Salt + Hash将密码加密后再存储进数据库
转载原地址 http://www.bozhiyue.com/mianshiti/_net/2016/0728/314239.html (一) 为什么要用哈希函数来加密密码 如果你需要保存密码(比如网站 ...
- runtime实现对象存储型数据库——LHDB
前言 最近在GitHub上看了一份关于基于runtime封装的对象存储型数据库的开源代码,觉得非常值得分享记录一下,在IOS中对数据库的操作一般通过CoreData和SQLite,CoreData 虽 ...
- DevOps之存储和数据库
唠叨话 关于德语噢屁事的知识点,仅提供专业性的精华汇总,具体知识点细节,参考教程网址,如需帮助,请留言. <数据(Data)> 了解有关数据部分.涉及存储及数据库的概念:知识与技能的层次( ...
- RDLC报表显示存储于数据库的图片
图片以二进制存储于数据库表中.在显示RDLC报表时,把图片呈现出来. 好吧. 把存储过程写好: CREATE PROCEDURE [dbo].[usp_File_Select] AS SELECT [ ...
- emoji表情存储到数据库的方法
方案1:修改数据库编码 为什么我们设置表的的字符类型为utf8却不能存放emoji呢?原来utf8可能是2或3或4个字节,而mysql的utf8是3个字节,存放一个emoji是需要4个字节的,自然不够 ...
- js上传文件带参数,并且,返回给前台文件路径,解析上传的xml文件,存储到数据库中
ajaxfileupload.js jQuery.extend({ createUploadIframe: function(id, uri) { //create frame var frameId ...
- Django中从本地上传excel文件并将数据存储到数据库
Django中从本地上传excel文件并将数据存储到数据库 一.前端界面 <div class="page-container"> <form action=&q ...
- 特殊字符,如Emoji表情Base64存储到数据库
有些特殊字符,如Emoji,存储到oracle数据库就会变成乱码,解决方案就是Base64转码后存储到数据库,取出后再解码传输,经过验证是可以的. 编码存储,接收参数转json再.ToString() ...
随机推荐
- windows 批处理-重命名
从数字1递增批量重命名ren.bat: @echo off SETLOCAL ENABLEDELAYEDEXPANSION set /A num= FOR /F "tokens=*" ...
- JavaScrip——练习(做悬浮框再进一步:悬浮窗后缀悬浮窗——用this.className)
对悬浮窗进一步改进: 用this.className 可以省略script <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitio ...
- jquery-ajax-php(内容点赞并进行cookie限制实现)
1.模板页html例如以下: 2.模板页的jquery里的ajax实现例如以下: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T ...
- linux 获取随机数的办法
1.1.1 inux随机数的办法 http://www.2cto.com/kf/201410/342717.html 方法一.[root@ob ~]# date +%N %N纳秒 随机获取的九位 ...
- php 抽象 继承 多态
1.继承和重载 !!!php中使用extends单一继承的方法 被继承的类 父类(基类) 继承者 子类(派生类) 如果说我们需要将父类方法重载(方法覆盖),在派生类里使用与基类方法重名的方法名称 ...
- 如果你不知道这11款常见的Web应用程序框架 就说明你out了
本文推荐了11款常见的Web应用程序框架,并列出了相关的学习资料和下载文档.如果对这些项目还不熟悉,就赶紧学起来吧~ Rails Rails是Ruby on Rails的简称,是一款开源的Web应用框 ...
- java基础复习二——面向对象一
面向对象三大特性:封装,继承,多态 类:对象的蓝图,生成对象的模板,是对一类事物的描述,是抽象的概念上的定义 对象:是实际存在的该类事物的每个个体,也称为实例 类之间三种关系:依赖关系(uses-a) ...
- 【转】WebService 的创建,部署和使用
WebService,即Web服务,能使得运行在不同机器上的不同应用无须借助,专门的第三方软件或硬件,就可相互交换数据或集成. 第一次选择WebService,是为了替代数据库远程连接.我们都知道当S ...
- 使用什么工具连接MySQL Server
字符界面:命令行终端(需MySQL Client) GUI界面:Navicat.MySQL Workbench 开发语言:使用相应语言的MySQL数据库驱动包或模块连接MySQL 我一般用的是命令行, ...
- linux gzip 命令详解
减少文件大小有两个明显的好处,一是可以减少存储空间,二是通过网络传输文件时,可以减少传输的时间.gzip是在Linux系统中经常使用的一个对文件进行压缩和解压缩的命令,既方便又好用. 语法:gzip ...