闭关纪要21.地图人站点的IP查询经纬度和经纬度查询行政区划的服务
现在我的闭关已经接近尾声,按照最初的计划我准备拿出一个月左右的时间研究JavaScript的代码混淆的,后来因为对Google App Engine的引擎的研究日渐深入,而且也觉得代码混淆比我想象的要复杂,因此,取消了研究代码混淆的计划,而专注于网站相关的研究。
本文要介绍的是我在Google App Engine上实现的3个REST接口服务:
1.通过经纬度查询行政区划的服务,传递一个经纬度坐标,返回的结果为该位置的行政区划,通常来讲,用来实现地图上的“面包屑导航”功能。
2.通过IP查询经纬度,传递一个IP(或者不传,缺省使用连接客户端的IP),返回结果为该IP的位置文字描述和经纬度
3.加载一个简单的笑话信息,这是一个很简单搞笑的功能。
本来,这些功能在地图人网站上原本就有,不过以前是我使用ASP.NET开发的,和网站运行在一个主机上,为避免主机性能受影响这些接口没有公布,而且在接口程序上做了站内限制,现在我将地图人网站的所有类似服务都迁移到了Google App Engine上,而Google App Engine的性能和稳定性是比较可靠的,因此我将这些服务公布出来供大家参考引用。
上次,因为网站的18万条数据因为GAE的一个BUG没有能够成功上传到GAE上,因此,影响了网站服务代码的迁移,不过我最近才知道,原来GAE是可以访问本地文件的(汗!我可能是被‘云’弄得晕乎乎了,连本地文件都不敢访问了),而我的那些数据包含明显的规律,使用本地文件访问比数据库更快,因此我毅然决定重写代码,依靠访问文件的方式来提供服务,跳过了那个BUG,并且带来更好的性能。
不过Google的单个文件大小最多为1M,这一点挺害人的,毕竟18W条的数据要压缩成1M的文件可不容易,因此我很费劲的研究了几晚上的Python二进制文件读写,以及数据类型什么的,最后终于成功的将数据压缩到800K,这样才能够完美的提供通过经纬度查询行政区划。
下面介绍一下每个服务的调用过程和实现,需要说明的是,除了第三个服务在上一篇文章《闭关纪要20.在Google App Engine之中解析RSS》之中已经公开了源码之外,其他的两个服务因为和数据相关,公开源码也没有意义,因此就不公开,不过第二个服务通过IP查询的,我的主要源码就是使用的别人的开源代码做了简单的整合,根据我的思路,很容易就可以自己实现了。
1.通过经纬度查询行政区划,这个服务通过读取本地二进制文件匹配出某个经纬度的行政区划编号,然后通过编号在Google DataStore之中查询行政区划信息,经过我的观察,性能还算不错,按照Google App Engine后台的统计显示,平均CPU时间消耗为80,算是比较少的,虽然这个服务看起来比较复杂。服务调用示例:
http://dituren-service.appspot.com/services/rgeo_ll?ll=39.94691582580937,116.38320347900391&c=onRgeoLoaded
其中,参数ll是逗号分隔经纬度,注意是纬度在前,经度在后,参数c是REST回调函数名称,上例返回的内容为:
onRgeoLoaded({area:'北京市-西城区',regionCode:'110102'});
返回的对象之中,area属性是减号分隔的按层级的地区名称,regionCode属性是行政区划编码,如果没有成功匹配到行政区划,将以空参数调用回调函数
需要注意的是,因为这个接口仅仅进行国内行政区划的查询,因此建议仅仅对纬度范围(从3到54),经度范围(从73到136)范围内的内容进行查询匹配,否则,白白连接一下,没有任何意义;
2.通过IP查询经纬度,这个服务首先要感谢gohsy,我的IP查询功能采用他的代码,而且连IP库也是采用他的版本,我本来想替换一个更全(至少文件更大)的IP库的,可惜后来发现超过1M的文件传不上去,而gohsy的IP库文件居然刚好是1M,不知道他怎么弄的,我就不客气的使用了,在采用这个库实现了通过IP得到一个地址的文字描述之后,我通过Google的地址解析服务去匹配经纬度,这个思路很清晰,不过我会在数据库之中缓存Google的地址解析结果,避免频繁的向Google请求地址匹配造成性能和稳定性问题,这个服务因为存在获取URL内容的功能,因此性能不稳定,从统计来看,平均CPU时间消耗为140,不过这个服务才运行了几个小时,随着缓存地址匹配数据的增多,平均CPU占用一定会下降。服务调用示例:
http://dituren-service.appspot.com/services/ip_lookup?c=onIpLookupLoaded&ip=202.204.59.204
其中,参数ip就是一个IP(废话),如果IP参数不存在,则直接缺省采用客户端连接IP,参数c是REST回调函数名称,返回的内容为:
onIpLookupLoaded({ip:'202.204.59.204',address:'北京市 北京科技大学',lat:39.987700,lon:116.361576,zoom:14})
返回的对象之中,ip属性就是当前IP,不管是否传递了ip参数,都会返回一个IP,address属性是在IP库之中查询的结果字符串,lat,lon是经纬度信息,zoom属性是较合适的显示缩放等级,因为匹配有精度的问题,例如匹配到“北京科技大学”和匹配到“北京市”都有经纬度,不过显示给用户的缩放登机最好是有所不同的,这个缩放等级是按照Google的地图做标准的,如果在51ditu接口上使用,考虑用17-zoom。
需要注意的是,因为IP查询采用网上的IP库,地址匹配采用Google的接口,我仅仅做一个简单的整合,因此,不能对数据的正确性和准确率作出保证,呵呵
3.加载一个笑话,本来这个功能就是上不得台盘的一个小玩意,不能和上面的两个接口相比,不过,我也随便的介绍一下,这个功能源码已经公开在《闭关纪要20.在Google App Engine之中解析RSS》
有时候,因为网速的问题,地图加载缓慢(地图API通常都比较大,而且地图相关的附加功能多),让用户等待地图下载的过程之中,在地图显示区域先加载个笑话或其他文字内容是不错的,不过要求这个内容要在主体内容加载之前开始加载(否则就失去意义了),而且要求加载比较快,尽量不要进一步拖慢页面加载速度,在主体内容加载完成之后,就显示主体内容,原来的临时内容被替换。
因为页面上不能每次打开都是同样的内容(如果是这样的话,直接写在静态页面上就可以了,而且让用户每次都看一个内容也就失去了打发等待页面加载时间的意义)所以页面内容还要自动变换,不过最好可供变换的内容不要太多,就可以使用缓存的优势使加载速度更快。
基于以上的思路,开发了一个以下服务,客户端动态的变化一个随机数字id,向这个服务发送请求,这个服务返回指定id的内容:
http://dituren-service.appspot.com/services/joke_random?c=onJokeLoaded&id=12
参数id是传递过来的随机整数,注意为什么不在服务端随机显示呢,因为在服务端随机显示的话就无法启用缓存了;参数c是REST回调函数名称,本服务返回的内容示例为:
onJokeLoaded({title:"贵族幼儿园面试",content:"小露丝去考贵族幼儿园,面试时老师取出一张10元的钞票问:这是什么?小露丝很快回答:这是奶奶给乞丐的废纸.老师说:好了,不用考了,你已被录取了。"})
title参数是标题,content参数是内容(全是废话),页面上先定义好onJokeLoaded函数,将笑话显示在指定的地方,页面主体内容加载完成后,再擦除内容就可以实现了。
以上就是我的网站上提供的3个相关的服务的说明,这些服务并没有考虑使用XML格式,而是采用REST的JavaScript格式,是希望可以直接调用而不会遭遇跨域的问题(因为这些服务都是在专用域名service.dituren.cn上的,和我自己的网站也不是在同一个域)以上服务返回的内容全部是UTF-8格式的JavaScript内容,调用的时候需要注意编码问题
本文仅仅是对这些服务接口本身进行介绍,后面我会将这些服务封装成简单的用户可以在直接使用的脚本对象,这些对象将会在我正准备更新的K_Map(原来名字叫K_ReverterMap的一些地图相关的类)之中公布,现在想起来K_Map的一些类已经好久没有更新过了。
这以后,我还会逐步的增加相关的服务,例如根据经纬度查询天气信息什么的,反正相关的东西,我都可以拿来研究!
posted on 2009-01-07 21:41 K_Reverter 阅读(8611) 评论(12) 编辑 收藏 举报