`
tenght
  • 浏览: 52026 次
社区版块
存档分类
最新评论

AWS云搜索的使用:极简Java API

 
阅读更多

作者Boris Lublinsky

当前,许多应用重度依赖于搜索功能。从电子商务网站中寻找合适的产品,到社交网络中搜索寻人,再到地图网站中寻找POI和地址,依赖于搜索的应用非常广泛。

亚马逊新推出的云搜索服务,为自行实现搜索功能或定制安装Apache LuceneApache Solrelasticsearch等流行产品提供了可行的替代方式。他们这样描述该服务:

“它是一个完全托管的云搜索服务,该服务允许用户十分方便地在应用中集成快速且高度可扩展的搜索功能。【它】让用户摆脱了运营和扩展搜索平台的负担。用户不用再去关心硬件配置、数据分区和软件补丁的问题了。”

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

数据定义

尽管亚马逊提供了数据上传和搜索响应的数据定义(以XMLJSON两种方式),但数据上传的文档中仅定义了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应用中的使用,必然会扩大应用的影响范围。

关于作者

Boris Lublinsky博士是诺基亚首席架构师,主要从事大数据、SOA、BPM、中间件的实现。在此之前Boris曾经是Herzum软件公司的首席架构师,为客户设计大规模的SOA系统,曾负责CNA保险公司的企业架构,参与了CNA的系统集成与SOA策略的设计和实现,构建了应用框架并实现了面向服务的架构。Boris在企业、技术架构,软件工程方面有超过25年的经验。他还是OASIS SOA参考模型技术委员会的活跃会员,也是《Applied SOA:Service-Oriented Architecture and Design Strategies》,一书的共同作者。他还发表了大量架构、编程、大数据、SOA、BPM的相关文章。

查看英文原文:Using AWS Cloud Search


分享到:
评论

相关推荐

    aws-java-sdk-core-1.11.939-API文档-中文版.zip

    赠送原API文档:aws-java-sdk-core-1.11.939-javadoc.jar 赠送源代码:aws-java-sdk-core-1.11.939-sources.jar 包含翻译后的API文档:aws-java-sdk-core-1.11.939-javadoc-API文档-中文(简体)版.zip 对应Maven...

    aws-java-sdk-s3-1.11.939-API文档-中文版.zip

    赠送原API文档:aws-java-sdk-s3-1.11.939-javadoc.jar 赠送源代码:aws-java-sdk-s3-1.11.939-sources.jar 包含翻译后的API文档:aws-java-sdk-s3-1.11.939-javadoc-API文档-中文(简体)版.zip 对应Maven信息:...

    aws-java-sdk-core-1.12.160-API文档-中英对照版.zip

    赠送原API文档:aws-java-sdk-core-1.12.160-javadoc.jar; 赠送源代码:aws-java-sdk-core-1.12.160-sources.jar; 赠送Maven依赖信息文件:aws-java-sdk-core-1.12.160.pom; 包含翻译后的API文档:aws-java-sdk-...

    aws-java-sdk-kms-1.11.939-API文档-中文版.zip

    赠送原API文档:aws-java-sdk-kms-1.11.939-javadoc.jar 赠送源代码:aws-java-sdk-kms-1.11.939-sources.jar 包含翻译后的API文档:aws-java-sdk-kms-1.11.939-javadoc-API文档-中文(简体)版.zip 对应Maven信息:...

    aws-java-sdk-s3-1.11.939-API文档-中英对照版.zip

    赠送原API文档:aws-java-sdk-s3-1.11.939-javadoc.jar; 赠送源代码:aws-java-sdk-s3-1.11.939-sources.jar; 赠送Maven依赖信息文件:aws-java-sdk-s3-1.11.939.pom; 包含翻译后的API文档:aws-java-sdk-s3-1.11...

    aws-java-sdk-kms-1.12.160-API文档-中英对照版.zip

    赠送原API文档:aws-java-sdk-kms-1.12.160-javadoc.jar; 赠送源代码:aws-java-sdk-kms-1.12.160-sources.jar; 赠送Maven依赖信息文件:aws-java-sdk-kms-1.12.160.pom; 包含翻译后的API文档:aws-java-sdk-kms-...

    aws-java-sdk-kms-1.11.939-API文档-中英对照版.zip

    赠送原API文档:aws-java-sdk-kms-1.11.939-javadoc.jar; 赠送源代码:aws-java-sdk-kms-1.11.939-sources.jar; 赠送Maven依赖信息文件:aws-java-sdk-kms-1.11.939.pom; 包含翻译后的API文档:aws-java-sdk-kms-...

    aws-java-sdk-core-1.11.939-API文档-中英对照版.zip

    赠送原API文档:aws-java-sdk-core-1.11.939-javadoc.jar; 赠送源代码:aws-java-sdk-core-1.11.939-sources.jar; 赠送Maven依赖信息文件:aws-java-sdk-core-1.11.939.pom; 包含翻译后的API文档:aws-java-sdk-...

    jmespath-java-1.11.939-API文档-中文版.zip

    标签:amazonaws、jmespath、java、jar包、java、中文文档; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构保持不变,注释和说明精准翻译,...

    AWS云平台Visio模具

    AWS云平台Visio模具是专为IT专业人员设计的一套图形工具,用于在Microsoft Visio中绘制和展示Amazon Web Services (AWS) 的架构图。这个模具集合包含了AWS平台中的所有服务图标,使得用户能够准确、直观地描绘出复杂...

    jmespath-java-1.11.939-API文档-中英对照版.zip

    标签:amazonaws、jmespath、java、jar包、java、中英对照文档; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构保持不变,注释和说明精准...

    aws sdk - java

    AWS SDK for Java是亚马逊Web服务(Amazon Web Services, AWS)为Java开发者提供的一个软件开发工具包,它使得在Java应用程序中使用AWS服务变得更加便捷。这个SDK包含了一系列的库,允许开发者轻松地集成Amazon S3、...

    AWS S3 SDK for Java开发指南V1.0

    AWS S3 SDK for Java开发指南V1.0是专为JAVA开发者设计的文档,旨在指导他们如何使用这个SDK与XSKY EOS对象存储系统进行交互。AWS S3(Simple Storage Service)是亚马逊提供的一个高度可扩展、持久、安全且低成本的...

    AWS S3 Java 开发文档

    - 在使用AWS S3 Java SDK之前,需要确保开发者已经开通了AWS S3服务,并且配置了访问密钥对。 - 需要注意SDK版本与AWS服务端支持的版本兼容性问题。 - 在代码中硬编码访问密钥可能会带来安全风险,应使用更安全的...

    AWS 云从业者题库(中文版)

    主题:AWS 云从业者题库(中文版) 适合人群:准备参加 AWS 云从业者认证的技术人员 主要内容:AWS 云从业者题库(中文版) 阅读建议:多次反复阅读 收获:AWS 云从业者认证 介绍:AWS Certified Cloud Practitioner...

    AWS-CheatSheet::cloud:AWS备忘单:cloud:

    - **AWS SDK**:官方提供的多语言SDK,如Java、Python、JavaScript等,方便开发者与AWS服务进行交互。 - **AWS CLI(Command Line Interface)**:统一的命令行工具,用于管理和操作所有AWS服务。 6. **云管理**...

    AWS文档 - 框架和方法.zip

    AWS 无服务器多层架构:使用 Amazon API Gateway 和 AWS Lambda.pdf AWS 云采用框架:安全性前景.pdf AWS 云采用框架概览.pdf AWS 运营检查清单.pdf AWS云采用框架-流程论点.pdf AWS云采用框架-平台论点.pdf AWS云...

    aws-java-sdk-s3-1.12.353.jar中文-英文对照文档.zip

    解压 【aws-java-sdk-s3-***.jar中文-英文对照文档.zip】,再解压其中的 【aws-java-sdk-s3-***-javadoc-API文档-中文(简体)-英语-对照版.zip】,双击 【index.html】 文件,即可用浏览器打开、进行查看。...

    AWS_S3 linux C++存储 动态库

    在IT行业中,Amazon Web Services(AWS)的S3(Simple Storage Service)是一项广泛使用的云存储服务,它提供了安全、可扩展且高度可用的数据存储解决方案。本文将深入探讨如何在Linux环境下,利用C++语言和动态库与...

    jmespath-java-1.12.160-API文档-中英对照版.zip

    赠送原API文档:jmespath-java-1.12.160-javadoc.jar; 赠送源代码:jmespath-java-1.12.160-sources.jar; 赠送Maven依赖信息文件:jmespath-java-1.12.160.pom; 包含翻译后的API文档:jmespath-java-1.12.160-...

Global site tag (gtag.js) - Google Analytics