提交 f09c44b3 编写于 作者: W wizardforcel

ch16.

上级 60f5716c
# 第十六章 布尔搜索
在本章中,我展示了上一个练习的解决方案。然后,你将编写代码来组合多个搜索结果,并按照它与检索词的相关性进行排序。
## 16.1 爬虫的答案
首先,我们来解决上一个练习。我提供了一个`WikiCrawler`的大纲;你的工作是填写`crawl`。作为一个提醒,这里是`WikiCrawler`类中的字段:
```java
public class WikiCrawler {
// keeps track of where we started
private final String source;
// the index where the results go
private JedisIndex index;
// queue of URLs to be indexed
private Queue<String> queue = new LinkedList<String>();
// fetcher used to get pages from Wikipedia
final static WikiFetcher wf = new WikiFetcher();
}
```
当我们创建`WikiCrawler`时,我们传入`source`和 index。最初`queue`只包含一个元素,`source`
注意,`queue`的实现是`LinkedList`,所以我们可以在末尾添加元素,并从开头删除它们 - 以常数时间。通过将`LinkedList`对象赋给`Queue`变量,我们将使用的方法限制在`Queue`接口中;具体来说,我们将使用`offer`添加元素,以及`poll`来删除它们。
这是我的`WikiCrawler.crawl`的实现:
```java
public String crawl(boolean testing) throws IOException {
if (queue.isEmpty()) {
return null;
}
String url = queue.poll();
System.out.println("Crawling " + url);
if (testing==false && index.isIndexed(url)) {
System.out.println("Already indexed.");
return null;
}
Elements paragraphs;
if (testing) {
paragraphs = wf.readWikipedia(url);
} else {
paragraphs = wf.fetchWikipedia(url);
}
index.indexPage(url, paragraphs);
queueInternalLinks(paragraphs);
return url;
}
```
这个方法的大部分复杂性是使其易于测试。这是它的逻辑:
+ 如果队列为空,则返回`null`来表明它没有索引页面。
+ 否则,它将从队列中删除并存储下一个 URL。
+ 如果 URL 已经被索引,`crawl`不会再次对其进行索引,除非它处于测试模式。
+ 接下来,它读取页面的内容:如果它处于测试模式,它从文件读取;否则它从 Web 读取。
+ 它将页面索引。
+ 它解析页面并向队列添加内部链接。
+ 最后,它返回索引的页面的 URL。
我在 15.1 节展示了`Index.indexPage`的一个实现。所以唯一的新方法是`WikiCrawler.queueInternalLinks`
我用不同的参数编写了这个方法的两个版本:一个是`Elements`对象,包含每个段落的 DOM 树,另一个是`Element`对象,包含大部分段落。
第一个版本只是循环遍历段落。第二个版本是实际的逻辑。
```java
void queueInternalLinks(Elements paragraphs) {
for (Element paragraph: paragraphs) {
queueInternalLinks(paragraph);
}
}
private void queueInternalLinks(Element paragraph) {
Elements elts = paragraph.select("a[href]");
for (Element elt: elts) {
String relURL = elt.attr("href");
if (relURL.startsWith("/wiki/")) {
String absURL = elt.attr("abs:href");
queue.offer(absURL);
}
}
}
```
要确定链接是否为“内部”链接,我们检查 URL 是否以`/wiki/`开头。这可能包括我们不想索引的一些页面,如有关维基百科的元页面。它可能会排除我们想要的一些页面,例如非英语语言页面的链接。但是,这个简单的测试足以起步了。
这就是它的一切。这个练习没有很多新的材料;这主要是一个机会,把这些作品组装到一起。
## 16.2 信息检索
这个项目的下一个阶段是实现一个搜索工具。我们需要的部分包括:
+ 一个界面,其中用户可以提供检索词并查看结果。
+ 一种查找机制,它接收每个检索词并返回包含它的页面。
+ 用于组合来自多个检索词的搜索结果的机制。
+ 对搜索结果打分和排序的算法。
用于这样的过程的通用术语是“信息检索”,你可以在 <http://thinkdast.com/infret> 上阅读更多信息 。
在本练习中,我们将重点介绍步骤 3 和 4 。我们已经构建了一个 2 的简单的版本。如果你有兴趣构建 Web 应用程序,则可以考虑完成步骤 1。
## 16.3 布尔搜索
大多数搜索引擎可以执行“布尔搜索”,这意味着你可以使用布尔逻辑来组合来自多个检索词的结果。例如:
+ 搜索“java + 编程”(加号可省略)可能只返回包含两个检索词:“java”和“编程”的页面。
+ “java OR 编程”可能会返回包含任一检索词但不一定同时出现的页面。
+ “java -印度尼西亚”可能返回包含“java”,不包含“印度尼西亚”的页面。
包含检索词和运算符的表达式称为“查询”。
当应用给搜索结果时,布尔操作符`+``OR``-`对应于集合操作 交,并和差。例如,假设
+ `s1`是包含“java”的页面集,
+ `s2`是包含“编程”的页面集,以及
+ `s3`是包含“印度尼西亚”的页面集。
在这种情况下:
+ `s1``s2`的交集是含有的“java”和“编程”的页面集。
+ `s1``s2`的并集是含有的“java”或“编程”的页面集。
+ `s1``s2`的差集是含有“java”而不含有“印度尼西亚”的页面集。
在下一节中,你将编写实现这些操作的方法。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册