现在的位置: 首页 > 综合 > 正文

闭关纪要18.将包含中文的数据上传到Google app engine

2012年02月22日 ⁄ 综合 ⁄ 共 3150字 ⁄ 字号 评论关闭

        从上一篇文章开始,我已经开始全面的使用Google App Engine,实际上,我在这方面是一个新手,因此,不会基于GAE写多少文章,不过一旦遇到很困扰我的问题,我还是觉得应该将心得提供出来给大家分享。

        数据上传是一个很费劲的问题,上面已经提到了,由于Google App Engine采用的Python不支持访问远程的数据库(这应该是基于性能的考虑),你只能选择将自己的数据上传到GAE的Google Datastore API库之中,Google Datastore API在Google文档之中是这样介绍的:

        Google Datastore API提供了一个用于数据查询和交互式存储的接口,全部基于Google的可扩展性架构实现,在Python之中提供了一系列数据模型接口,和一个类似于SQL语句的查询语言GQL,让开发可扩展性的数据程序和其他简单的WEB应用一样容易。

        看了这段“不知所云”的介绍之后,让我来发几段关于这个Google Datastore API的牢骚吧,可能长时间以来,我被关系型数据库以及相关的工具宠坏了,据我看来,Google Datastore API给我带来了如下困扰:

        1.不支持进行多个表的联合查询,这个要求可能实在是有点高,因为GData据说根本不是基于关系型数据库的,不过确实带来很多不便;

        2.每次返回的结果数有限,每次查询最多只能返回1000条结果,本来我确实也不需要那么多,不过当我需要知道整个数据库之中有多少条数据的时候,可能就有这个要求了,不过这个并非不能解决,你可以每次查询都按照key排序,然后每次拿最后一个查询结果的key来查询大于这个key的新的1000条结果,理论上讲还是可以查询所有结果的,不过我没有实际使用过这个功能;

        3.查询条件支持的有限,虽然提供了很多数据类型,例如GeoPt,不过如果不支持根据距离查询经纬度的话,这个参数也就只能当作一个长度为2的浮点数数组来使用了;

          4.数据的上传和管理相当困难,Google提供的数据管理视图非常简单,只能做简单的查询而已,例如我想将所有符合条件的记录都删除,就不行,因为GQL是没有delete语句的;

        这篇文章我专门说说数据上传,要知道,Google虽然因为数据库架构的考虑很多功能不能做的和我一直使用的关系型数据库一样,不过还是会有很多解决方案来解决这些问题,在数据上传得时候,采用Bulk Data Uploader.

        Bulk Data Uploader的原理就是采用一个本地Python脚本将csv之中的数据每十条十条的向服务器页面Post发送(不能太多,因为服务器处理很容易超时的),然后在服务端根据简单的数据类型配置将数据保存到数据库。

        这个过程是很慢的,我正在将一个18w条记录的数据发送到数据库之中,我就在机器进行这个进程的时候写的这篇博客,虽然我的每一条数据仅仅是4个int类型的整数,我初步估算了一下,每秒只能发送大约0.7个请求,也就是说平均每秒7条数据,这样,我需要7个小时才能发送完所有的数据,当然,这个和网速也是有关系的,我这边的网速,下载的文件通常速度是60K.实际上,我的数据文件CSV大小才有4M都不到,要是有一个更加有效率的机制来处理数据的话,我想肯定能在一分钟之内解决问题的。

        我先说说如何解决上传中文的问题,再介绍用Bulk上传数据的过程,要是使用Google介绍的默认方法来上传,在遇到中文的时候总是会遇到这样或那样的问题,要么是说"'ascii' codec can't encode characters u'\ufeff' in position 0",要么就是说什么"应该有3列,只接收到2列"什么的,我在搜索了一段时间之后,发现这个问题在Google已经有解决方案“Issue 157:non-ascii CSV data not handled by google.appengine.ext.bulkload (Unicode errors),一般来讲,结合这个汉字上传问题的解决,上传数据的过程如下:

        1.将刚才的Issue157之中的一个__init__.py保存到项目的根文件夹下,并且重命名为"bulkload.py",这个文件实际上包含了解决汉字上传问题的修改;

        2.创建一个服务端的访问页面,用来接收数据并保存到数据库之中,因此,需要在此文件之中进行数据类型的指定:

 1 import bulkload # 这里并不使用Google文档之中的"from google.appengine.ext import bulkload",而使用自身项目根目录下的bulkload,解决汉字上传问题
 2 from google.appengine.api import datastore_types
 3 from google.appengine.ext import search
 4 
 5 class InitData(bulkload.Loader):
 6   def __init__(self):
 7 #下面定义数据格式,DataTable1是上传之后的数据类型名称
 8 #后面代表每一个数据列的名称和类型
 9 #GeoPt类型在CSV文件之中必须是引号括起来的lat,lon的格式,例如"2.99629,73.00207"
10     bulkload.Loader.__init__(self, 'DataTable1',
11                          [('field1', int),
12                           ('field2', datastore_types.GeoPt),
13                           ('field3', unicode),
14                           ('field4', str),
15                           ])
16 
17 if __name__ == '__main__':
18   bulkload.main(InitData())

        3.在上面定义了这样一个页面之后,然后再在,app.yaml得handlers节之中注册这个页面:

- url: /datainit
  script:datainit.py

      本来基于安全考虑,还应该将这个URL配置为管理人员(login: admin)才能访问的,可是我不太明白设置了admin之后在bulk client之中怎么设置用户名和密码,所以只好作罢;

       4.在客户端运行google_appengine安装目录下的tools\bulkload_client.py,例如:

        bulkload_client.py --filename data/areaList.csv --kind AreaList --url http://aaa.appspot.com/datainit

          filename参数是本地的csv文件的路径,kind参数是数据类的名称,url参数是服务端处理上传的页面的地址

        运行之后,就可以看到客户端开始不停的进行数据上传的操作了,这个过程特别慢,而且,如果你的数据甚至比我的还要多,还要复杂的话,建议还是分批上传比较合适,因为Google服务器对请求数和占用的CPU时间有日限额限制的,虽然平时要达到这个限额很难,不过在不停的上传数据的情况下,需要小心,因为写入数据本身就比较耗性能的。

 

抱歉!评论已关闭.