随着互联网数据规模的爆炸式增长,如何从海量的历史、实时 数据中快速获取有用信息,变得越来越具有挑战性。搜索是获取信息最高效的途径之一,因此也是各类网站、应用的基础标配功能。开发者想在自己的产品中实现搜索功能一般都是基于某个开源搜索系统(如ElasticSearch、Solr、Sphinx)搭建搜索服务。然而,除了购买主机或托管服务器,从系统熟悉、服务搭 建、功能定制,再到服务上线,通常需要耗费较长时间。
云搜索是一种结构化数据的搜索托管服务,开发者可将数据上传至云端进行数据处理和索引构建,再通过API使用云搜索服务。它的出现很好地解决了以上问题。OpenSearch(开放搜索服务)是阿里巴巴搜索事业部推出的一套自助式、可定制的云搜索服务,初衷是将阿里巴巴积累近10年的搜索引擎技术平台化、服务化,并开放给广大开发者,降低实现专业搜索产品的门槛,让开发者以较低的成本轻松拥有跟淘宝、天猫、一淘等应用的搜索工具类似的专业搜索产品。本文将介绍OpenSearch的发展历程、 基本功能及实现原理和架构,以实际应用场景为例讲述应用实践过程。
发展背景
2012年初,我们组建了云搜索技术团队,尝试将当时刚刚替换掉雅虎搜索的搜索引擎平台服务化和产品化。初期,OpenSearch的功能虽然简单,但已完全体现云服务的概念:用户通过各种方式上传数据到云端,云端进行数据处理和索引构 建,用户再通过API使用云端搜索服务,并整合到自己产品中。 产品Beta版发布后,在未做任何推广的情况下,服务了1200多家活跃网站,包括一些较大的垂直门户网站,例如威锋网、青岛新闻网等。
OpenSearch帮助开发者简化了使用搜索服务的复杂度,降低开发成本,加快产品迭代速度。以作文网为例,其站长仅靠自己摸索,从接触产品到上线仅用了一天时间。但我们也逐渐发现仅仅通过现有几个预制的应用场景模板远远满足不了开发者需求,因为不同属性的网站往往有不同的数据结构,千差万别的 相关性排序规则。
当时,我们内部在并行研发另外一款名为站内云搜索的产品,也是一款在云端提供搜索服务的产品,其数据结构固定,搜索结果样式可定制。站长开通这一服务后,网站数据可以被自动采集并进入系统。该产品的系统后台是从当时阿里云全网搜索系统(现为神马搜索)中剥离出来的,本质上类似谷歌、百度 等站内搜索工具,只是实时性更好。但由于无法满足对数据结构、相关性排序等做深度定制等需求,产品被叫停。
这些事例让我们认识到,虽然用户对云搜索服务的需求很大,但一定要有深度定制的服务,否则无法满足开发者复杂多变的搜索需求。
2013年初,我们将精力集中在降低服务成本和提升产品功能上:一方面优化存储和搜索服务架构;另一方面开发数据结构、相关性排序、数据处理定制功能。一年时间内,OpenSearch快速迭代,服务了阿里集团内部上百个产品和应 用。这段时间的技术积累和内部业务的锤炼对OpenSearch至关重要,促使其系统架构更加完善、性能更高、稳定性更好,定制能力也能满足绝大部分搜索产品的需求,同时服务成本降到了一个较低的水平。2014年7月,OpenSearch完成全面改版,并向外部开发者开放,在公测阶段受到了广大开发者的欢迎。在2015年1月,OpenSearch正式开始商业化售卖。
产品功能
OpenSearch有以下一些主要功能。
■ 支持文档索引结构定制,以及自由修改。OpenSearch将搜索引擎复杂的索引结构概念简单化、可视化和自助定制化。开发者可以通过控制台创建搜索实例,定制文档字段的结构和属性,包括字段名称、类型、分词方式、搜索属性等。搜索实例在运行过程中可以自由修改,满足了产品快速变化的需求,极大缩短了需求变更到上线的过程。
■ 支持多种数据接入方式,数据自动同步更新。开发者的数 据如果在阿里云的云存储服务(RDS、OSS、ODPS等)上,开发者 只需要在OpenSearch控制台中授权,数据就可以自动同步至 OpenSearch中,后续数据的更新也可以自动实时同步(ODPS 除外)。而且在同一区域中,从云存储同步数据至OpenSearch 免收流量费用。数据不在阿里云上的开发者,可以通过RESTful API或者SDK上传数据,小数据量也可以直接在控制台上传。
■ 支持多表,插件式数据处理。类似于数据库,每个搜索实例可以创建一张或者多张表,每张表的字段上可以内置数据处理 插件,对字段内容做文本处理和转换,例如拼音转换、HTML 标签剔除、JSON数据解释等,多个表可以Join在一起实现多表联合查询。数据存放在RDS数据库里的开发者,可以用此功能 替代数据库全文检索,实现更高的性能和搜索体验。
■ 支持搜索结果相关性两阶段排序定制,线上实时相关性调试。用户使用搜索功能的目的是从海量数据中找到自己想要的信息,搜索结果相关性排序是影响用户体验最关键的一环。 OpenSearch支持开发者定制两轮相关性排序规则来准确控制 搜索结果的排序。
第一轮为粗排,从命中的文档集合里海选出相关文档。支持配置字段、文本相关性和实效性算分特征的权重。第二轮为精排,对粗排的结果做更精细筛选,支持任意复杂的表达式和语 法。这样做除了方便开发者能更准确控制排序效果之外,更重要的是能优化系统性能,提高搜索响应速度。 开发者可以通过排序规则直接在控制台中调试效果,并在效果满意后直接切换 到线上。
实现原理和技术架构
OpenSearch底层搜索服务基于阿里自主研发的大规模分布式实时引擎平台ISearch 5,该平台有灵活的相关性计算框架和统 一的业务服务层,并且有自动容错和自动伸缩机制,承载了阿 里集团包括淘宝、天猫、神马搜索等在内的所有主要搜索业务流量,搜索请求峰值数十万QPS。图1是其整体架构图。
图1 OpenSearch整体架构
开发者通过控制台和API与系统交互。典型的使用流程是开发者进入控制台,创建应用实例,配置应用字段结构、搜索属 性、文本处理插件、定制相关性排序规则等。应用实例创建完 成后,开发者再通过SDK/API将数据推送至云端(阿里云存储 用户可以使用数据自动同步机制),数据实时进入Import子系统的数据导入服务模块(iStream Service),经过格式解析和数 据处理后,存储在结构化数据存储系统中。随后,Dump子系统的数据导出服务(iStream Service)将数据经过一定处理后发 送给实时消息队列系统(Swift),搜索系统(HA3)从消息队列中订阅数据,在内存中构建索引并提供搜索服务。这个数据实 时流式处理过程(见图1白色箭头)大概十秒左右。
当开发者修改了索引结构后,需要对应用中的数据做增量索引 重建。为了保证搜索效率,系统也会定期对所有数据做全量重 建索引。索引重建流程参见图1红色箭头,这是一个非实时的流程,依数据大小不同可能需要几分钟到十几分钟,全量索引重建则需要数小时。
数据在云端经过一系列处理和索引构建后,开发者就可以通过API搜索应用实例中的数据,搜索请求会被发送到查询聚合服务Aggregator中。如果开发者配置了智能查询分析功能,Aggregator会将查询请求发送给查询改写服务QP,QP按照开发者配置的处理规则(如拼写纠错、同义词或者词权重)改写查询请求,并将改写后的查询回传给Aggregator,Aggregator最终将查询请求发送给搜索系统HA3,HA3根据开发者定制的相关性排序规则对命中的结果文档排序,并最终通过Aggregator将结果返回给开发者。为了保 证不同开发者各个应用数据推送和搜索相互不受影响,配额 管理服务(Quota Server)会依据开发者的配额(实例容量和QPS峰值)对进入系统的数据和搜索请求频率做限流控制。
前面多次提到的HA3是阿里自主研发的新一代分布式实时搜索系统,中文名叫问天3,具备自动容灾、动态扩容、秒级实时等能力。图2是HA3系统模块组成图。
图2 HA3系统模块图
其中,Admin是整个系统的大脑,负责节点角色分配、调度决 策、FailOver处理、状态监测、动态扩容等。Amonitor是系统 的性能状态监控模块,收集和展示整个系统所有节点的性能参数。QRS是查询解析和改写服务,是系统对外的搜索接口。 Proxy是搜索代理模块,负责接收QRS的查询请求,并转发给下辖的所有Searcher节点。Searcher节点执行实际的查询匹配计算,将搜索结果汇总后回传给QRS。DeployExpress是分布式链式数据实时分发系统,负责将离线集群构建好的索引数据分发到各个Searcher节点。DeployExpress的最大亮点是将1份数据分发多份拷贝到Searcher节点,其分发时间接近单份拷贝的数据分发时间,而且单节点故障能自动恢复,不影响数据拷贝。在同等硬件条件下,基于1200万数据做单机性能对比测试发现,HA3比ElasticSearch开源系统的QPS高4倍,查询延迟低4倍。
图3是HA3的多集群异构部署图,其中部署了两个异构逻辑集群Cluster1和Cluster2,两者的硬件配置、索引结构、服务能力可以不同。这种部署一般用来实现冷热数据分层查询、异构数 据查询等功能。
图3 HA3多集群异构部署图
OpenSearch利用异构逻辑集群优化资源配置,提升系统服务能力和降低机器成本。不同特性的应用实例被分配在不同的逻辑 Cluster中。例如,QPS较高,数据量较少的应用实例分配在SSD磁盘的Cluster中,该Cluster列数较少,但行数较多,能承载较大的搜索流量;而一些QPS较低,数据量又较大的应用实例分配在普通磁盘Cluster中,该Cluster行数较少,但列数较多,能 承载海量的用户数据。当每个逻辑集群的数据量增大时,系统可以通过增加列(Partition)来扩大系统数据容量;当搜索流量 增大时,通过增加行(Replicas)来提升系统服务能力。
应用实践
基于OpenSearch,开发者可以实现各种功能的搜索产品。例如,淘点点实现了基于地理位置的餐厅、外卖、代金券搜索,天猫魔盒实现了电影、电视剧搜索,宝宝树实现了问答、知识搜索,威锋网实现了论坛帖子搜索,书旗网实现了小说搜 索,来往实现了扎堆内容搜索。这些产品,不同程度地使用了 OpenSearch索引结构定制、数据自动同步、两阶段相关性排序 等定制功能。下面结合实际应用场景,讲述OpenSearch的应用实践过程。
下面以两个实际应用场景为例,介绍OpenSearch应用实践过程。
- 简单实例:小说搜索
假设开发者做了一个小说网站,小说迷们可以在线搜索、阅读 小说。网站小说数量突破100万大关,活跃用户已过千万。随着 用户数量增长,搜索量越来越大,小说搜索功能刚刚从数据库全文检索迁移到某搜索引擎的站内搜索上。迁移后,虽然解决了搜索并发问题,但新的烦恼来了:搜索结果不全,新增小说无法及时搜索到,搜索功能单一,不支持按作者、章节搜索,不支持按分类、章节、状态、时间、阅读数、评分等条件过滤。在这个场景下,OpenSearch可以为其排忧解难。
开发者先登录OpenSearch控制台,在控制台中创建一个应 用实例,例如my_novel。创建过程中选择“小说类(builtin_ novel)”模板。这个模板已依据小说搜索的应用场景,预先定 义好了小说类数据的字段结构、搜索属性、排序规则、搜索结 果高亮配置等功能。
创建完应用实例后,可以编写代码上传数据。以PHP SDK为例:
//上传数据是json格式,字段根据实际模板不同
$json = <<<EOF
[{"fields":{"id":"0","title":"the title", "body":"the body"}, "cmd":"ADD"}, {"fields":{"id":"1","title":"t he title","body": "the body",}, "cmd":"UPDATE"}, {"fi elds":{"id":"2"},"cmd":"DELETE"}]EOF;
client=newCloudsearchClient( accessKeyId, //替换成用户自己的AK ID $secret, //替换成用户自己的AK Secretarray('host' => 'http://opensearch.aliyuncs. com'),
“aliyun”
);
doc=newCloudsearchDoc(‘mynovel′, client);
// 添加文档,参数1是json格式的string或者数组,
// 参数2是应用实例的表名, 一个应用可以创建多张表doc−>add( json, 'main');
如果开发者的小说数据在阿里云云存储服务OSS中,一篇小说一个文件,存放在一个bucket下,在创建应用过程中,可以直接配置使用这个bucket作为数据源,小说数据将自动同步至OpenSearch中。
接下来使用API/SDK搜索云端的小说数据,代码示例:
// 添加指定搜索的应用:
// 指定搜索返回的格式。
$search->setFormat('json');
// 返回搜索结果。
$search->search();
到这里,小说搜索云端部分的工作就完成了。开发者可以前往 控制台“下载中心”下载小说搜索结果的模板,做简单修改后, 一个专业的小说搜索产品就可以上线了。此时,更新的小说能即刻搜索,搜索结果全而且结构丰富;搜索功能上不仅支持按书名和作者搜索,而且支持按分类、字数、状态过滤,按默认相 关性、更新时间、评分数、阅读数、推荐数、点击数排序。
实现效果如图4所示:
图4 小说搜索效果图
- 复杂场景:外卖搜索(场景中所有配置均为示例,开发者需 按实际需求调整)。
假设开发者开发了一个外卖App,聚合了上百万的外卖商家数据,用户可以在App中基于地理位置搜索附近的商家,支持按菜品、商家名搜索,按配送范围、配送速度、配送时间、菜品类 型等条件过滤,按人均消费、评价、距离远近排序。开发者基于数据库在实现这些功能的过程中碰到了一些问题:菜品或商家搜索匹配效果不理想,基于地理位置的排序效果不好,搜索结果无法定制(例如实现一些商业排序逻辑)。
对于这个场景,OpenSearch的内置模板目前并没有覆盖,但开发者仍然可以基于OpenSearch解决上述问题。首先,在创建应 用实例流程里,选择“自定义结构”,配置数据表的字段结构、 数据处理方式、索引属性,最后提交创建应用实例。表1中是配置 的字段和类型(限于篇幅字段数量做了精简)示例。
表1字段和类型示例
字段 |
类型 |
说明 |
id |
STRING |
主键 |
name |
TEXT |
店名 |
city |
INT32 |
所在城市编号 |
lon |
DOUBLE |
经度 |
lat |
DOUBLE |
维度 |
phone |
STRING |
联系电话 |
address |
TEXT |
详细地址 |
area_range |
INT32 |
配送范围 |
delivery_time |
INT64 |
配送时间 |
cat_name |
STRING |
菜品类型 |
cost |
FLOAT |
人均消费 |
delivery_speed |
INT32 |
配送速度 |
auction_title |
SWS_TEXT |
菜品标题 |
auction_attr |
STRING |
菜品属性 |
area_range |
INT32 |
配送范围 |
sold_score |
INT8 |
外卖评分 |
speed_score |
INT8 |
配送评分 |
delivery_fee |
FLOAT |
配送费用 |
business_hours |
INT64 |
营业时间 |
激活应用实例后,进入“应用详情”配置页,选择“搜索结果相关性配置”,添加一个粗排配置,可以配置数值类型字段、文本相关性特征(static_bm25)、时效性(timeliness)特征的权重,例如:
static_bm25()*0.3 +speed_score*0.2 + sold_score*0.5
在粗排排序过程中,每家商家将按上述表达式计算分值。在这 个例子里,商家名的文本相关性特征的分值比重是0.3,配送评价分值比重是0.2,外卖评价分值比重是0.2。
接着,在“搜索结果相关性配置”界面中,继续添加一个精排配置,这里可以是一个非常复杂的表达式,例如:
text_relevance(auction_title)*3+if(text_ relevance(auction_title)>0.1, speed_score*1.5, speed_ score*0.6) + atan(speed_score + sold_score)*0.5
在精排排序过程中,粗排计算得到的商家按上述表达式计算分值。这个表达式用自然语言描述是:auction_title字段上的文本 相关性分值乘以3倍,如果auction_title字段的文本相关性分值大于0.1,则配送速度speed_score分值乘以1.5,否则乘以0.6。 speed_score、sold_score累加后做atan数学运算,比重是0.5。各 部分分值累加后作为商家的最后分值,所有商家按分值高低排 序后作为最终搜索结果返回。将添加的粗排、精排配置设置为默认,搜索结果就会按照自定义的规则排序。开发者也可以直 接在API或SDK中指定粗排、精排名称,具体参考API说明文档。
最后,在“应用详情”配置页中进入“搜索结果摘要”,添加需要做摘要和高亮的文本类型字段,配置摘要片段长度、片段数 量、高亮标签。这样配置后,将会在搜索返回的商家列表中将命中的搜索关键词高亮显示。
至此,商家搜索应用实例定制基本完成,开发者可以依据上一实 例介绍的方法上传数据,并且设计和开发产品的搜索结果页。
另外一个基于地理位置排序效果不好的问题,可以在搜索查询串中使用distance语法实现,例如:
sort=-distance(lon, lat, "20.23", "20.84349")
从上述介绍的应用实践案例可以看出,使用OpenSearch,对搜 索了解不多的开发者可以轻松上手;当数据结构复杂时,对相 关性要求高的开发者也能灵活定制。
下一步规划
为了给开发者提供更简洁、流畅的云搜索服务体验,我们将在 以下几方面发力。
■ 增强相关性定制功能、提升定制灵活性。在粗排和精排规则中增加电商搜索、O2O地理位置搜索、图片搜索、音视频搜索 等常见业务场景的相关性特征函数。这些特征函数将进一步提高相关性排序效果。精排规则将允许使用成熟的脚本语言,例如Lua,来编写更加复杂的相关性排序逻辑。
■ 丰富应用场景模板。在应用场景模板方面,将预制更多模 板,并丰富搜索结果页样式,允许开发者定制样式,并将结果页在云端托管。再进一步,将支持开发者分享和交易自己创建的模板,传承开发者在各个领域积累的搜索经验。
■ 帮助开发者盈利。通过流量盈利:我们将对接广告系统,允 许开发者通过API在自己的搜索结果页中嵌入广告,或者在云端托管的搜索结果页中定制和嵌入广告,将搜索流量转换成广告收益。通过数据盈利:开发者以搜索服务的方式共享数据源在线交易,其他开发者利用这些数据定制和创建自己的产品。
云搜索服务在国内外都还刚刚起步,还没有广泛应用。但在可预见的未来,云搜索必将像其他基础云服务一样,成为互联网产品的基础设施。我们希望能和广大开发者一起努力,打造更为好用、更为强大的云搜索服务。