Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
OpenDocCN
think-dast-zh
提交
f09c44b3
T
think-dast-zh
项目概览
OpenDocCN
/
think-dast-zh
8 个月 前同步成功
通知
0
Star
26
Fork
13
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
T
think-dast-zh
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
f09c44b3
编写于
9月 24, 2017
作者:
W
wizardforcel
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
ch16.
上级
60f5716c
变更
1
隐藏空白更改
内联
并排
Showing
1 changed file
with
132 addition
and
0 deletion
+132
-0
16.md
16.md
+132
-0
未找到文件。
16.md
0 → 100644
浏览文件 @
f09c44b3
# 第十六章 布尔搜索
在本章中,我展示了上一个练习的解决方案。然后,你将编写代码来组合多个搜索结果,并按照它与检索词的相关性进行排序。
## 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.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录