【阿里云产品公测】大数据下精确快速搜索OpenSearch

【阿里云产品公测】大数据下精确快速搜索OpenSearch

作者:阿里云用户小柒2012

 

      相信做过一两个项目的人都会遇到上级要求做一个类似百度或者谷歌的站内搜索功能。传统的sql查询只能使用like 或者FIND_IN_SET来实现、后者性能稍微好点但是必须要逗号分隔才可以实现匹配、甚至多条件的话还可能用到OR这是极影响系统性能的。

       最近公司项目需要、主要是系统查询缓慢、并且查询精度不敢恭维。一开始想到的是Lucene 毕竟是一个开放源代码的全文检索引擎工具包 并且官方还在持续更新中。当时闲暇时间大概搞了将近一个星期的时间、索引的增删查改以及中文分词IKAnalyzer。但是数据量大了问题就来了、Lucene是不支持集群的。谷歌了半天找到一个叫solr的东西、它是基于Lucene的全文搜索服务器并且支持集群。然后就是各种搭环境配置中文分词、搭建zookeeper服务器、搭建solr服务器、然后是服务器之间的各种整合。期间出现的问题可谓是数不胜数、只能用2个字来形容”繁琐”。说了那么多顺便说说solr的安全性问题、SolrJ没有提供访问控制接口,也就是说只要知道solr服务器信息,任何人都可以连接solr服务器来进行索引增加、修改、删除操作。虽然有多种方式可以限制、但总觉得心里不踏实、但是阿里云的Opensearch就不一样了(见后面代码)。

      趁着阿里云搞活动、也是公司业务需要于是申请了Opensearch内测资格。

 

一:创建应用

1、创建应用名以及描述。

2、选择结构类型、因为是测试所以选择自定义结构。输入表明以及字段点击继续即可。

3、继续后会看到一个静态展示的表结构这时点击下一步即可。

4、因为没有购买阿里云的OSS和ODPS所以这里选择手动上传。

5、应用结构展示。

6、创建后还要激活应用。

7、这里你可以自定义配额、以后也可以自行修改(很人性化的功能)。

8、同第四步没有OSS和ODPS 这里直接选择完成即可、至此整个应用配置完毕。

9、因为本人是做javaWeb开发的所以这里选择java的SDK下载。

 

二:创建demo

1插入数据

本地测试插入1000条数据、push以后花费时间为4565ms

本地测试插入10000条数据、push以前花费时间106ms、push半天报错

复制代码

  1. 十月 10, 2014 8:43:48 上午 org.apache.http.impl.client.DefaultRequestDirector tryExecute

  2. 信息: I/O exception (java.net.SocketException) caught when processing request: Connection reset by peer: socket write error

  3. 十月 10, 2014 8:43:48 上午 org.apache.http.impl.client.DefaultRequestDirector tryExecute

  4. 信息: Retrying request

感觉应该是阿里云服务端做了限制、一次性push 10000条记录就会中断、选择每1000条数据push一次、 测试插入10000条数据:71940ms。

 

本地测试插入 五万条数据 一次push 1000条数据花费时间:210267ms

 

本地测试插入 十万条数据 一次push 1000条数据 到6万的时候中断、不清楚是否阿里云服务端限制、如果后台定时任务一次性构建百万或者千万条数据是否还有影响。

具体一次性push多少数据、我没有详细的测试、应该是越多越好、以上是测试数据仅供参考、并不是十分准确。

至此一共插入124147条数据 也算是10万级别的了。

2、查询数据

以上为查询关键词VPS分页查询10条数据查询时间为0.009275秒几乎可以忽略不计了。

 

三:系统测试

1、目前系统测试

系统为单核非集群、服务器为tomcat、数据库数据为5000条。

页面数据包括 基础查询条件以及表数据展示、单表字段为47个。

 

并发100人,页面搜索反应时间为0.73秒

应用服务器:30%<CPU<50%左右, 内存使用较小

数据库服务器:CPU<10%,内存使用较小

 

并发120人,页面搜索反应时间为1.18秒

应用服务器:30%<CPU<50%左右, 内存使用较小

数据库服务器:CPU<10%,内存使用较小

 

并发150人,页面搜索反应时间为5.08秒

应用服务器:CPU<50%左右, 内存使用较小

数据库服务器:CPU<10%,内存使用较小

 

根据以上12万数据的查询大体可以得出结论 并发150 应该会控制到ms级别。

 

最后附上测试代码:

 

复制代码

  1. package openSearch;

  2. import java.io.IOException;

  3. import java.util.HashMap;

  4. import java.util.Map;

  5. import org.apache.http.client.ClientProtocolException;

  6. import org.json.JSONException;

  7. import org.junit.Before;

  8. import org.junit.Test;

  9. import com.opensearch.javasdk.CloudsearchClient;

  10. import com.opensearch.javasdk.CloudsearchDoc;

  11. import com.opensearch.javasdk.CloudsearchSearch;

  12. import com.opensearch.javasdk.object.KeyTypeEnum;

  13. public class OpenSearch {

  14.     /**

  15.      * 阿里云OpenSearch采用Access Key 连接方式、相比solr安全系数不止提高了一个档次。

  16.      */

  17.     private static final String  ACCESSKEY = "xxx";

  18.     private static final String  SECRET  = "xxx";

  19.     private static final String  INDEXNAME = "52itstyle";

  20.     private static final String  URL = "http://opensearch.aliyuncs.com";

  21.     private CloudsearchClient client;

  22.     @Before

  23.     public void init() {

  24.        Map<String, Object> opts = new HashMap<String, Object>();

  25.        opts.put("host", URL);

  26.        client = new CloudsearchClient(ACCESSKEY, SECRET , opts,KeyTypeEnum.ALIYUN);

  27.     }

  28.     @Test

  29.     /**

  30.      * 测试数据插入

  31.      * @throws JSONException

  32.      * @throws ClientProtocolException

  33.      * @throws IOException

  34.      */

  35.     public void addTest() throws JSONException, ClientProtocolException, IOException{

  36.         CloudsearchDoc doc = new CloudsearchDoc(INDEXNAME, client);

  37.         Map<String, Object> ques = new HashMap<String, Object>();

  38.         //开始时间

  39.         Long beginDate = System.currentTimeMillis();

  40.         //插入50000条数据测试

  41.         for(int i=0;i<=50000;i++){

  42.             ques.put("id", "200003"+i);//ID主键

  43.             ques.put("title", "搞网站运营已有6年时间了)");

  44.             ques.put("content", "搞网站运营已有6年时间了,期间运营过大大小的网站10多个,空间、VPS国内国外都使用过。国内最普遍的环境就是不稳定,隔三差五不是被攻击就是线路调整。一直困惑不已。  ");

  45.             doc.add(ques);

  46.             //每加入1000条数据结束之后push一下

  47.             if(i%1000==0){

  48.                 doc.push("article");

  49.             }

  50.         }

  51.         //结束时间

  52.         Long endDate = System.currentTimeMillis();

  53.         System.out.print("插入50000条数据:"+(endDate-beginDate));

  54.     }

  55. }

 

javaWeb测试系统稍后放出 
 
评测总结: 
优点:

    1:   省去了配置以及维护solr运营成本、数据直接扔给opensearch、用户不用再去关心宕机、集群的问题。

    2:阿里后台有清晰的应用结构、错误日志、基本信息、配额管理以及数据统计、界面化管理一目了然。

    3:应用自定义结构、相比于solr的配置schema.xml要耐看的多。

    4:支持复杂查询、排序表达式、可聚合、可过滤以及多次查询等特点、基本满足了项目的需求。

    5:还有很多自己摸索、、、、

 
缺点: 
    1:推送数据、每秒推送次数5次 每个包大小编码前2M、这些限制肯定有它的道理、服务开销或者技术瓶颈什么的、按说阿里不会有神马技术瓶颈吧。问题是如果数据丢失或者重构索引我应该一次push多少在表结构不是很确定的情况下。 
---数据推送可以批量发送,按照目前的设置每秒可以推送10M数据,基本可以满足用户需求,这个主要是从节省系统资源、提高效率来考虑的,当然如果有更多需求可以跟我们联系。另外,索引重建不需要重新推送数据。

    2:查看API 搜索返回的格式 有xml, json和protobuf 这三种、是否可以像solr一样导入@FILE 直接转化为试题类的API、这样其实包括add或者search 都会变得相对简单一些吧。 
---我们正在规划Lucene、Solr、ElasticSearch等通用开源产品的适配接口,方便开源用户无缝对接,敬请期待。

   3:是否能做的像CNZZ统计一样就更高达上了。 
---统计方面后续也会推出很多衍生产品,比如topquery、热词、相关文章、下拉提示等等,敬请期待。

   4:貌似后台索引只能单个删除、能否一键删除或者个性化删除。虽然这些功能API都可以做到、但是还是希望阿里能搞定它。 
---删除功能目前仅支持doc级别,后续会推出应用清空功能,如果还有其他需求可以反馈给我们。

   5:价格问题 你懂我懂大家都懂。 
---预计12月会启动商业化流程。


 
Opensearch整合小项目:目前只是实现了 分页飘红效果 后续API所有功能将补充完毕。 
 
Constants.java 存放常量: 

复制代码

  1. public class Constants {

  2.     //应用名称

  3.     public static final String  INDEXNAME = "52itstyle";

  4.     //分页条数

  5.     public static final int PAGESIZE = 10;

  6. }

 
OpenSearchUtil.java 获取服务: 

复制代码

  1. public class OpenSearchUtil {

  2.     private static final String  ACCESSKEY = "xxx";

  3.     private static final String  SECRET  = "xxx";

  4.     private static final String  URL = "http://opensearch.aliyuncs.com";

  5.     private static CloudsearchClient client;

  6.     private static Object lock = new Object();

  7.     public static CloudsearchClient getInstance() throws MalformedURLException {

  8.         if (client == null) {

  9.             synchronized (lock) {

  10.                 if (client == null) {

  11.                    Map<String, Object> opts = new HashMap<String, Object>();

  12.                      opts.put("host", URL);

  13.                      client = new CloudsearchClient(ACCESSKEY, SECRET , opts,KeyTypeEnum.ALIYUN);

  14.                 }

  15.             }

  16.         }

  17.         return client;

  18.     }

  19. }

 
OpenSearch.java 操作类 增删查改: 

复制代码

  1. public class OpenSearch extends BaseAction {

  2.     private Integer pageNo;

  3.     private String content;

  4.     public void queryOpenSearch() throws Exception{

  5.         CloudsearchSearch search = new CloudsearchSearch(OpenSearchUtil.getInstance());

  6.         // 添加指定搜索的应用:

  7.         search.addIndex(Constants.INDEXNAME);    

  8.         // 索引字段名称是您在您的数据结构中的“索引到”字段。

  9.         search.setQueryString(content);

  10.         //参数一 要飘红的字段 、参数二 数据截取字数100、参数三 多余部分...显示、参数四飘红显示几段 、参数五六为html标签可以自定义

  11.         search.addSummary("content", 200, "......", 3, "<font color='red'>", "</font>");

  12.         //分页查询

  13.         search.setStartHit((pageNo-1)*Constants.PAGESIZE > 0 ? (pageNo-1)*Constants.PAGESIZE : 0);

  14.         //每页显示10条

  15.         search.setHits(Constants.PAGESIZE);

  16.         //指定搜索返回的格式为json

  17.         search.setFormat("json");

  18.         //返回搜索结果。

  19.         printMsgToClient(search.search());

  20.     }

  21.     public Integer getPageNo() {

  22.         return pageNo;

  23.     }

  24.     public void setPageNo(Integer pageNo) {

  25.         this.pageNo = pageNo;

  26.     }

  27.     public String getContent() {

  28.         return content;

  29.     }

  30.     public void setContent(String content) {

  31.         this.content = content;

  32.     }

  33. }

 
search.html 页面展示: 

复制代码

  1. function openSearch(pageNo){

  2.     var content = $("#content").val()=="阿里云搜索"?"": $("#content").val();

  3.      $.ajax({

  4.             url:'openSearch_queryOpenSearch.action',

  5.               async:false,

  6.               type:'post',

  7.               dataType:"json",

  8.               data:{'time':(new Date()).toString(),'pageNo':pageNo,'content':content},

  9.             success:function(result){

  10.                 //alert(result.status);//返回状态

  11.                 //alert(result.result.searchtime);//查询时间

  12.                 //alert(result.result.total);//数据总数

  13.                 //alert(result.result.num);//展示个数

  14.                 //alert(result.result.viewtotal);//最多展示个数

  15.                 //alert(result.result.items)//实体数据

  16.                 var searchtime ="找到相关结果"+result.result.total+"条 (用时"+result.result.searchtime+"秒)";

  17.                 gotoPagePrev(pageNo,result.result.total,"perPagination","endPagination","openSearch",10,"master","条");

  18.                 $("#searchtime").html(searchtime);

  19.                 var array = eval(result.result.items);

  20.                 var str ='';

  21.                 for(var i=0;i<array.length;i++){

  22.                     str +='';

  23.                     str +='<div class="ttlist_box">';

  24.                     str +='  <div class="ttlist_tle jb_tit">';

  25.                     str +='<div class="ttlist_tle1 clearfix">';

  26.                     str +='<div class="tst_nm2 fl ">';

  27.                     str +=' <span>文章编号:<i class="c_gray">'+array[i].id+'</i></span>';

  28.                     str +='      </div>';

  29.                     str +='         <div class="tst_wuse fl ">';

  30.                     str +='         </div>';

  31.                     str +='         <div class="tst_dft fl">';

  32.                     str +='         </div>';

  33.                     str +='         <div class="tst_tjq fl ">';

  34.                     str +='         </div>';

  35.                     str +='         <div class="tst_tjd fl">';

  36.                     str +='         </div>';

  37.                     str +='         <div class="fr">';

  38.                     str +='         </div>';

  39.                     str +='      </div>';

  40.                     str +='      <div class="ttlist_tle2 clearfix">';

  41.                     str +='          <div class="tst_kng fl clearfix">';

  42.                     str +='           </div>';

  43.                     str +='            <div class="tst_skl fl clearfix">';

  44.                     str +='            </div>';

  45.                     str +='          <div class="tst_enj fl">';

  46.                     str +='           </div>';

  47.                     str +='       </div>';

  48.                     str +='   </div>';

  49.                     str +='  <div class="ttlist_cont clearfix">';

  50.                     str +='      <div class="st_ctg">'+array[i].content+'</div>';

  51.                     str +='   </div>';

  52.                     str +='</div>';

  53.                 }

  54.                 $("#master").html(str);

  55.             },

  56.         });

  57. }

 
 项目演示地址:http://121.42.26.72:8080/opensearch  
 

原文地址:http://bbs.aliyun.com/read/179042.html   

微博互动:http://weibo.com/1644971875/BrxCRmYbD?mod=weibotime#_rnd1413282678532 

参加活动:http://promotion.aliyun.com/act/aliyun/freebeta/ 

posted @ 2014-10-14 18:30  阿里云官方博客  阅读(1094)  评论(0编辑  收藏  举报