Requirements(本人選擇):
- Java 1.5
- Apache's Tomcat 5.x
- Win32 with Cygwin
- Nutch, 呵呵
Nutch 0.72版就我個人而言,感覺不太好用(有人說所謂感覺就是靠不住,管他呢),現在可以從svn倉庫中下載源碼,並用ant package編譯,之後你就得到了一個0.8版本的Nutch。編譯之後的目錄結構:
nutch
bin -- 執行指令碼
build -- 編譯產生的類,外掛程式目錄,以及放入tomcat的war包。
conf -- 各種設定檔
...
這兒有一篇0.8的英文的tutorial http://lucene.apache.org/nutch/tutorial8.html, 文檔寫的比較詳細,但是其中有幾個可能會害死人的小Bug,一般而言,文檔中的Bug比程式中的Bug更氣人,我寫的文檔也是Bug不斷,誰看誰生氣。如果誰看到中文tutorial文檔,請貼出串連。這兒還有一篇野網頁(非官方)
http://wiki.media-style.com/display/nutchDocu/Home,裡面有如何在Eclipse中調試Nutch的圖解。
- 執行bin/nutch,可以察看bin/nutch的所有命令,一個可能的輸出是:
Usage: nutch COMMAND
where COMMAND is one of:
crawl one-step crawler for intranets
readdb read / dump crawl db
mergedb merge crawldb-s, with optional fi
readlinkdb read / dump link db
inject inject new urls into the database
generate generate new segments to fetch
fetch fetch a segment's pages
parse parse a segment's pages
segread read / dump segment data
mergesegs merge several segments, with opti
updatedb update crawl db from segments aft
invertlinks create a linkdb from parsed segme
mergelinkdb merge linkdb-s, with optional fil
index run the indexer on parsed segment
merge merge several segment indexes
dedup remove duplicates from a set of s
plugin load a plugin and run one of its
server run a search server
or
CLASSNAME run the class named CLASSNAME
Most commands print help when invoked w/o parameters.
2. 執行bin/nutch後面再加一個裸命令(無參數),可以察看這個命令的用法,比如
bin/nutch crawl斷行符號,可能輸出:
Usage: Crawl <urlDir> [-dir d] [-threads n] [-depth i] [-topN N]
3. 可以用readdb, readlinkdb,segread等命令幫你檢查你的資料。
Intranet Crawling:
適合抓取網頁預期總數在一百萬,網站數量有限的情況,一步式命令bin/nutch crawl,比較舒服,對於很多垂直
搜尋領域已經足夠。
Whole-web Crawling:
抓取WWW海量資料,一般可分為
inject 注入url,
generate 產生抓取列表,
fetch 抓取網頁,
updatedb 更新crawldb,
invertlinks 建立串連資料庫,
index 建立索引
dedup 去重
merge 合并索引
其實這兩種模式基本上一樣的,可以互換,差別只是設定檔的不同(個人見解!)。如果是crawl命令,可能涉及的設定檔crawl-urlfilter.txt, regex-urlfilter.txt,prefix-urlfilter.txt,suffix-urlfilter.txt,automaton-urlfilter.txt, 注意設定檔要放在類搜尋路徑上,如果你用bin/nutch指令碼來啟動程式,則這些設定檔都應該在conf目錄中找到。還有一點要注意的是,這些filter檔案是否生效,要看你的外掛程式配置情況,哎天哪,什麼都需要配置!
執行下面的迴圈:
generate
fetch
updatedb
invertlinks
index
dedup
merge
我自己簡單修改了org.apache.nutch.crawl.Crawl, 產生了一個新類可以方便的一步式更新
package org.apache.nutch.crawl;
public class CrawlUpdate {
public static final Logger LOG = LogFormatter
.getLogger("org.apache.nutch.crawl.CrawlUpdate");
private static String getDate() {
return new SimpleDateFormat("yyyyMMddHHmmss").format(new Date(System
.currentTimeMillis()));
}
public static void main(String[] args) throws IOException {
if (args.length < 1) {
System.out
.println("Usage: CrawlUpdate [-dir d] [-threads n] [-topN N]");
return;
}
Configuration conf = NutchConfiguration.create();
conf.addDefaultResource("crawl-tool.xml");
JobConf job = new NutchJob(conf);
Path dir = new Path("crawl-" + getDate());
int threads = job.getInt("fetcher.threads.fetch", 10);
int topN = Integer.MAX_VALUE;
for (int i = 0; i < args.length; i++) {
if ("-dir".equals(args[i])) {
dir = new Path(args[i + 1]);
i++;
} else if ("-threads".equals(args[i])) {
threads = Integer.parseInt(args[i + 1]);
i++;
} else if ("-topN".equals(args[i])) {
topN = Integer.parseInt(args[i + 1]);
i++;
}
}
FileSystem fs = FileSystem.get(job);
if (!fs.exists(dir)) {
throw new RuntimeException(dir + " dosn't exist.");
}
LOG.info("crawl started in: " + dir);
LOG.info("threads = " + threads);
if (topN != Integer.MAX_VALUE)
LOG.info("topN = " + topN);
Path crawlDb = new Path(dir + "/crawldb");
Path linkDb = new Path(dir + "/linkdb");
Path segments = new Path(dir + "/segments");
Path indexes = new Path(dir + "/indexes" + getDate());
Path index = new Path(dir + "/index");
Path tmpDir = job.getLocalPath("crawl" + Path.SEPARATOR + getDate());
Path segment = new Generator(job).generate(crawlDb, segments, -1, topN,
System.currentTimeMillis());
new Fetcher(job).fetch(segment, threads, Fetcher.isParsing(job)); // fetch
if (!Fetcher.isParsing(job)) {
new ParseSegment(job).parse(segment); // parse it, if needed
}
new CrawlDb(job).update(crawlDb, segment); // update crawldb
new LinkDb(job).invert(linkDb, new Path[] { segment }); // invert links
// index, dedup & merge
new Indexer(job)
.index(indexes, crawlDb, linkDb, new Path[] { segment });
Path[] indexesDirs = fs.listPaths(dir, new PathFilter() {
public boolean accept(Path p) {
return p.getName().startsWith("indexes");
}
});
new DeleteDuplicates(job).dedup(indexesDirs);
List indexesParts = new ArrayList();
for (int i = 0; i < indexesDirs.length; i++) {
indexesParts.addAll(Arrays.asList((fs.listPaths(indexesDirs[i]))));
}
new IndexMerger(fs, (Path[]) (indexesParts
.toArray(new Path[indexesParts.size()])), index, tmpDir, job)
.merge();
LOG.info("crawl update finished: " + dir);
}
}
這樣我可以用如下模式來周期更新我的搜尋資料:
Crawl urlsdir -dir crawl -topN 1000 -- 第一次下載
CrawlUpdate -dir crawl -topN 1000 -- 更新
CrawlUpdate -dir crawl -topN 1000 -- 繼續更新
...
還沒搞明白,是lucene的限制還是基於什麼考慮,在更新時(準確說是更新索引時)要先停止tomcat,感覺有那麼一點不舒服。