浏览 2198 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2009-03-19
加上令人头疼的公司的事情, 导致我很忙... 哎... 为了保持博客的新鲜度, 就贴一点充数的资料吧..呵呵... 在我前段时间搞的一个开源的mapreduce小框架中, 对于map, reduce数据流的读取, 我抽象出一个迭代器, 进行数据的读取. 这样我的数据无论来自local Disk, 来自memory, 来时NFS都一视同仁... 在写一个module之前,我先想象其接口及用法: %%% usage: %%% Iter = make_iter(prev_fun, next_fun, State), %%% {Next , Iter2} = next(Iter), %%% {Next2, Iter3} = next(Iter2), %%% {Next, Iter2} = prev(Iter3). 我们首先通过调用make_iter/3 构建一个迭代器, 第一个参数是一个函数用来获取前一条记录, 第二个参数用来获取下一条 记录. State是一个内部状态信息, 用来保存当前的状态. 构造好iter后, 我们可以通过调用prev/1, next/1 来遍历这个Iter. 这个实现,有点OO的感觉在里面, Iter可以理解为一个对象,其State为内部数据, prev_fun, next_fun为对应的方法. 为了让我们的iter模块更丰富,我们仿照lists module, 加入了foldl/3 和 foldr/3 两个函数. 当然还可以让这个iter功能更强大,比如是否可以循环迭代?是否可以双向或单向迭代?等等.有兴趣朋友可以实现哦. 好了,贴上代码: -module(heng_iter). -author('litaocheng@gmail.com'). -vsn('0.1'). -include("heng_master.hrl"). -export([make_iter/3]). -export([next/1, prev/1]). -export([foldl/3, foldr/3]). -record(iter, { %type = normal :: 'normal' | 'cyclic', % next = nil :: 'nil' | fun(), prev = nil :: 'nil' | fun(), state }). %% @doc get the next item next(#iter{next = nil}) -> {error, edirection}; next(Iter = #iter{next = Next, state = State}) -> case Next(State) of nil -> % to the end {nil, Iter}; {V, State2} -> {{value, V}, Iter#iter{state = State2}} end. %% @doc get the item in the backward prev(#iter{prev = nil}) -> {error, edirection}; prev(Iter = #iter{prev = Prev, state = State}) -> case Prev(State) of nil -> % to the end {nil, Iter}; {V, State2} -> {{value, V}, Iter#iter{state = State2}} end. %-spec foldl(Fun :: fun(), Acc :: term(), Iter :: iter()) -> % term(). foldl(Fun, Acc, Iter) when is_function(Fun, 2) -> {V, Iter2} = next(Iter), foldl0(Fun, Acc, V, Iter2). foldl0(_Fun, Acc, nil, _Iter) -> Acc; foldl0(Fun, Acc, {value, V}, Iter) -> Acc2 = Fun(V, Acc), {V2, Iter2} = next(Iter), foldl0(Fun, Acc2, V2, Iter2). foldr(Fun, Acc, Iter) when is_function(Fun, 2) -> {V, Iter2} = prev(Iter), foldr0(Fun, Acc, V, Iter2). foldr0(_Fun, Acc, nil, _Iter) -> Acc; foldr0(Fun, Acc, {value, V}, Iter) -> Acc2 = Fun(V, Acc), {V2, Iter2} = prev(Iter), foldr0(Fun, Acc2, V2, Iter2). %% @doc 'fward' equal 'forward' , 'bid' equal 'bidirectional' make_iter(Next, Prev, State) when is_function(Next) andalso is_function(Prev) %andalso ((Type =:= 'normal') or (Type =:= 'cyclic')) -> #iter{%type = Type, next = Next, prev = Prev, state = State }. 最后是一个小例子, 我们定义一个迭代器,用来访问list, 当然这个做法似乎有点多此一举.. (这段代码摘自 iter 模块中的测试代码 ) %% @doc some test basic_test_() -> Data = ["begin", "one", "two", "there", "four", "end"], ExpR1 = "begin one two there four end", ExpR2 = "end four three two one begin", %% 定义一个迭代器, 其调用listnext/1 获取下一条记录, 调用listprev/1 获取上一条记录, State为一个tuple %% 分别保存:数据的begin, last, length 和具体的数据(也就是list) Iter = make_iter(fun listnext/1, fun listprev/1, {0, 0, length(Data), Data}), R = ?MODULE:foldl(fun(Str, Acc) -> [Str, $ | Acc] end, [], Iter), Str = lists:flatten(lists:reverse(R)), % Str 为 ExpR1 Iter2 = make_iter(fun listnext/1, fun listprev/1, {length(Data)+1, 1, length(Data), Data}), R2 = ?MODULE:foldr(fun(E, Acc) -> [E, $ | Acc] end, [], Iter2), Str2 = lists:flatten(lists:reverse(R2)), % Str 为 ExpR2 [ ?_assert(Str = ExpR1), ?_assert(Str2 = ExpR2) ]. %% 用来获取下一条记录 listnext({Last, _First, Last, _Data}) -> nil; listnext({Pos, First, Last, Data}) -> Pos2 = Pos + 1, V = lists:nth(Pos2, Data), {V, {Pos2, First, Last, Data}}. %% 用来获取前一条记录 listprev({0, _First, _Last, _Data}) -> nil; listprev({First, First, _Last, _Data}) -> nil; listprev({Pos, First, Last, Data}) -> Pos2 = Pos - 1, V = lists:nth(Pos2, Data), {V, {Pos2, First, Last, Data}}. 好了就是这些, 有了这个module, 在mapreduce框架中,用户可以自定义各种的iter 实现, map, reduce会依据用户的iter 进行具体的数据读取,然后进行处理.. 详细的代码, 请参考此处: http://code.google.com/p/heng/source/browse/trunk/master/heng_iter.erl 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |