级别: 初级 Arthur Choi (achoi@us.ibm.com), 技术销售顾问, IBM
2007 年 5 月 16 日 学习如何从自己的定制应用程序轻松地访问可免费下载的搜索引擎,IBM® OmniFind™ Yahoo! Edition(本文中简称为 OmniFind)。OmniFind 提供了一个 Representational State Transfer(REST)Web 服务,这个服务向其他应用程序公开它的搜索 API 和文档推送或删除 API。通过使用这些 API,可以编写定制的搜索应用程序,提供具有个性化外观和体验的搜索页面。还可以编写定制的爬行器应用程序,可以在 OmniFind 当前支持的 Web 和文件系统存储库之外的其他内容存储库中,推送和删除文档。
简介
与其他几种搜索引擎一样,OmniFind 也提供 REST API 来公开它的功能。为什么许多基于 Web 的应用程序和服务广泛使用 REST 作为服务交付机制?这有许多原因。
REST 客户机不需要任何额外的软件,只需要套接字接口和 XML 解析器,而这些是大多数计算平台都附带的软件。相反,SOAP Remote Procedure Call(RPC)客户机需要安装特殊的运行时库来处理额外的消息层和传输。因此,REST 客户机的软件依赖性很低。您还会发现 REST 的许多其他好处。关于 REST 体系结构的风格和优点的详细内容,请参考 REST Wikipedia Web 站点。
下面的讨论主要关注如何访问 OmniFind REST API 提供的每个服务,并用简短的示例代码片段加以说明。实现本文中的示例代码片段是为了补充 “IBM OmniFind Yahoo! Edition Programming Guide and API reference”。在这份编程指南和示例代码的帮助下,您可以立即开始编写定制的应用程序。因此,如果还没有下载 IBM OmniFind Yahoo! Edition,现在就下载它并开始使用 OmniFind REST API 编写定制的应用程序。
OmniFind REST API 概述
OmniFind API 公开的服务包括对索引进行搜索、在索引中添加文档以及从索引中删除文档。下面是 OmniFind REST API 的概况,其中包含服务端点 URL、底层 HTTP 方法的类型、必需的参数以及对服务的简短描述。
| 端点 URL | HTTP 方法 | 必需的参数 | 描述 |
|---|
| http://host:port/api/search | GET | index=Default, query | 搜索并以 atom 提要或 HTML 片段形式返回搜索结果 |
|---|
| http://host:port/api/document | POST | index=Default, action=addDocument, docType, docId | 向默认索引添加一个文档 |
|---|
| http://host:port/api/document | DELETE | index=Default, action=deleteDocument, docId | 从默认索引中删除一个文档 |
|---|
搜索 API 的端点 URL 是 http://host:port/api/search。搜索 API 使用 HTTP GET 方法发送查询和接收搜索结果。各个搜索参数以 HTTP GET URL 的形式传递。文档 API 的端点 URL 是 http://host:port/api/document。添加文档 API 使用 HTTP POST 方法。添加文档操作的各个参数作为 HTTP 请求头传递,实际的文档内容作为 HTTP POST 体传递。删除文档 API 使用 HTTP DELETE 方法。删除文档操作的各个参数作为 HTTP 请求头传递。
注意,尽管所有 OmniFind API 都需要 “index” 参数,但是 OmniFind 当前只支持一个预定义的索引,Default。因此 “index” 参数的值应该总是 “Default”。对于文档推送 API,需要将文档内容作为 HTTP POST 体推送,并使用 “docType” 参数设置适当的内容类型(比如 MIME 类型)。
docId 必须惟一地标识索引中的某个文档。对于文档推送和删除操作,docId 用来标识默认索引中的某个文档。docId 还用来在搜索之后获得原来的文档。为了正确地获得原来的内容,docId 必须是一个有效的 URL。如果 URL 是标准格式的,可以由浏览器直接处理,那么不需要做任何事情就可以获得原来的内容。否则,可能需要创建一个定制的文档检索 J2EE Web 应用程序并将 docId 传递给这个应用程序,这样就可以获得原来的文档。尽管获得原来的内容很重要,但是在本文中并不进一步讨论这个问题,因为它不是 OmniFind REST API 的一部分。
OmniFind REST API 的典型用途
通过编写定制的搜索 Web 应用程序,可以提供具有独特外观和体验的搜索页面。如图 1 所示,典型的定制搜索 Web 应用程序从客户机接收查询字符串,并使用 OmniFind 搜索 REST API 搜索 OmniFind 索引。如何显示搜索输入表单以及如何显示搜索结果完全取决于客户应用程序。定制的 Web 应用程序很可能结合使用 AJAX 和 DHTML,从而进一步改进用户体验和用户界面的响应性。定制的 Web 搜索应用程序通常部署在 J2EE 应用服务器中,这些应用程序通过 OmniFind REST API 使用 OmniFind 搜索服务。这些搜索应用程序与 OmniFind 服务器节点中嵌入的 J2EE 应用服务器进行交互来使用 OmniFind 搜索服务。
图 1. 定制的搜索应用程序
当前,OmniFind 支持的数据源包括 Web 站点和文件系统。为了对来自其他存储库的数据编制索引,需要编写定制的爬行器,这些爬行器从这些存储库获得文档并将它们推送给 OmniFind 索引。例如,如图 2 所示,为了将电子邮件编制进 OmniFind 索引,需要编写一个定制的电子邮件爬行器,它从电子邮件服务器提取电子邮件,并使用 OmniFind 文档推送 API 将提取的这些电子邮件推送到 OmniFind 索引。
图 2. 定制的爬行器
使用 Apache Jakarta Commons HttpClient & ROME 库
因为 OmniFind REST API 是基于标准的 HTTP 方法,所以对编程环境的惟一需求是,它要能够发送 HTTP GET/POST/DELETE 请求并处理对应的 HTTP 响应。基本上,所有平台和编程语言都支持 HTTP 协议。但是,本文只关注 Java™ 平台。
Java 平台提供 java.net.* 包,这个包使我们能够编写各种连网应用程序。可以使用原始套接字级接口或者来自 java.net 的更高级的 URLConnection 和 HttpURLConnection 类。但是,为了避免重复开发并进一步简化示例代码,这个示例中使用 Apache Jakarta Commons HttpClient 库 处理 HTTP 请求或响应。Apache HttpClient Web 站点对 Apache Jarkarta common HTTP 客户机库的目的做了如下说明:
“尽管 java.net 包为通过 HTTP 访问资源提供了基本的功能,但是它没有提供许多应用程序需要的全面的灵活性或功能。Jakarta Commons HttpClient 组件试图弥补这一欠缺,它提供一个高效的最新的特性丰富的包,实现了最新 HTTP 标准和推荐的客户端。”
使用的另一个开放源码库是 ROME(用于 Java 的 RSS 和 Atom 实用程序)。正如后面提到的,OmniFind 搜索 API 支持两种搜索响应格式:HTML 片段和默认的 Atom 1.0 提要格式。ROME 库简化了对 Atom 1.0 提要和其他几种联合提要格式的处理。它将原始的 XML 流映射到 Java 对象,Java 程序可以轻松地处理这些对象。
有了这些开放源码库的帮助,下面的讨论就可以用简短的示例程序解释 OmniFind REST API。
使用 OmniFind 搜索 API
通过 HTTP GET 方法访问 OmniFind 搜索 API。支持 8 个搜索参数:索引、查询文本、查询语言、输出格式、启始偏移量、结果语言过滤器、结果的数量和 XSL 样式表(用来对输出结果进行格式化)的完全限定 URL。在这些参数中,必需的参数只有索引和查询文本。如果没有指定其他参数,就采用默认值。关于支持的搜索请求参数的细节,请参考 “IBM OmniFind Yahoo! Edition Programming Guide and API reference”。
下面的程序是一个简单的 OmniFind 搜索应用程序,它通过使用 Apache HttpClient 库发送一个搜索请求并接收搜索响应:
清单 1. 示例搜索程序
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
/**
* This is a simple search example against the Omnifind default index.
*
* Steps as following; (1)construct HttpClient so that we can issue HTTP GET
* request later (2) construct search URL with the Omnifind search REST endpoint
* and any necessary parameters such as index and query parameters (3) construct
* GetMethod with the search URL (4) execute the GetMethod and check HTTP status
* (5) retrieve the search result
*/
public class SimpleSearch {
// omnifind the REST end point URL for Omnifind search
final static String targetSearchAPIEndpointURL = "http://localhost/api/search";
public static void main(String[] args) throws UnsupportedEncodingException {
// query string command line parameter
String queryString = args[0];
// construct HttpClient so that we issue HTTP GET request
HttpClient client = new HttpClient();
// construct search URL with the Omnifind search REST endpoint
// and any necessary parameters such as index and query
StringBuffer url = new StringBuffer();
url.append(targetSearchAPIEndpointURL);
url.append("?index=Default&");
url.append("query=" + java.net.URLEncoder.encode(queryString, "UTF-8"));
// construct GetMethod with the search URL
HttpMethod method = new GetMethod(url.toString());
try {
// execute the GetMethod and check http response
String responseBody = null;
int status = client.executeMethod(method);
if (status != HttpStatus.SC_OK) {
System.err.println("SimpleSearch failed: " + method.getStatusLine());
System.exit(status);
}
// retrieve the search result. By default it is in Atom 1.0 format
responseBody = method.getResponseBodyAsString();
// write out the response body
System.out.println(responseBody);
} catch (HttpException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// clean up the connection resources
method.releaseConnection();
}
}
} |
这个程序构造一个 HttpClient 对象和一个 OmniFind 搜索 URL。这个搜索 URL 只包含必需的 “index” 和 “query” 搜索参数。根据构造的 URL,实例化一个 GetMethod 对象并执行这个方法。在执行之后,GetMethod 类提供提取 HTTP 响应的各种方法。在这个示例中,使用简单的 getResponseBodyAsString 方法获得完整的响应字符串。但是,GetMethod 类提供了其他方法,这些方法返回一个输入流而不是字符串。对于长的大响应,建议使用来自响应的输入流。更多细节参见 Apache HTTP Client v3.1.Beta Javadocs。
这个程序返回的输出是一个 XML 字符串,它符合 Atom 1.0 联合提要格式。如果没有指定 “output” 格式参数,就会出现这种情况。OmniFind 支持两种搜索结果格式:Atom 1.0 和 HTML 片段。搜索结果格式由 “output” 搜索参数控制。如果没有指定这个参数,就使用默认的 Atom 1.0 格式。
清单 2. ATOM 格式的示例搜索结果
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"
xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/">
<title>Search results for query 'Axis' on index Default</title>
<link
href="http://localhost:8800/api/search?
index=Default&results=1&query=Axis"
rel="self" type="application/atom+xml" />
<author>
<name>IBM OmniFind Yahoo! Edition API Web Service</name>
</author>
<id>
http://localhost:8800/api/search?index=Default&
results=1&query=Axis
</id>
<category term="Default" label="Default" />
<updated>2007-01-07T03:09:48Z</updated>
<opensearch:totalResults>94</opensearch:totalResults>
<opensearch:Query role="request" searchTerms="Axis" />
<opensearch:startIndex>1</opensearch:startIndex>
<opensearch:itemsPerPage>1</opensearch:itemsPerPage>
<entry>
<link
href="http://www.javaworld.com/askTheExpert.jsp?
pagename=http:%2F%2Fwww.javaworld.com%2Fjavaworld%2Fjw-02-2006%2F
jw-0220-axis.html&pagename=%2Fjavaworld%2Fjw-02-2006%2F
jw-0220-axis.html&pageurl=%2Fjavaworld%2Fjw-02-2006%2F
jw-0220-axis.html&pubsite=j"
rel="alternate" type="text/html"
hreflang="en" />
<link
href="http://192.168.0.100:8800/search/?query=cache::http%3A%2F%2F
www.javaworld.com%2FaskTheExpert.jsp%3Fpagename%3Dhttp%3A%252F%252F
www.javaworld.com%252Fjavaworld%252Fjw-02-2006%252Fjw-0220-axis.html%26
pagename%3D%252Fjavaworld%252Fjw-02-2006%252Fjw-0220-axis.html%26
pageurl%3D%252Fjavaworld%252Fjw-02-2006%252F
jw-0220-axis.html%26pubsite%3Dj&output=binary"
rel="via" type="text/html"
hreflang="en" />
<opensearch:relevance>1.55</opensearch:relevance>
<title type="html">Feedback Form</title>
<updated>2007-01-06T14:56:04Z</updated>
<id>
http://www.javaworld.com/askTheExpert.jsp?pagename=http:%2F%2F
www.javaworld.com%2Fjavaworld%2Fjw-02-2006%2F
jw-0220-axis.html&pagename=%2Fjavaworld%2Fjw-02-2006%2F
jw-0220-axis.html&pageurl=%2Fjavaworld%2Fjw-02-2006%2F
jw-0220-axis.html&pubsite=j
</id>
<summary type="html">
<SPAN class="ellipsis">...
</SPAN>Feedback. Tell us your thoughts on this article
or the issues raised in it. We'll cc: the author
<SPAN class="ellipsis">
... </SPAN>
</summary>
</entry>
</feed>
|
为了编程式地处理 Atom 1.0 格式的搜索响应,可以使用任何 XML 解析器。不幸的是,这是一个非常冗长乏味的过程。好在开放源码类库 ROME 可以简化对 Atom 1.0 提要和其他许多联合提要格式的处理。ROME 基本上可以将任何 RSS 或 Atom feed 解析为规范的 bean 接口,SyndFeed。这就使开发人员能够处理 Java 对象而不是 XML 原始字符串。
下面的代码片段演示如何使用 ROME 处理搜索响应流。在这个示例中,从搜索响应流中提取第一个 “/feed/entry/link” 元素,并在控制台中显示它。为此,创建一个 SyndFeedInput 实例并提供搜索响应流。SyndFeedInput 返回 SyndFeed 对象实例,这样就可以访问必需的信息。关于 OmniFind Atom 1.0 元素的细节,请参考 “IBM OmniFind Yahoo! Edition Programming Guide and API reference”。
清单 3. 使用 ROME 解析的搜索示例
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import com.sun.syndication.feed.synd.SyndEntry;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.io.FeedException;
import com.sun.syndication.io.SyndFeedInput;
import com.sun.syndication.io.XmlReader;
/**
* This is a simple search example against an Omnifind default index. For this
* program, we are parsing the search results with ROME library to extract feed
* entries.
*
* Steps as following; (1)construct HttpClient so that we can issue HTTP GET
* request later (2) construct search URL with the Omnifind search REST endpoint
* and any necessary parameters such as index and query parameters (3) construct
* GetMethod with the search URL (4) execute the GetMethod and check HTTP status
* (5) retrieve the search result (6) convert the search result in ATOM to a
* SyndFeed using ROME library (7) extract feed entries
*/
public class SimpleSearchWithParsing {
// omnifind the REST end point URL for Omnifind search
final static String targetSearchAPIEndpointURL = "http://localhost/api/search";
public static void main(String[] args) throws UnsupportedEncodingException {
// query string command line parameter
String queryString = args[0];
// construct HttpClient so that we issue HTTP GET request
HttpClient client = new HttpClient();
// construct search URL with the Omnifind search REST endpoint and any
// necessary parameters such as index and query parameters
StringBuffer url = new StringBuffer();
url.append(targetSearchAPIEndpointURL);
url.append("?index=Default&");
url.append("results=1&");
url.append("query=" + java.net.URLEncoder.encode(queryString, "UTF-8"));
// construct GetMethod with the search REST end point URL
HttpMethod method = new GetMethod(url.toString());
try {
// execute the GetMethod and check http status
int status = client.executeMethod(method);
if (status != HttpStatus.SC_OK) {
System.err.println("SimpleSearchWithParsing failed: "
+ method.getStatusLine());
System.exit(status);
}
// retrieve the search result
// convert the search result in ATOM to a SyndFeed using ROME
// library
SyndFeedInput input = new SyndFeedInput();
SyndFeed feed = input.build(new XmlReader(method
.getResponseBodyAsStream()));
// extract feed entries
List list = feed.getEntries();
for (Iterator iter = list.iterator(); iter.hasNext();) {
SyndEntry entry = (SyndEntry) iter.next();
System.out.println(entry.getLink());
}
} catch (HttpException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (FeedException e) {
e.printStackTrace();
} finally {
// clean up the connection resources
method.releaseConnection();
}
}
} |
与前面的两个程序一样,发送搜索请求和处理响应是非常容易的,因为 API 基于标准的 HTTP 方法。有许多开放源码的 Java 库可以进一步简化对 OmniFind 搜索功能的访问。
正如前面提到的,OmniFind 支持两种搜索响应格式。除了默认的 Atom 1.0 提要格式之外,OmniFind 还可以以 HTML 片段格式返回搜索响应。只需添加 “output” 搜索参数并将它的值设置为 “htmlsnippet”,搜索响应就会以 HTML 片段的形式返回。清单 4 是一个 HTML 片段输出示例。这个 HTML 片段包含层叠样式和代表搜索响应列表的 HTML 元素。
清单 4. HTML 片段格式的搜索响应示例
<link rel="stylesheet" type="text/css" href="styles/nuvo.css">
<style>
body {
font-family: Verdana;
font-size: 12px;
background-repeat: no-repeat;
background-color: white;
}
.background {
background-repeat: no-repeat;
}
…
.resultFooterHtmlCachedLink {
font-family: Arial;
color: #8284cc;
}
.resultFooterOriginalCachedLink {
font-family: Arial;
color: #8284cc;
}
</style>
<div id=yschres>
<div id=yschcont style="margin-left:0px;">
<div id=yschpri style="margin-left:5px;">
<div id=yschrel>
</div>
<div id=yschweb>
<ol start=1>
<li>
<div>
<a class="yschttl" style="
font-family: Arial; color: #0000de; "
href="http://www.javaworld.com/
askTheExpert.jsp?pagename=http:%2F%2F
www.javaworld.com%2F
javaworld%2Fjw-02-2006%2F
jw-0220-axis.html&pagename=%2F
javaworld%2Fjw-02-2006%2F
jw-0220-axis.html&pageurl=%2F
javaworld%2F
jw-02-2006%2Fjw-0220-axis.html&pubsite=j">
Feedback Form</a>
</div>
<div class=yschabstr style="font-family: Arial;
color: black; ">
<SPAN class="ellipsis">... </SPAN>
Feedback. Tell us your thoughts on this article or
the issues raised in it. We'll cc: the
author <SPAN class="
ellipsis">... </SPAN></div>
<em class=yschurl style="font-family:
Arial; color: #088000; " >
http://www.javaworld.com/askTheExpert.jsp?pagename=http:%2F%2F
www.javaworld.com%2Fjavaworld%2Fjw-02-2006%2F
jw-0220-<SPAN class="
highlight"><SPAN class="
hlTerm0">axis</SPAN></SPAN>.html&
pagename=%2Fjavaworld%2Fjw-02-2006%2Fjw-0220-<SPAN class="
highlight"><SPAN class="
hlTerm0">axis</SPAN></SPAN>.html&
pageurl=%2Fjavaworld%2Fjw-02-2006%2Fjw-0220-<SPAN
class="highlight"><SPAN class="
hlTerm0">axis</SPAN></SPAN>.html&
pubsite=j </em>
-
</ol>
</div>
</div>
</div>
</div> |
HTML 片段输出格式更适合向最终用户显示搜索结果的 J2EE Web 应用程序。通过使用 DHTML,可以将返回的 HTML 片段动态地插入搜索结果页面。对于编程式访问,默认的 Atom 提要格式更合适。
有另一个与 Atom 提要格式相关的搜索参数,它称为 “stylesheet”。如果指定了这个参数,它应该是 XSL 样式表的完全限定 URL,这个样式表用来对输出结果进行格式化。这个参数只在 “output” 搜索参数的值为 “atomxml” 时是有效的。
注意,作为参数指定的 XSL 样式表不是在 OmniFind 搜索引擎中处理的。实际的转换是由客户机应用程序执行的,这些应用程序可以是支持 XSL 的 Web 浏览器或定制的 XSLT 应用程序。关于 OmniFind 搜索结果的 XSLT 转换的细节,请参考 “Add IBM Omnifind
Yahoo! Edition to your Web site”(developerWorks,2006 年 12 月)。
使用文档推送 API 添加文档
为了添加文档,需要使用 OmniFind 文档 API,与搜索 API 一样,这个 API 也基于标准的 HTTP 方法。但是,与搜索 API 不同,可以通过 HTTP POST 方法访问文档推送 API。与搜索不同,访问文档 API 时需要从 OmniFind 管理控制台提供一个 API 密码(参见图 3)。通过在管理控制台中点击 “Manage System -> Manage Authentication”,就可以获得 API 密码。
图 3. API 密码
下面的程序是一个简单的 OmniFind 文档推送客户机,它将一个 PDF 文档添加到默认的 OmniFind 索引中。它使用 Apache HttpClient 库发出一个 HTTP POST 方法,PostMethod。因为文档 API 需要 API 密码,所以使用 API 密码进行 HTTP 基本身份验证。不会使用并忽略基本身份验证的用户 ID。因此,它可以是任何值。
文档推送 API 支持 7 个参数:操作参数、索引、文档类型(docType)、文档内容后备语言(译者注:当应用程序的资源未被本地化为 “文档内容语言” 所指定的语种时,资源将被按照“文档内容后备语言”中指定的语种处理)、文档内容语言、文档 id(docId)和最后修改日期。在这些参数中,操作、索引、docType 和 docId 参数是必需的。如果没有指定,其他参数就保持 “IBM OmniFind Yahoo! Edition Programming Guide and API reference” 中指定的默认值。
清单 5. 文档推送程序示例
import java.io.File;
import java.io.IOException;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.methods.FileRequestEntity;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
/**
* This is a document push example.
*
* Steps as following; (1)construct HttpClient so that we can issue HTTP POST
* request later (2) set the credential using Omnifind API password (2)
* construct a PostMethod and set necessary request headers (4) set the request
* entity with the file content to be indexed (5) execute the PostMethod and
* check HTTP status (6) check an error
*/
public class PushPDFDocument {
// omnifind the REST end point URL for document push
final static String targetDocumentAPIEndpointURL = "http://localhost/api/document";
public static void main(String[] args) {
// construct HttpClient so that we issue HTTP POST request
HttpClient client = new HttpClient();
// set the credential using Omnifind API password
client.getState().setCredentials(new AuthScope("localhost", 80),
new UsernamePasswordCredentials("notused", "+UrSlFg="));
// construct a PostMethod and set necessary request headers
PostMethod method = new PostMethod(targetDocumentAPIEndpointURL);
method.setDoAuthentication(true);
method.setRequestHeader("action", "addDocument");
method.setRequestHeader("index", "Default");
method.setRequestHeader("docId", "pdfrepository://oye_api_guide_v84.pdf");
method.setRequestHeader("docType", "application/pdf");
try {
// set the request entity with the file content to be indexed
File input = new File("oye_api_guide_v84.pdf");
RequestEntity entity = new FileRequestEntity(input, "application/pdf");
method.setRequestEntity(entity);
// execute the post method and check HTTP status
int status = client.executeMethod(method);
if (status != HttpStatus.SC_OK) {
System.err.println("PushPDFDocument failed: " + method.getStatusLine());
System.exit(status);
}
// Note on the response from a document API call. The HTTP response
// code is always 200, with the exception of 401 for failed
// authentication. If an error occurs during the document insert
// process, the HTTP response code is still 200 and the HTTP
// response header contains a parameter of "hasError".
// Therefore, to do the proper handling of the document push result,
// you must check for the existence of the "hasError" response
// header or the HTTP 401 response code.
Header hasErrorHeader = method.getResponseHeader("hasError");
if (hasErrorHeader == null) {
System.out.println("document pushed fine.");
} else {
String errorResponse = method.getResponseBodyAsString();
System.out.println("error response: " + errorResponse);
}
} catch (HttpException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// clean up the connection resources
method.releaseConnection();
}
}
} |
为了添加 PDF 文档,这个程序创建一个 HttpClient 对象,并调用 setCredentials() 方法设置 HTTP 基本身份验证的用户 ID/密码凭证。添加文档操作所需的参数作为 HTTP 请求头传递。最后,实例化并执行 PostMethod 对象。在执行 PostMethod 之前,将实际的 PDF 文件设置为 PostMethod 的 HTTP POST 体。
注意,在文档推送 API 调用的响应中,HTTP 响应编码总是 200,但是如果身份验证失败,响应编码就是 401。如果在文档插入过程中出现错误,HTTP 响应编码仍然是 200,HTTP 响应头会包含参数 “hasError”。因此,为了正确地处理文档推送结果,必须检查是否存在 “hasError” 响应头或 HTTP 401 响应编码。
尽管在前面的程序中文档 ID 是任意设置的,但是这不是一种好做法,因为在搜索之后无法获得原来的文档。如果 docID 值不是有效的 URL,文档就不会成为搜索结果页面中的可点击的结果。例如,在执行上面的程序之后,我搜索刚添加的文档。搜索页面显示 “pdfrepository://oye_api_guide_v84.pdf” 链接。因为这个 docID 不是有效的 URL,所以如果点击它,就会显示一个错误页面。但是,通过点击 Cached 链接仍然可以查看原来的文档。对于您的程序,需要将 docId 设置为有效的 URL,这样就能够可靠地获得原来的文档。
图 4. 不可点击的链接
关于通过 OmniFind 文档推送 API 添加文档,要注意一点:编程指南指出,“在管理控制台中的 Document Status 窗口中,无法跟踪通过 addDocument API 添加进索引中的文档。”
使用文档 API 删除文档
为了删除文档,需要使用 OmniFind 文档 API;与搜索 API 一样,这个 API 也基于标准的 HTTP 方法。但是,与搜索 API 不同,可以通过 HTTP DELETE 方法访问文档删除 API。文档删除操作需要从 OmniFind 管理控制台提供 API 密码,见 图 3。
下面这个简单的程序从默认的 OmniFind 索引中删除一个 PDF 文档。与搜索程序一样,我们使用 Apache HttpClient 库发送一个 HTTP 方法。但是这一次,使用 Apache HttpClient 库的 DeleteMethod 而不是 GetMethod。因为文档 API 需要 API 密码,所以使用 API 密码进行 HTTP 基本身份验证。不使用并将忽略基本身份验证的用户 ID。因此,它可以是任何值。
文档删除 API 需要 3 个参数:操作参数、索引和文档 id(docId)。操作参数的值必须是 “deleteDocument”。索引参数的值必须是 “Default”。docId 应该惟一地标识要从默认索引中删除的特定文档。如果在索引中没有找到给定的 docId,就将它作为警告对待,删除 API 不会返回错误。
清单 6. 文档删除程序示例
import java.io.IOException;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.methods.DeleteMethod;
/**
* This is a document delete example.
*
* Steps as following; (1)construct HttpClient so that we can issue HTTP DELETE
* request later (2) set the credential using Omnifind API password (2)
* construct a DeleteMethod and set necessary request headers (4) execute the
* DeleteMethod and check HTTP status (5) check an error
*/
public class DeletePDFDocument {
// omnifind the REST end point URL for document push
final static String targetDocumentAPIEndpointURL = "http://localhost/api/document";
public static void main(String[] args) throws HttpException, IOException {
// construct HttpClient so that we issue HTTP POST request
HttpClient client = new HttpClient();
// set the credential using Omnifind API password
client.getState().setCredentials(new AuthScope("localhost", 80),
new UsernamePasswordCredentials("notused", "+UrSlFg="));
// construct a DeleteMethod and set necessary request headers
DeleteMethod method = new DeleteMethod(targetDocumentAPIEndpointURL);
method.setDoAuthentication(true);
method.setRequestHeader("action", "deleteDocument");
method.setRequestHeader("index", "Default");
// the docId of the document to be deleted
method.setRequestHeader("docId", "pdfrepository://oye_api_guide_v84.pdf");
try {
// execute the delete method
int status = client.executeMethod(method);
if (status != HttpStatus.SC_OK) {
System.err.println("DeletePDFDocument failed: "
+ method.getStatusLine());
System.exit(status);
}
// Note on the response from a document API call. The HTTP response
// code is always 200, with the exception of 401 for failed
// authentication. If an error occurs during the document insert
// process, the HTTP response code is still 200 and the HTTP
// response header contains a parameter of "hasError".
// Therefore, to do the proper handling of the document push result,
// you must check for the existence of the "hasError" response
// header or the HTTP 401 response code.
Header hasErrorHeader = method.getResponseHeader("hasError");
if (hasErrorHeader == null) {
System.out.println("document deleted.");
} else {
String errorResponse = method.getResponseBodyAsString();
System.out.println("error response: " + errorResponse);
}
} finally {
// clean up the connection resources
method.releaseConnection();
}
}
} |
注意:删除文档并不保证这个文档不再是可搜索的。编程指南指出,“文档变成不可搜索所需要的时间取决于发出删除请求时的搜索服务器负载。”
结束语
在本文中,给出了几个使用 OmniFind 搜索和文档功能的简单程序。因为 OmniFind API 基于标准的 HTTP 方法,而且有许多开放源码库和工具,所以访问 OmniFind 功能并不需要付出太大的努力。我们使用 Apache HttpClient 库处理 HTTP GET/POST/DELETE 方法。因为使用了开放源码的 ROME 库,只需几行代码就能够处理 Atom feed 格式的搜索结果。请下载 OmniFind Yahoo! Edition,并尝试用这些技术改进您的定制应用程序。
下载 | 描述 | 名字 | 大小 | 下载方法 |
|---|
| 本文的示例程序 | ofsamples.zip | 980KB | HTTP |
|---|
参考资料 学习
获得产品和技术
讨论
关于作者  | |  | Arthur Choi 当前是 IBM Information Management Division 的 Content Management & Discovery Center of Excellence 的技术销售顾问。他负责帮助 IBM 的客户将 IBM 的企业搜索解决方案部署到他们的企业计算环境中。他以前从事过各种企业搜索相关项目,包括 Lotus Extended Search 和 WebSphere Enterprise Search 产品。 |
对本文的评价
|