文 / 蔡华 俗话说“民以食为天”,结束一天繁忙的工作,三五好友一聚,找个饭馆搓一顿,早已成为人们日常生活的一部分。随着移动互联网的兴起,随时随地使用LBS服务查找餐馆信息逐渐成为一种趋势,也为创业者提供了巨大的商机。本文将介绍如何基于阿里云的开放结构化数据服务(Open Table Service,以下简称OTS)快速构建查找餐馆信息的LBS服务的数据管理系统。 如何成为OTS的应用开发者 开发者首先要在OTS官方网站 http://ots.aliyun.com上注册一个账户,然后从OTS管理中心页面的API密钥管理选项卡中获取AccessId和AccessKey安全加密对,注意:任何与OTS服务的交互操作必须携带AccessId。OTS通过这一加密对进行身份验证,从而保证开发者的数据不能被别人访问,因此开发者务必小心保管AccessKey,不要对任何人泄露。 OTS提供的所有功能都可以通过Restful API来访问,但为了提高开发效率,我们为开发者提供了Python SDK。本文的例子就是使用Python SDK进行构建的。OTS SDK及文档可以从OTS官方网站下载。 三步构建一个LBS服务的数据管理系统 互联网应用的开发通常采用循环迭代的方式进行,下面我们通过从简单到复杂的三步,来构建一个餐馆查询的LBS服务,该LBS服务的完整代码可以从 http://ots.aliyun.com/ots_sdk/samples/restaurant_lbs.py下载。 餐馆基本信息查询 餐馆基本信息查询的流程一般是:移动设备上的客户端软件将用户的位置信息发送到要构建的LBS服务,然后LBS服务返回用户位置附近的餐馆信息供用户浏览。构建这个服务,首先需要收集城市内各个餐馆的基本数据,并存入到OTS表(RestaurantInfo)中供后续访问,表的每一行数据对应到一个餐馆,schema设置如表1所示。 [caption id="attachment_9927" align="aligncenter" width="458" caption="表1 RestaurantInfo表存储餐馆的数据"]
[/caption] 表1的primary key由DistrictID和RestaurantID这两个字段组成,唯一标识一个餐馆,其中DistrictID为partition key,指定同一区域内的餐馆数据属于同一个数据分片。开发者要注意的是在创建表时不需要指定primary key之外的信息,可以参考以下代码(为简便起见,本文中的代码不考虑异常处理,异常处理请参考OTS开发者指南,网址为
http://ots.aliyun.com/guide/index): [caption id="attachment_9928" align="aligncenter" width="423" caption="图1 在OTS控制台中查看RestaurantInfo表的schema信息"]
[/caption] 执行完上述操作之后,系统会在后台执行表加载,这个过程需要1~2分钟。加载成功之后才能往表中写入数据,这一点是需要开发者特别注意的。表创建成功之后,用户可以通过OTS官方网站上的控制台查看RestaurantInfo表的schema信息,如图1所示。

接下来是向表中添加数据。OTS提供了两种添加数据的方式:单条添加和批量添加。批量操作效率高,但有一个约束,即批量操作的行必须拥有相同的partition key。我们的例子采用批量添加方式,每次插入一个区域内的一批餐馆数据(拥有相同的partition key——DistrictID)。下面的代码展示如何插入一批DistrictID为“10000”的餐馆记录:

当有新的餐馆信息需要写入到服务中或者已有餐馆信息需要更新时,可以通过简单的单条写入数据操作(PutData)来执行,这里不再说明。

回到最初的场景——用户希望查找当前位置周围的餐馆。首先LBS服务根据用户的位置信息获取用户附近的餐馆区域ID(例如调用已有的GIS服务),可能会得到一个或者多个餐馆区域ID,LBS服务再根据这些区域ID去RestaurantInfo表中查询区域内的餐馆,针对每一个区域ID调用一次RangeQuery得到这个区域内的所有餐馆。下述代码将查询DistrictID为10000的区域内的前1000条餐馆数据:

在OTS中,我们建议RangeQuery在一个partition key范围内执行。对应到本例子中,就是针对每个区域调用一次RangeQuery。对于返回的每一条餐馆数据,LBS服务会根据用户的位置信息和餐馆的位置信息计算两者之间的距离,并将距离信息随同餐馆的基本信息一起返回并展示在移动终端。至此一个最基本的LBS服务就完成了。 用户评论的发表和查询 在这个LBS服务积累了一定量的人气之后,用户反馈对于服务质量的提高会有很大帮助。于是我们需要增加用户评价功能,允许用户对每个餐馆的用餐体验进行评价和打分,并能查询用户评价。我们通过增加另外一张表(RestaurantComment)来支持这个功能,表的每一行对应用户的一条评价结果,表的schema设置如表2所示。 [caption id="attachment_9931" align="aligncenter" width="572" caption="表2 RestaurantComment表存储用户对餐馆的评价数据"]
[/caption] 表2的primary key有四个字段——DistrictID、RestaurantID、DateTime和CommentID,这四个字段的数据唯一确定一条评价,其中CommentID由LBS服务系统在接收到评价数据时自动生成,确保唯一性。在设计这张表时需要考虑一个问题:如果餐馆的生意很好,用户评价就会非常多,那么用户在浏览这家餐馆的用户评价时,如果LBS服务一次性将这家餐馆所有的评价返回给移动设备,那么效率会非常低,且可能导致访问超时。为了解决这个问题,我们使用OTS的分页功能,将该表的paging key设置为DistrictID和RestaurantID,这样任何一个餐馆的用户评价数据都可以被客户端分页获取。创建RestaurantComment表的代码类似,此处不再列举。

当用户评价提交到LBS服务之后,LBS服务就会将这条评价数据写入到用户评价表中。当用户浏览某一家餐馆时,LBS服务会自动将这家餐馆的评价数据分页查询出来,并返回给移动设备展示,返回的数据按照评价的发表时间进行排序。对应的代码如下:

更多功能扩展 RestaurantComment表的primary key设置决定了用户发表的评价按照发表时间进行排序,以这种顺序来访问数据的话,效率也会很高。而有些用户可能希望按照作者来查看,但在这张表上实现这种顺序的查询非常困难,只能将所有的评价查询出来之后再按照作者名字进行排序,当评价记录很多时非常低效。因此,OTS提供了视图(view)机制来支持应用的这个功能。视图建立在原表上,指定不同于原表的primary key,从而将原表的数据按照另外一种顺序进行组织并且持久化。视图一旦建立之后,原表的数据会自动同步到视图中,保持一致性。那么在这个例子中,我们在创建原表时可以同时创建一张视图RestaurantComment_View,并指定原表的DistrictID、RestaurantID、UserName和CommentID四个字段作为视图的primary key,原表中其他字段作为视图的attribute columns。 随着业务流量的不断增大,与餐馆的合作也就会不可避免,例如餐馆接受用户通过移动设备在线预定,并随时查询到每个餐馆剩余的预定数。这需要我们为该LBS服务建立用户体系和提供订单预定功能,可以通过创建额外的两张表——用户信息表(UserInfo)和订单表(OrderInfo)来实现,逻辑也简单直接,本文不再赘述。 综上所述,基于OTS开发一个简单的LBS服务非常方便,编码也很简单。同时OTS还提供了分页(paging)和视图(view)等高级功能,为应用构建丰富的功能提供了可能。更多关于OTS的功能和使用,请参考OTS官方网站。 基于OTS开发的优势和潜力 基于OTS服务构建应用有下面两个优势。
  • 节省成本:创业者无需雇用专门的人来处理数据库软件的安装、配置以及数据库服务的维护工作。并且,OTS服务的价格对广大开发者来说也足够低廉。
  • 可扩展:随着应用规模的不断扩大,数据量和并发访问需求都会超越单机的能力范围,OTS服务会自动将数据和访问分布到多个节点,为应用的长期快速发展解决后顾之忧。
此外,当应用积累的业务数据越来越多时,就可以结合阿里云提供的ODPS(Open Data Processing Service,阿里云的开放数据处理服务,官方网址为: http://odps.aliyun.com)服务对这些数据进行离线处理和分析,为服务的运营提供更多指导,从而为用户带来更大的价值。 本文选自《凌云》杂志第1期,更多精彩内容敬请关注《凌云》专区。 《程序员》2012年杂志订阅送好礼活动火热进行中            
Logo

20年前,《新程序员》创刊时,我们的心愿是全面关注程序员成长,中国将拥有新一代世界级的程序员。20年后的今天,我们有了新的使命:助力中国IT技术人成长,成就一亿技术人!

更多推荐