求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
 
  
 
 
     
   
分享到
AWS云搜索的使用:极简Java API
 

发布于2013-7-31

 

这个实现方式中,我们发现的唯一缺点是缺乏用于上传数据和实现搜索的Java API。虽然亚马逊提供的REST API也能达到上述的目的,但是在Java代码中使用它们并不方便。为了简化搜索调用和数据上传功能,我们开发了一些简单的Java API,将在本文中逐一介绍。

数据定义

尽管亚马逊提供了数据上传和搜索响应的数据定义(以XML和JSON两种方式),但数据上传的文档中仅定义了Relax NG 模式,而搜索响应则未定义任何模式。

在我们的实现方式中,我们决定使用XML数据格式而不是JSON,这是因为进行XML数据封装更加简单——XML使用规范的数据格式,而JSON则是动态的(JSON的标签是动态定义,每个请求各异)。我们分别用下边的两种模式(列表1和列表2)来上传数据和搜索结果。

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
………………………………………………………………………………………….
<xsd:complexType name="fieldType">
<xsd:simpleContent>
<xsd:extension base="xsd:string">
<xsd:attribute name="name" type="field_nameType" />
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>

<xsd:complexType name="addType">
<xsd:sequence>
<xsd:element name="field" type="fieldType" maxOccurs="unbounded" />
</xsd:sequence>
<xsd:attribute name="id" type="IDType" />
<xsd:attribute name="version" type="versionType" />
<xsd:attribute name="lang" type="xsd:language" />
</xsd:complexType>

<xsd:complexType name="deleteType">
<xsd:attribute name="id" type="IDType" />
<xsd:attribute name="version" type="versionType" />
</xsd:complexType>

<xsd:complexType name="batchType">
<xsd:sequence>
<xsd:element name="add" type="addType" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="delete" type="deleteType" minOccurs="0" maxOccurs="unbounded" />
</xsd:sequence>
</xsd:complexType>

<xsd:element name="batch" type="batchType" />

<xsd:simpleType name="statusType">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="success"/>
<xsd:enumeration value="error" />
</xsd:restriction>
</xsd:simpleType>

<xsd:complexType name="errorsType">
<xsd:sequence>
<xsd:element name="error" type="xsd:string" maxOccurs="unbounded" />
</xsd:sequence>
</xsd:complexType>

<xsd:complexType name="warningsType">
<xsd:sequence>
<xsd:element name="warning" type="xsd:string" maxOccurs="unbounded" />
</xsd:sequence>
</xsd:complexType>

<xsd:complexType name="responseType">
<xsd:sequence>
<xsd:element name="errors" type="errorsType" minOccurs="0" />
<xsd:element name="warnings" type="warningsType" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="status" type="statusType"/>
<xsd:attribute name="adds" type="xsd:int"/>
<xsd:attribute name="deletes" type="xsd:int"/>
</xsd:complexType>

<xsd:element name="response" type="responseType" />
</xsd:schema>

Listing 1 Upload data schema

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://cloudsearch.amazonaws.com/2011-02-01/results"
xmlns="http://cloudsearch.amazonaws.com/2011-02-01/results"
elementFormDefault="qualified">

<xsd:complexType name="constraintType">
<xsd:attribute name="value" type="xsd:string"/>
<xsd:attribute name="count" type="xsd:int"/>
</xsd:complexType>

<xsd:complexType name="facetType">
<xsd:sequence>
<xsd:element name="constraint" type="constraintType" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
<xsd:complexType name="facetsType">
<xsd:sequence>
<xsd:element name="facet" type="facetType" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>

<xsd:complexType name="infoType">
<xsd:attribute name="rid" type="xsd:string" />
<xsd:attribute name="time-ms" type="xsd:int" />
<xsd:attribute name="cpu-time-ms" type="xsd:int" />
</xsd:complexType>

<xsd:complexType name="dType">
<xsd:simpleContent>
<xsd:extension base="xsd:string">
<xsd:attribute name="name" type="xsd:string" />
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>

<xsd:complexType name="hitType">
<xsd:sequence>
<xsd:element name="d" type="dType" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="id" type="xsd:string" />
</xsd:complexType>

<xsd:complexType name="hitsType">
<xsd:sequence>
<xsd:element name="hit" type="hitType" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="found" type="xsd:int" />
<xsd:attribute name="start" type="xsd:int" />
</xsd:complexType>

<xsd:complexType name="resultsType">
<xsd:sequence>
<xsd:element name="rank" type="xsd:string" />
<xsd:element name="match-expr" type="xsd:string" />
<xsd:element name="hits" type="hitsType" minOccurs="0"/>
<xsd:element name="facets" type="facetsType" minOccurs="0"/>
<xsd:element name="info" type="infoType" />
</xsd:sequence>
</xsd:complexType>

<xsd:element name="results" type="resultsType"/>

<xsd:complexType name="messageType">
<xsd:attribute name="severity" type="xsd:string" />
<xsd:attribute name="code" type="xsd:string" />
<xsd:attribute name="message" type="xsd:string"/>
</xsd:complexType>

<xsd:complexType name="errorType">
<xsd:sequence>
<xsd:element name="error" type="xsd:string" />
<xsd:element name="rid" type="xsd:string" />
<xsd:element name="time-ms" type="xsd:int" />
<xsd:element name="cpu-time-ms" type="xsd:int" />
<xsd:element name="messages" type="messageType" maxOccurs="unbounded" />
</xsd:sequence>
</xsd:complexType>

<xsd:element name="error" type="errorType" />

</xsd:schema>

Listing 2 Search results data schema

我们使用xjc binding compiler 生成上述的两种模式的Java类,这样就能通过Java Architecture for XML Binding (JAXB)进行自动封装/解封装。

查询定义

除了数据定义,实现搜索API还需要查询定义。我们已经创建了一组类,用来实现亚马逊的查询定义。

这个搜索查询的核心是过滤器。我们引入了SearchQueryFilter 接口,并提供了两种实现方式——Search Query Value Filter(列表3)和Search Query Filter Operation(列表4)。

public class SearchQueryValueFilter implements SearchQueryFilter{

private String _field;
private String _value;
private boolean _isExclude;
private boolean _isNumeric;

public SearchQueryValueFilter(){}

public SearchQueryValueFilter(String field, String value, boolean isNumeric, boolean isExclude){
_field = field;
_value = value;
_isExclude = isExclude;
_isNumeric = isNumeric;
}

public String getField() {
return _field;
}

public void setField(String field) {
_field = field;
}

public String getValue() {
return _value;
}

public void setValue(String value) {
_value = value;
}

public boolean isExclude() {
return _isExclude;
}

public void setExclude(boolean isExclude) {
_isExclude = isExclude;
}

public boolean isNumeric() {
return _isNumeric;
}

public void setNumeric(boolean isNumeric) {
_isNumeric = isNumeric;
}

@Override
public String toString(){
StringBuffer sb = new StringBuffer();
if(_isExclude){
sb.append("(not ");
}
if(_field != null){
sb.append(_field);
sb.append(":");
}
if(!_isNumeric){
sb.append("'");
}
sb.append(_value);
if(!_isNumeric){
sb.append("'");
}
if(_isExclude){
sb.append(")");
}
return sb.toString();
}
}

Listing 3 Value filter implementation

public class SearchQueryFilterOperation implements SearchQueryFilter {

List<SearchQueryFilter> _filters;
FilterOperation _operation;

public SearchQueryFilterOperation(){
_operation = FilterOperation.and;
_filters = new LinkedList<SearchQueryFilter>();
}

public List<SearchQueryFilter> getFilters() {
return _filters;
}

public void setFilters(List<SearchQueryFilter> filters) {
_filters = filters;
}

public void addFilters(SearchQueryFilter filter) {
_filters.add(filter);
}

public FilterOperation getOperation() {
return _operation;
}

public void setOperation(FilterOperation operation) {
_operation = operation;
}

@Override
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("(");
sb.append(_operation);
for(SearchQueryFilter f : _filters){
sb.append(" ");
sb.append(f);
}
sb.append(")");
return sb.toString();
}

public enum FilterOperation{
and, or
}
}

Listing 4 Operation filter implementation

Search Query Value Filter类支持开发者使用等于、小于、大于、区间(同样支持负值比较)等运算符设置单个字段的限制。而Search Query Filter Operation类还支持开发者使用AND/OR操作符,将多个Search Query Value Filters和Search Query Filter Operations组合使用。通过这两个类的组合使用,就能实现亚马逊云搜索所支持的任意查询过滤器的表达式了。

亚马逊云搜索支持分面分类(Faceted classification):

“分面分类系统支持对一个对象赋予多个特征(属性),支持按照多种方式对分类排序,而非按照单一的、预定的分类顺序。一个分面包括‘定义清晰、相互独立、完全穷尽的方面,某类属性、特征或是特定的主题’。【1】例如,藏书可以按照作者,主题,日期等归类。”

分面分类应用于分面搜索系统,用户在这种系统中能够从多方面进行信息的导航(译者注:如书籍可以从作者、主题、出版日期等不同的分面),多方面对应于不同顺序的分面。

AWS支持按分面控制搜索执行以及对搜索结果排序。同时还支持开发者控制返回的搜索结果中包含的分面数量。所有的分面操作由Search Query Facet(列表5)这个类来实现。

public class SearchQueryFacet {

private String _name;
private int _maxFacets;
private List<String> _constraints;
private FacetSort _sort;

public SearchQueryFacet(String name){
_name = name;
_maxFacets = -1;
_constraints = null;
_sort = FacetSort.none;
}

public SearchQueryFacet(String name, int maxFacets){
_name = name;
_maxFacets = maxFacets;
_constraints = null;
_sort = FacetSort.none;
}

public SearchQueryFacet(String name, int maxFacets, FacetSort sort){
_name = name;
_maxFacets = maxFacets;
_constraints = null;
_sort = sort;
}

public SearchQueryFacet(String name, int maxFacets, List<String> constraints){
_name = name;
_maxFacets = maxFacets;
_constraints = constraints;
_sort = FacetSort.none;
}

public SearchQueryFacet(String name, List<String> constraints){
_name = name;
_maxFacets = -1;
_constraints = constraints;
_sort = FacetSort.none;
}

public SearchQueryFacet(String name, FacetSort sort, List<String> constraints){
_name = name;
_maxFacets = -1;
_constraints = constraints;
_sort = sort;
}

public SearchQueryFacet(String name, FacetSort sort){
_name = name;
_maxFacets = -1;
_constraints = null;
_sort = sort;
}

public String getName() {
return _name;
}

public void setName(String name) {
_name = name;
}

public int getMaxFacets() {
return _maxFacets;
}

public void setMaxFacets(int maxFacets) {
_maxFacets = maxFacets;
}

public FacetSort getSort() {
return _sort;
}

public void setSort(FacetSort sort) {
_sort = sort;
}

public int get_maxFacets() {
return _maxFacets;
}

public void set_maxFacets(int _maxFacets) {
this._maxFacets = _maxFacets;
}

public List<String> getConstraints() {
return _constraints;
}

public void setConstraints(List<String> constraints) {
_constraints = constraints;
}

public void addConstraint(String constraint) {
if(_constraints == null)
_constraints = new LinkedList<String>();
_constraints.add(constraint);
}

@Override
public String toString(){
StringBuffer sb = new StringBuffer();
sb.append("&facet=");
sb.append(_name);
if(_maxFacets > 0){
sb.append("&facet-");
sb.append(_name);
sb.append("-top-n=");
sb.append(_maxFacets);
}
if((_constraints != null) && (_constraints.size() > 0)){
sb.append("&facet-");
sb.append(_name);
sb.append("-constraints=");
boolean first = true;
for(String c : _constraints){
if(!first)
sb.append("%2C");
else
first = false;
sb.append("%27");
sb.append(c);
sb.append("%27");
}
}
if(!_sort.equals(FacetSort.none)){
sb.append("&facet-");
sb.append(_name);
sb.append("-sort=");
sb.append(_sort);
}

return sb.toString();
}

public enum FacetSort{
none, alpha, count, max, sum
}
}
Listing 5 Facets control class

最后Search Query Sort类(列表6)实现了开发者对结果排序的控制。

public class SearchQuerySort {

private List<SearchRank> _ranks;

public SearchQuerySort(){
_ranks = new LinkedList<SearchRank>();
}

public void addRank(SearchRank rank){
_ranks.add(rank);
}
@Override
public String toString(){
if(_ranks.size() == 0)
return null;
StringBuffer sb = new StringBuffer();
sb.append("&rank=");
boolean first = true;
for(SearchRank r : _ranks){
if(!first)
sb.append("%2C");
else
first = false;
sb.append(r);
}
return sb.toString();
}

public static class SearchRank{
private String _name;
private boolean _ascending;

public SearchRank(){
_ascending = true;
}
public SearchRank(String name){
_ascending = true;
_name = name;
}
public SearchRank(String name, boolean ascending){
_ascending = ascending;
_name = name;
}

@Override
public String toString(){
if(_ascending)
return _name;
return "-" + _name;
}
}
}

Listing 6 Sort control class

CloudSearch查询除了将所有的参数汇总到一起,还增加了页码信息和一组返回字段。

这个查询类还提供了一个方法——HTTP查询转换(列表7),将搜索查询的所有部分汇总,并生成能被搜索处理的HTTP字符串。

public String toHttpQuery() throws Exception{
StringBuffer sb = new StringBuffer();
sb.append("?results-type=xml");
if(_size > 0){
sb.append("&size=");
sb.append(_size);
}

if(_start > 0){
sb.append("&start=");
sb.append(_start);
}

if((_fields != null) && (_fields.size() > 0)){
sb.append("&return-fields=");
boolean first = true;
for(String f : _fields){
if(!first)
sb.append("%2C");
else
first = false;
sb.append(f);
}
}

if(_filter != null){
if(_filter instanceof SearchQueryValueFilter)
sb.append("&q=");
else
sb.append("&bq=");
sb.append(URLEncoder.encode(_filter.toString(), "UTF8"));
}

if((_facets != null) && (_facets.size() > 0)){
for(SearchQueryFacet f : _facets){
sb.append(f);
}
}

if((_sorts != null) && (_sorts.size() > 0)){
for(SearchQuerySort s : _sorts){
sb.append(s);
}
}

return sb.toString();
}

Listing 7 Convert to HTTP query method

我们使用Apache HttpComponents来实现与亚马逊云搜索的通信。

测试我们的API

我们使用亚马逊提供的IMDB样例来进行验证。首次单元测试(列表8)用于验证我们实现的搜索API。

public class SearchAPITester extends TestCase {

private static final String SearchURL = "search-imdb-movies-ab4fpqw4eocczpgsnrtlu4rn7i.us-east-
1.cloudsearch.amazonaws.com";
private CloudSearchClient client;

protected void setUp() throws Exception {
client = new CloudSearchClient(SearchURL);
}

protected void tearDown() {
client.close();
}

public void testSearch() throws Exception{

SearchQueryValueFilter f1 = new SearchQueryValueFilter("title", "star", false, false);
SearchQueryValueFilter f11 = new SearchQueryValueFilter("title", "war", false, true);
SearchQueryValueFilter f2 = new SearchQueryValueFilter("year", "..2000", true, false);
SearchQueryFilterOperation f12 = new SearchQueryFilterOperation();
f12.setOperation(FilterOperation.or);
f12.addFilters(f1);
f12.addFilters(f11);
SearchQueryFilterOperation f3 = new SearchQueryFilterOperation();
f3.addFilters(f12);
f3.addFilters(f2);


CloudSearchQuery query = new CloudSearchQuery(f3);
query.addField("actor");
query.addField("director");
query.addField("title");
query.addField("year");


SearchQueryFacet sf = new SearchQueryFacet("genre", 5, FacetSort.alpha);
sf.addConstraint("Drama");
sf.addConstraint("Sci-Fi");
query.addFacet(sf);

SearchQuerySort sort = new SearchQuerySort();
SearchRank r1 = new SearchRank("title");
SearchRank r2 = new SearchRank("year", false);
sort.addRank(r1);
sort.addRank(r2);
query.addSort(sort);

try {
System.out.println("Test 1 ");
SearchResults result = client.search(query);
System.out.println(result);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Listing 8 Search API tester

该测试获得的结果(列表9),和直接通过亚马逊REST API获得的结果相同。

SearchResults 
[ID=6ddcaa561c05c4cc3dae0f2d67b89419fbfea467ac6292b612dfb3a4a547692c6bea0194d6d37630b171b100197578dc, hitcount=1942, start=0, expression=(and (or title:'star' (not title:'war')) year:..2000), execution time=35ms, cpu execution time=0ms Hit [ID=tt0092493, values={title:['Crocodile' Dundee II]year:[1988] actor:[Blinco, Maggie,Dingo, Ernie,Hogan, Paul,Holt, Jim,Kozlowski, Linda,Meillon, John,Mercurio, Gus,Rackman, Steve,Scavone, Anthony,Skilton, Gerry,Wilson, Alec]director:[Cornell, John]}]
Hit [ID=tt0078718, values={title:[...And Justice for All.]year:[1979]actor:[Bryggman, Larry, Christian, Robert,Forsythe, John,Lahti, Christine,Levene, Sam,Pacino, Al,Strasberg, Lee,Tambor, Jeffrey,Waites, Thomas G.,Warden, Jack,Williams, Jonathan]director:[Jewison, Norman]}]
Hit [ID=tt0078721, values={title:[10]year:[1979]actor:[Andrews, Julie,Crosby, Denise,Daly, Rad,Dennehy, Brian,Derek, Bo,Haven, Annette,Jones, Sam J.,LeMay, Dorothy,Money, Constance,Moore, Dudley,Royalle, Candida,Serena,Showalter, Max,Volz, Nedra, Wallace, Dee,Webber, Robert]director:[Edwards, Blake]}]
Hit [ID=tt0147800, values={title:[10 Things I Hate About You]year:[1999]actor:[Babin, Michelle,Bennett, Tim,Blake, Shelsie,Gordon-Levitt, Joseph,Junger, Gil,Keegan, Andrew,Kountz, Daniel,Krumholtz, David,Ledger, Heath,Magnuson, Katy,Matthews, Amber,Miller, Larry,Mitchell, Daryl,O'Neill, Bridget,Oleynik, Larisa,Pratt, Susan May,Snider, Tommy,Stiles, Julia,Union, Gabrielle,Zorich, Jay]director:[Junger, Gil]}]
Hit [ID=tt0214388, values={title:[100 Girls]year:[2000]actor:[Billman, Ange, Chriqui, Emmanuelle,DeBello, James,Graham, Aimee,Grant, Tanisha,Green, Johnny,Heigl, Katherine,Hiraizumi, Gina,Musiala, Agnieszka,Oleynik, Larisa,Pressly, Jaime,Ribisi, Marissa,Tucker, Jonathan]director:[Davis, Michael]}]
Hit [ID=tt0115433, values={title:[101 Dalmatians]year:[1996]actor:[Close, Glenn,Daniels, Jeff,Fielder, Harry,Fraser, Hugh,Laurie, Hugh,McInnerny, Tim,Mullard, Arthur,Plowright, Joan,Richardson, Joely, Richardson, Laurence,Shrapnel, John,Weiss, Zohren,Welker, Frank,Williams, Mark]director:[Herek, Stephen]}]
Hit [ID=tt0050083, values={title:[12 Angry Men]year:[1957]actor:[Balsam, Martin,Begley, Ed,Binns, Edward, Bond, Rudy,Cobb, Lee J.,Fiedler, John,Fonda, Henry,Kelly, James,Klugman, Jack,Marshall, E.G.,Nelson, Billy, Savoca, John,Sweeney, Joseph,Warden, Jack]director:[Lumet, Sidney]}]
Hit [ID=tt0103594, values={title:[1492: Conquest of Paradise]year:[1992]actor:[Assante, Armand,Dean, Loren,Depardieu, Gérard,Dunn, Kevin,Karyo, Tchéky,Langella, Frank,Molina, ángela,Montero, Silvia, Rey, Fernando,Weaver, Sigourney,Wincott, Michael]director:[Scott, Ridley]}]
Hit [ID=tt0078723, values={title:[1941]year:[1979]actor:[Aykroyd, Dan,Beatty, Ned,Belushi, John,Caan, James,Cheshire, Denise,Gary, Lorraine,Hamilton, Murray,Lassick, Sydney,Lauren, Mo,Lee, Christopher, Marshall, Penny,Matheson, Tim,Mifune, Toshir?,Moriarty, Steve,Oates, Warren,Robinson, Hank,Rothstein, Debbie,Stack, Robert]director:[Spielberg, Steven]}]
Hit [ID=tt0046672, values={title:[20000 Leagues Under the Sea]year:[1954]actor:[Cooper, Ted,Daheim, John,Douglas, Kirk,Gargan, Jack,Graham, Fred,Harvey, Harry,Helton, Percy,Kerrigan, J.M.,Lorre, Peter,Lukas, Paul,Lummis, Dayton,Marr, Eddie,Mason, James,Mitchell, Laurie,Pall, Gloria,Pennick, Jack,Vigran, Herb,Wilke, Robert J.,Young, Carleton,de Corsia, Ted]director:[Fleischer, Richard]}]
Facet [name=genre, values={(Sci-Fi,237},(Drama,1063}}]
]

列表9 搜索API测试结果

第二次测试(列表10)用来验证文档的添加和删除。

public class DocumentAPITester extends TestCase {

private static final String DocumentURL = "doc-imdb-movies-ab4fpqw4eocczpgsnrtlu4rn7i.us-east-
1.cloudsearch.amazonaws.com";
private CloudSearchDocumentClient client;
private BatchType batch;

protected void setUp() throws Exception {
client = new CloudSearchDocumentClient(DocumentURL);

FieldType title = new FieldType();
title.setName("title");
title.setValue("The Seeker: The Dark Is Rising");
FieldType director = new FieldType();
director.setName("director");
director.setValue("Cunningham, David L.");
FieldType genrea = new FieldType();
genrea.setName("genre");
genrea.setValue("Adventure");
FieldType genred = new FieldType();
genred.setName("genre");
genred.setValue("Drama");
FieldType genref = new FieldType();
genref.setName("genre");
genref.setValue("Fantasy");
FieldType genret = new FieldType();
genret.setName("genre");
genret.setValue("Thriller");
FieldType actor1 = new FieldType();
actor1.setName("actor");
actor1.setValue("McShane, Ian");
FieldType actor2 = new FieldType();
actor2.setName("actor");
actor2.setValue("Eccleston, Christopher");
FieldType actor3 = new FieldType();
actor3.setName("actor");
actor3.setValue("Conroy, Frances");
FieldType actor4 = new FieldType();
actor4.setName("actor");
actor4.setValue("Conroy, Frances");
FieldType actor5 = new FieldType();
actor5.setName("actor");
actor5.setValue("Ludwig, Alexander");
FieldType actor6 = new FieldType();
actor6.setName("actor");
actor6.setValue("Crewson, Wendy");
FieldType actor7 = new FieldType();
actor7.setName("actor");
actor7.setValue("Warner, Amelia");
FieldType actor8 = new FieldType();
actor8.setName("actor");
actor8.setValue("Cosmo, James");
FieldType actor9 = new FieldType();
actor9.setName("actor");
actor9.setValue("Hickey, John Benjamin");
FieldType actor10 = new FieldType();
actor10.setName("actor");
actor10.setValue("Piddock, Jim");
FieldType actor11 = new FieldType();
actor11.setName("actor");
actor11.setValue("Lockhart, Emma");
AddType add = new AddType();
add.setId("tt0484562");
add.setVersion(1l);
add.setLang("en");
add.getField().add(title);
add.getField().add(director);
add.getField().add(genrea);
add.getField().add(genred);
add.getField().add(genref);
add.getField().add(genret);
add.getField().add(actor1);
add.getField().add(actor2);
add.getField().add(actor3);
add.getField().add(actor4);
add.getField().add(actor5);
add.getField().add(actor6);
add.getField().add(actor7);
add.getField().add(actor8);
add.getField().add(actor9);
add.getField().add(actor10);
add.getField().add(actor11);

DeleteType delete = new DeleteType();
delete.setId("tt0301199");
delete.setVersion(1l);

batch = new BatchType();
batch.getAdd().add(add);
batch.getDelete().add(delete);

}

protected void tearDown() {
client.close();
}

public void testSearch() throws Exception{

try {
System.out.println("Test 1 ");
ResponseType result = client.index(batch);
System.out.println("Status " + result.getStatus() + " Added " + result.getAdds() + " Deleted " +
result.getDeletes());
} catch (Exception e) {
e.printStackTrace();
}
}
}

Listing 10 Document upload tester

测试也获得了预期的结果(列表11)

Status SUCCESS Added 1 Deleted 1
Listing 11 Document upload test results

总结

上面这些简单的Java API实现了亚马逊云搜索的功能,显著简化了亚马逊云搜索功能在已有Java应用中的使用,必然会扩大应用的影响范围。

相关文章

Java微服务新生代之Nacos
深入理解Java中的容器
Java容器详解
Java代码质量检查工具及使用案例
相关文档

Java性能优化
Spring框架
SSM框架简单简绍
从零开始学java编程经典
相关课程

高性能Java编程与系统性能优化
JavaEE架构、 设计模式及性能调优
Java编程基础到应用开发
JAVA虚拟机原理剖析
 
分享到
 
 


Java 中的中文编码问题
Java基础知识的三十个经典问答
玩转 Java Web 应用开发
使用Spring更好地处理Struts
用Eclipse开发iPhone Web应用
插件系统框架分析
更多...   


Struts+Spring+Hibernate
基于J2EE的Web 2.0应用开发
J2EE设计模式和性能调优
Java EE 5企业级架构设计
Java单元测试方法与技术
Java编程方法与技术


Struts+Spring+Hibernate/EJB+性能优化
华夏基金 ActiveMQ 原理与管理
某民航公司 Java基础编程到应用开发
某风电公司 Java 应用开发平台与迁移
日照港 J2EE应用开发技术框架与实践
某跨国公司 工作流管理JBPM
东方航空公司 高级J2EE及其前沿技术
更多...