在Domino应用程序中集成Google的Web API服务
【IT168 技术文档】
使用 Google 的 Web API 服务向 Domino 应用程序添加 Google Web 搜索功能。本文将展示如何使用一个简单的代理在应用程序中实现该搜索功能。请下载代码示例,开始 googling 吧!
面对 Google 当前和不断扩充的 30 多亿个 Web 页面的索引,它之所以会成为在 Internet 上执行工业强度的搜索的非常好的工具之一就不难理解了。除了其 Web 页面的数量之外,搜索结果的质量之高也归功于其专有的搜索算法,该算法建立在相关性和流行性的基础上。最近的报告表明,Google 每天以 88 种不同的语言响应 2 亿个搜索请求(平均每秒响应 2,300 个请求!)。而根据 SearchEngineWatch.com 的调查,Google 处理了基于 Web 的所有查询中的百分之七十五。
显而易见,许多 Web 用户很熟悉 Google 及其搜索特性。不那么为人所知的事实是,您可以使用 Google 的 Web API 服务,将 Google 的搜索功能整合进自己的 Domino 应用程序中(正如我们将在下一节说明的那样,您可以免费下载这个 API)。本文讲述如何向 Domino 应用程序添加 Google 的搜索功能。我们将简要介绍 Google API 以及它们是如何工作的。然后我们将研究一个示例应用程序,它将 Google 搜索功能与 Domino 应用程序集成在一起。我们最后将提供一些如何扩充和定制这个简单例子的思路,从而结束本文的讨论。(本文中出现的所有例子都包含在一个 Domino 数据库中,您可以从 Sandbox下载该数据库。)
本文假设您是对编写 Domino 代理很熟悉的有经验的 Notes 应用程序开发人员。虽然高级 Java 经验不是理解我们的例子所必需的,但是强烈建议您了解一些 Java 的基础知识。
要使用 Google 的 API,请从 Google 的 Web API 下载页面下载 Google Web API 开发者工具箱(Googleapi.zip),并创建一个免费的 Google 帐户以获得一个许可密钥。该密钥允许您每天最多执行 1,000 次搜索(您必须在发出搜索请求时在查询中包括此密钥。这是通过编程方式完成的,因此用户不必在每次执行查询时都键入该密钥)。该开发者工具箱附带了文档和例子,使您对 Google 的自动化搜索如何工作有一个基本的了解。
在下载 Googleapi.zip 之后,请将它解压缩到 c:\Googleapi 目录中。然后您就可以通过在 MS-DOS 命令提示符下键入以下命令来快速调用该 Web API: java -cp Googleapi.jar com.Google.soap.search.GoogleAPIDemo <key> search Lotus Domino > result.html ,其中 < key > 是您的注册密钥,“Lotus Domino”是您想要搜索的项,result.html 是您想要将搜索结果写到其中的文件的名称。例如,下面的例子:
...
Start Index = 1
End Index = 10
Estimated Total Results Number = 663000
...
|
显示了估计的 663,000 项查询结果中的前 10 项结果。
不过,如果您在 Google Web 站点上试验相同的查询,可能会获得不同的结果。例如,在 Google上针对“Lotus Domino”的相同查询将产生估计的 596,000 项结果。(Google API 支持团队已证实,该 Web API 和 Google 站点本身使用相同的搜索引擎和索引页面,搜索结果方面的细微差别可能是由 Google 所维护的许多数据中心造成的。)
快速浏览一下 Googleapi 目录中的 GoogleAPIDemo.java:
清单 2. 摘自 GoogleAPIDemo.java 的代码片断
...
GoogleSearch s = new GoogleSearch();
...
GoogleSearchResult r = s.doSearch();
...
|
您可以发现 doSearch() 方法在设置许可密钥和搜索字符串属性之后调用了 Google 搜索。
在继续下一个例子之前,让我们快速查看一下您将使用的 Google Web API 中的几个方法:
- setKey()设置用户许可密钥。
- setQueryString()设置查询字符串。
- doSearch()调用 Google 搜索。
- toString()返回 Google 搜索结果的格式化表示形式。
- getResultElements()返回结果元素的数组。
- getSnippet()返回一个代码片断,这个代码片断显示它出现的地方的 URL 环境中的查询。
- getSummary()在当前文档包含于 ODP 目录中时返回 ODP 摘要。
- getTitle()返回 HTML 格式的搜索结果标题。
- getURL()返回搜索结果的绝对 URL。
此外,下面这组方法可以进一步完善您的搜索应用程序:
- setStartResult()设置要返回的第一个结果的索引。例如,如果有 500 个结果,您可能希望从第 100 个结果处开始返回。
- setMaxResults()设置每个查询要返回的最大结果数目。每个查询的最大值是 10。如果执行没有多少匹配项的查询,所获得的实际结果数目可能要比您所请求的少。
- setFilter()启用或禁用“相关查询”过滤器。这个过滤器排除非常相似的结果。
simpleSearch代理
下面让我们开始这个例子,在一个名为 GoogleSe.nsf 的新数据库中创建一个名为 simpleSearch 的 Notes 代理。您可以从 Sandbox下载这个数据库。这个数据库包含 simpleSearch 代理和 goSearch 代理,以及本文后将要讨论的表单和视图。这个应用程序是在 Windows 2000 上生成的,不过作为一个 Java 应用程序,它可以在任何平台上运行。在 Lotus Domino 中运行 Google API 不需要任何特殊的代理设置。当该 API 被调用时,它们将使用 Domino 所具有的任何配置。
首先复制开发者工具箱中的 GoogleAPIDemo.java 的以下代码行(注意 clientKey 是在您注册到 Google 之后,通过发送给您的许可密钥来初始化的):
清单 3. simpleAgent 代码
...
String clientKey = "4B0KufpQFHJxhAxzua0tR11ElLNrHRJ6";
String directive = "search";
String directiveArg = "Lotus Domino";
// Report the arguments received
System.out.println("Parameters:");
System.out.println("Client key = " + clientKey);
System.out.println("Directive = " + directive);
System.out.println("Args = " + directiveArg);
// Create a Google Search object, set our authorization key
GoogleSearch s = new GoogleSearch();
s.setKey(clientKey);
// Depending on user input, do search or cache query,
then print out result
try {
if (directive.equalsIgnoreCase("search")) {
s.setQueryString(directiveArg);
pw.println("about to begin doSearch...");
GoogleSearchResult r = s.doSearch();
pw.println("doSearch ok");
System.out.println("Google Search Results:");
System.out.println("======================");
System.out.println(r.toString());
...
|
在 Domino Designer 中创建 simpleSearch 并粘贴进上述代码。然后执行该代理。(本例中的搜索字符串被初始化为“Lotus Domino”。)要查看这个查询的结果,请在 simpleSearch 完成运行之后打开一个 Java Debug Console(Java 调试控制台)。您应该会看到类似如下的结果:
图 1. simpleSearch 结果
我们的 simpleSearch 代理提供了一种查看搜索结果的快速方式,它显示估计找到的 720,000 项结果中的前 10 项结果。例如,第一项包含以下内容:
清单 4. 搜索结果样例
URL = "http://www.lotus.com/"
Title = "IBM
Lotus software"
Snippet = "
... and societal demands
Domino Web Access demo upgraded to 6.5
All you've come to expect -- Lotusphere 2004 Basex Excellence Award goes to
IBM
Lotus Workplace
... "
Directory Category = {SE="", FVN="Top/Computers/Software/Operating_Systems/
Mainframe/IBM/Software"}
Directory Title = "
Lotus Software"
Summary = "IBM subsidiary best known for multi-platform Notes and
Domino
messaging groupware supports z/OS-based..."
Cached Size = "20k"
Related information present = true
Host Name = ""
|
如果从本地运行该代理,请确保 Googleapi.jar 文件位于 Notes 程序目录中并且被指派给了本地 Notes.ini 文件中的 JavaUserClasses(JavaUserClasses 具有 256 个字符的限制,因此如果向它添加 Googleapi.jar 超出了这个限制,Domino 将无法识别它)。
添加一个类似 Google 的界面
simpleSearch 返回的搜索结果是充满信息的,不过就表示来说显然是不够完善的。然而,您可以通过一种类似于 Google 所使用的格式来表示它们,从而极大地改进这些结果的可用性。为此,我们将创建一个名为 goSearch 的新代理,并且使用 simpleSearch 中的代码作为起点。我们还将向 GoogleSe.nsf 数据库添加两个表单 Search 和 Result(包含这些表单以及 simpleSearch 和 goSearch 代理的完整 GoogleSe.nsf 数据库可从 Sandbox下载)。
首先向 GoogleSe.nsf 数据库添加一个查询表单(我们把它命名为 Search)。这样允许用户输入和保存他们的查询字符串:
图 2. Search 表单
然后添加一个名为 Result 的输出表单来显示查询结果:
图 3. Results 表单
现在让我们生成一个比 simpleSearch 提供更完善功能的代理,包括处理查询列表的自动化功能和更像 "Google"的外观和感觉。首先复制 simpleSearch 中的代码,并将它粘贴进 goSearch 中。然后添加以下代码,用 Google 所使用的相同文本颜色来显示结果,并使用 Notes 中的 RTF 字段来输出 HTML:
...
style.setColor(RichTextStyle.COLOR_BLUE);
//renders HTML into rich text fields
String str = re[a].getTitle();
while (str.length() > 0 ) {
int i = str.indexOf("<b>");
int j = str.indexOf("<b>");
style.setBold(RichTextStyle.NO);
int k = i;
int len = 3;
if (j<i || (j>i && i==-1)) {
style.setBold(RichTextStyle.YES);
&n! bsp; k=j;
len=4;
}
//no more <b> or </b> left on str
if (i==-1 && j==-1) {
title.appendStyle(style);
title.appendText(str);
break;
}
! String sstr = str.substring(0,k);
if (sstr.length()==0) {
sstr="";
}
title.appendStyle(style);
title.appendText(sstr);
str = str.substring(k+len);
}
...
|
接下来向 goSearch 代理添加以下代码。这个代码片断把查询结果合并到 Result 文档中:
清单 6. 将查询结果合并到 Result 文档的代码
…
Document ndoc = db.createDocument();
ndoc.appendItemValue("Form", "Result");
RichTextItem title = ndoc.createRichTextItem("Title");
...
RichTextItem snippet = ndoc.createRichTextItem("Snippet");
...
ndoc.appendItemValue("URL", re[a].getURL());
...
ndoc.save();
…
|
最后添加以下代码来执行所有保存为 Search 文档的查询字符串,并将对应的结果生成为 Result 文档。
清单 7. 执行查询和生成 Result 文档的代码
...
View view = db.getView("AllSearches");
Document doc = view.getFirstDocument();
while (doc != null) {
...
int a=r.getStartIndex() - 1;
int b=r.getEndIndex() - 1;
//reiterate the result set
while (a<=b) {
...
&! nbsp; a++;
}
doc = view.getNextDocument(doc);
}
...
|
上面的例子允许在 Google 的搜索引擎中执行批量查询,并批量保存结果以供以后分析。由于结果保存起来了,所以您可以通过监控某些主题的搜索频率来分析趋势。这可以通过按查询字符串和日期来排序及显示 Result 文档来实现,如下面的 AllResultsByTitleDate 视图所示:
图 4. AllResultsByTitleDate 视图
Title 字段是一个 RTF 字段。因此,您需要创建一个新的 RTF 字段,在 Result 文档中存储未格式化的文本值,以便您能在上面的视图中将它作为列的值来使用 :ndoc.appendItemValue("TitleText", title.getFormattedText(false, 0, 0));
可考虑的其他思路
goSearch 代理可以计划在非高峰时间运行,以降低流量和提高效率。另一种改进 goSearch 代理的思路是在每当遇到 HTML 格式的字符串时调用分析器。
...
class Parser {
//renderHTML takes 5 arguments: HTML string,
rich text style, rich text item
reference, delimiter 1 and 2
void renderHTML(String html, RichTextStyle style, RichTextItem rtitem,
String delim1, String delim2) {
try {
System.out.println("html:" + html);
style.setColor(RichTextStyle.COLOR_BLUE);
//renders HTML into rich text fields
while (html.length() > 0 ) {
int i = html.indexOf(delim1);
int j = html.indexOf(delim2);
style.setBold(RichTextStyle.NO);
int k = i;
int len = 3;
if (j<i || (>i && i==-1)) {
style.setBold(RichTextStyle.YES! );
k=j;
len=4;
}
//no more <b> or </b> left on str
if (i==-1 && j==-1) {
rtitem.appendStyle(style);
rtitem.appendText(html);
break;
}
String sstr = html.substring(0,k);
if (sstr.length()==0) {
sstr="";
}
rtitem.appendStyle(style);
rtitem.appendText(sstr);
html = html.substring(k+len);
}
} catch(Exception e) {
e.printStackTrace();
}
}
}
|
这样得到的结果是一个更紧凑的代理类。
您可以使用 delim1 和 delim2 参数来扩充这个分析器所能处理的 HTML 标签集(比如 <h1>……</h1> 或 <p>),从而进一步扩展将 HTML 输入呈现为 Notes RTF 字段的思想。