AppEngine-MapReduce简介

标签:Google App Engine, Python

最近做blog真是接触到很多以前没用过的玩意啊,今天为了批量处理数据,我又用到了AppEngine-MapReduce

提起MapReduce,熟悉函数式编程的应该很容易明白它的思想。用Python来举例,它就是map函数和reduce函数,就这么简单!
考虑到有人对Python不太了解,所以再介绍下map和reduce吧:
  • map接受一个序列参数和一个函数参数,遍历这个序列,将其中所有的元素代入函数中执行。例如将一个列表里的元素全部加2,那么列表就是序列参数,加2就是函数参数。
  • reduce同样接受一个序列参数和一个函数参数,遍历这个序列,依次将所有的元素和上一次的执行结果代入函数中执行。例如统计一个列表的积,那么列表就是序列参数,乘法就是函数参数。
很明显,map是用于大规模修改元素的,而reduce是用于统计元素的。对应到datastore上的话,map可以修复错误的属性,可以从某些属性计算出其他属性所应有的值;reduce可以统计一个属性的总和、平均值、方差等。

了解了这些后,就不难明白AppEngine-MapReduce也需要2个最重要的参数:操作和所操作的实体集。
于是来看一个mapreduce.yaml的例子:
mapreduce:
- name: fix Article
  mapper:
    input_reader: google.appengine.ext.mapreduce.input_readers.DatastoreInputReader
    handler: fix_uploaded_data.fix_article
    params:
    - name: entity_kind
      default: model.Article
在这个文件里就定义了操作(fix_uploaded_data.fix_article)和所操作的实体集(model.Article)。因此它会遍历所有的model.Article实体,进行fix_uploaded_data.fix_article操作。遗憾的是目前只能指定一个类型的所有实体,还不能指定某一部分为参数(例如指定a属性小于10的实体)。

接下来再来看看fix_uploaded_data.fix_article做了什么:
from model import Comment
from google.appengine.ext.mapreduce import operation

def empty(list):
	return list is None or list == ['']

def fix_article(article):
	if empty(article.keywords):
		article.keywords = []
	if empty(article.tags):
		article.tags = []
	article.replies = Comment.all().ancestor(article).filter('approved =', True).count(100000)
	yield operation.db.Put(article)
其实就是一个很简单的map操作,处理一下空值,并计算replies属性,最后用yield operation.db.Put(article)返回即可。
注意这里用的不是db.put,此外除了Put操作,还能执行Delete操作,其他就基本都一样了。

定义完操作后,还得定义一个handler来处理。由于现在的SDK已经内置了AppEngine-MapReduce,因此只要在app.yaml的handlers里加上这段即可:
- url: /mapreduce(/.*)?
  script: $PYTHON_LIB/google/appengine/ext/mapreduce/main.py
  login: admin
然后访问一下/mapreduce,就可以看到其界面了。

最后我这个操作是每秒处理了22.39个实体,显得有点慢,不过考虑到这个实体很大,而且每次都有一个count查询,也还是可以接受的。只不过从性能上来考虑的话,自己写个task,用游标来记录位置,每次操作多处理一些实体估计会更快。

我顺便还在执行结果里发现了google.appengine.ext.key_range这个模块,而且知道它是依靠猜测,将key分成几段,并利用end游标来分成多个task并行执行的。

此外还有一些高级的参数和用法,这里就不再介绍了,毕竟这个库还没正式并入GAE SDK里,以后说不定还有很大改动。

0条评论 你不来一发么↓

    想说点什么呢?