如何使用Erlang在Riak上执行MapReduce,以便从存储数字1到1000的所有键中获取偶数值

时间:2014-05-13 06:34:08

标签: erlang riak erlang-shell

我正在尝试用Erlang在Riak上做mapreduce。我有以下数据:

Bucket = "Numbers"
{Keys,values} = {Random key,1},{Random key,2}........{Random key,1000}. 

现在,我存储1000个值,从1到1000,其中所有键都是由作为参数给定的术语undefined自动生成的,因此所有键的值都从1到1000开始。

所以我希望数据只来自偶数值。使用mapreduce,我该如何实现?

1 个答案:

答案 0 :(得分:0)

您将按照http://docs.basho.com/riak/latest/dev/advanced/mapreduce/

中的描述构建阶段函数

一种可能的地图功能:

Mapfun = fun(Object, _KeyData, _Arg) ->
    %% get the object value, convert to integer and check if even
    Value = list_to_integer(binary_to_term(riak_object:get_value(Object))),
    case Value rem 2 of
      0 -> [Value];
      1 -> []
    end
end.

虽然您可能希望在遇到兄弟姐妹的情况下不会完全失败:

Mapfun = fun(Object, _KeyData, _Arg) ->
    Values = riak_object:get_values(Object),
    case length(Values) of        %% checking for siblings
      1 ->                   %% only 1 value == no siblings
         I = list_to_integer(binary_to_term(hd(Values))),
         case I rem 2 of
            0 -> [I];    %% value is even
            1 -> []          %% value is odd
         end;
      _ -> []                %% What should happen with siblings?
    end
end.

您可能还需要阻止或检查以下其他情况:包含非数字字符的值,空值,已删除的值(tombsones),仅举几例。

编辑:
需要注意的是:执行全桶MapReduce作业需要Riak读取磁盘中的每个值,这可能会导致极大的延迟和超大数据集的超时。可能不是你想要在制作中做的事情。

<小时/> 完整的MapReduce示例(出于空间考虑,限制为1到200):

假设您克隆并构建了riak-erlang-client 使用上面的第二个Mapfun

erl -pa {path-to-riak-erlang-client}/ebin

定义reduce函数以对列表进行排序

Reducefun = fun(List,_) -> 
    lists:sort(List) 
end.

附加到本地Riak服务器

{ok, Pid} = riakc_pb_socket:start_link("127.0.0.1", 8087).

生成一些测试数据

[ riakc_pb_socket:put(
                  Pid,
                  riakc_obj:new(
                            <<"numbers">>,
                            list_to_binary("Key" ++ V),V
                            )
                  ) || V <- [ integer_to_list(Itr) || Itr <- lists:seq(1,200)]],

使用此客户端执行MapReduce的功能是
mapred(pid(), mapred_inputs(), [mapred_queryterm()])

mapred_querytermreadme中定义的{Type, FunTerm, Arg, Keep}形式的阶段规范列表。对于此示例,有两个阶段:

  • 仅选择偶数的地图阶段
    {map, Mapfun, none, true}
  • 对结果进行排序的减少阶段
    {reduce, Reducefun, none, true}

执行MapReduce查询

{ok,Results} = riakc_pb_socket:mapred(
                              Pid,  %% The socket pid from above
                              <<"numbers">>,  %% Input is the bucket 
                              [{map,{qfun,Mapfun},none,true},
                              {reduce,{qfun,Reducefun},none,true}]
                                     ),

Results将是[{_Phase Index_, _Phase Output_}]的列表,其中Keep为真的每个阶段都有单独的条目,在此示例中,两个阶段都标记为keep,因此在此示例中{{ 1}}将是 Results

打印出每个阶段的结果:

[{0,[_map phase result_]},{1,[_reduce phase result_]}]

当我跑这个时,我的输出是:

[ io:format("MapReduce Result of phase ~p:~n~P~n",[P,Result,500]) 
                || {P,Result} <- Results ].