第1关:函数、过滤器、地图和平面地图、窥视操作


任务描述

本关任务:使用 Storm Trident 完成一个过滤器的实现。

相关知识

为了完成本关任务,你需要掌握以下 Trident API: 1.Functions(函数) 2.Filters(过滤器) 3.map and flatMap(地图和平面地图) 4.peek(窥视)

Functions(函数)

加工处理 tuple 内容。

一个能把 tuple 中 text 内容变成大写的 Function :

 
  1. public static class UppercaseFunction extends BaseFunction {
  2. @Override
  3. public void execute(TridentTuple tuple, TridentCollector collector) {
  4. collector.emit(new Values(tuple.getString(0).toUpperCase()));
  5. }
  6. }

Topology:

 
  1. topology.newStream("spout", spout)
  2. .each(new Fields("text", "actor"), new UppercaseFunction(), new Fields("uppercased_text"))

首先, UppercaseFunction 函数的输入是 Fields("text", "actor"),其作用是把其中的" text "字段内容都变成大写。

其次,作用是每个 tuple 在经过这个 Function 函数处理后,输出字段都会被追加到 tuple 后面,在本例中,执行完 Function 之后的 tuple 内容多了一个“ uppercased_text ”,并且这个字段排在最后面。

Filters(过滤器)

一个通过 actor 字段过滤消息的 Filter :

 
  1. public static class PerActorTweetsFilter extends BaseFilter {
  2. String actor;
  3. public PerActorTweetsFilter(String actor) {
  4. this.actor = actor;
  5. }
  6. @Override
  7. public boolean isKeep(TridentTuple tuple) {
  8. return tuple.getString(0).equals(actor);
  9. }
  10. }

Topology:

 
  1. topology.newStream("spout", spout)
  2. .each(new Fields("actor", "text"), new PerActorTweetsFilter("dave"));

从上面例子看到,each() 方法有一些构造参数 第一个构造参数:作为 Field Selector ,一个 tuple 可能有很多字段,通过设置 Field ,我们可以隐藏其它字段,仅仅接收指定的字段(其它字段实际还在)。

第二个是一个 Filter :用来过滤掉除 actor 名叫” dave “外的其它消息。

map and flatMap(地图和平面地图)

map 返回一个 stream , 它包含将给定的 mapping function (映射函数)应用到 stream 的 tuples 的结果. 这个可以用来对 tuples 应用 one-one transformation (一一变换).

例如, 如果有一个 stream of words (单词流), 并且您想将其转换为 stream of upper case words (大写字母的流), 你可以定义一个 mapping function (映射函数)如下:

 
  1. public class UpperCase extends MapFunction {
  2. @Override
  3. public Values execute(TridentTuple input) {
  4. return new Values(input.getString(0).toUpperCase());
  5. }
  6. }

然后可以将 mapping function (映射函数)应用于 stream 以产生 stream of uppercase words (大写字的流).

 
  1. mystream.map(new UpperCase())

flatMap 类似于 map , 但具有将 one-to-many transformation (一对多变换)应用于 values of the stream (流的值)的效果, 然后将所得到的元素 flattening (平坦化)为新的 stream 。

例如, 如果有 stream of sentences (句子流), 并且您想将其转换成 stream of words (单词流), 你可以定义一个 flatMap 函数如下:

 
  1. public class Split extends FlatMapFunction {
  2. @Override
  3. public Iterable<Values> execute(TridentTuple input) {
  4. List<Values> valuesList = new ArrayList<>();
  5. for (String word : input.getString(0).split(" ")) {
  6. valuesList.add(new Values(word));
  7. }
  8. return valuesList;
  9. }
  10. }

然后可以将 flatMap 函数应用于 stream of sentences (句子流)以产生一个 stream of words (单词流)

mystream.flatMap(new Split())

当然这些操作可以被 chained (链接), 因此可以从如下的 stream of sentences (句子流)中获得 stream of uppercase words (大写字的流),

mystream.flatMap(new Split()).map(new UpperCase())

如果不将 output fields (输出字段)作为 parameter (参数)传递, 则 mapflatMap 会将 input fields (输入字段)保留为 output fields (输出字段).

如果要使用 MapFunctionFlatMapFunction 使用 new output fields (新的输出字段)替换 old fields (旧字段), 您可以使用附加的 Fields 参数调用map / flatMap , 如下所示,

mystream.map(new UpperCase(), new Fields("uppercased"))

Output stream (输出流)只有一个 output field (输出字段) ”uppercased“ , 而不管以前的流有什么输出字段. 同样的事情适用于 flatMap, 所以以下是有效的,

mystream.flatMap(new Split(), new Fields("word"))

peek(窥视)

peek 可用于在每个 trident 元组流过流时对它们执行附加操作。当元组流过管道中的某个点时,这对于调试以查看元组很有用。

例如,下面的代码将打印将单词转换为大写的结果,然后再将它们传递给 groupBy 。

 
  1. mystream.flatMap(new Split()).map(new UpperCase())
  2. .peek(new Consumer() {
  3. @Override
  4. public void accept(TridentTuple input) {
  5. System.out.println(input.getString(0));
  6. }
  7. })
  8. .groupBy(new Fields("word"))
  9. .persistentAggregate(new MemoryMapState.Factory(), new Count(), new Fields("count"))

编程要求

根据提示,在右侧编辑器补充代码,编写一个过滤器的操作和实现,要求过滤出 tuple 中值为 the 的 tuple 。

测试说明

平台会对你编写的代码进行测试:

预计输入:

 
  1. the cow jumped over the moon
  2. the man went to the store and bought some candy
  3. four score and seven years ago
  4. how many apples can you eat

预计输出:

 
  1. emit word is :the
  2. Filter word is:the and return type is:true
  3. emit word is :cow
  4. emit word is :jumped
  5. emit word is :over
  6. emit word is :the
  7. Filter word is:the and return type is:true
  8. emit word is :moon
  9. emit word is :the
  10. Filter word is:the and return type is:true
  11. emit word is :man
  12. emit word is :went
  13. emit word is :to
  14. emit word is :the
  15. Filter word is:the and return type is:true
  16. emit word is :store
  17. emit word is :and
  18. emit word is :bought
  19. emit word is :some
  20. emit word is :candy
  21. emit word is :four
  22. emit word is :score
  23. emit word is :and
  24. emit word is :seven
  25. emit word is :years
  26. emit word is :ago
  27. emit word is :how
  28. emit word is :many
  29. emit word is :apples
  30. emit word is :can
  31. emit word is :you
  32. emit word is :eat

代码如下:

import org.apache.storm.Config;

import org.apache.storm.LocalCluster;

import org.apache.storm.generated.StormTopology;

import org.apache.storm.trident.TridentTopology;

import org.apache.storm.trident.operation.BaseFilter;

import org.apache.storm.trident.operation.BaseFunction;

import org.apache.storm.trident.operation.TridentCollector;

import org.apache.storm.trident.testing.FixedBatchSpout;

import org.apache.storm.trident.tuple.TridentTuple;

import org.apache.storm.tuple.Fields;

import org.apache.storm.tuple.Values;

/*  部分输出

emit word is :the

Filter word is:the  and return type is:true

emit word is :cow

emit word is :jumped

emit word is :over

emit word is :the

Filter word is:the  and return type is:true

emit word is :moon

* */

public class FunctionFilter {

    public static void main(String[] args){

        TridentTopology topology = new TridentTopology();

        FixedBatchSpout spout = new FixedBatchSpout(new Fields("sentence"), 1,

                new Values("the cow jumped over the moon"),

                new Values("the man went to the store and bought some candy"),

                new Values("four score and seven years ago"),

                new Values("how many apples can you eat"));

        //不循环发送数据

        spout.setCycle(false);



        //****请根据提示补全Topology程序****//

        /*********begin*********/



        topology.newStream("spout1", spout)

        //topology的newStream 方法从输入源中读取数据, 并在 topology 中创建一个新的数据流 batch-spout

        .each(new Fields("sentence"), new Split(), new Fields("word"))

        .groupBy(new Fields("word"));

         //使用.each()方法,sentence tuple经过split()方法后输出word tuple  

         //使用.each()方法,new Fields()保留setence tuple和word tuple ,经过WordFilter() 过滤 单词 the

                       

        /*********end*********/





        StormTopology stormTopology = topology.build();

        LocalCluster cluster = new LocalCluster();

        Config conf = new Config();

        cluster.submitTopology("soc", conf,stormTopology);

    }

    //Filter过滤器

    public static class WordFilter extends BaseFilter {

        String actor;

        public WordFilter(String actor) {

            this.actor = actor;

        }

        @Override

        public boolean isKeep(TridentTuple tuple) {

            //如果元组的值和 actor 相等(这里的actor是“the”)

            if(tuple.getString(1).equals(actor)){

                //输出 Filter word is:the  and return type is:true

                System.out.println("Filter word is:"+tuple.getString(1) + "  and return type is:"+tuple.getString(1).equals(actor));

            }

            return tuple.getString(1).equals(actor);

        }

    }

    // Function函数

    public static class Split extends BaseFunction {

        public void execute(TridentTuple tuple, TridentCollector collector) {

            String sentence = tuple.getString(0);

            //把句子以空格切分为单词

            //每一个 sentence tuple 可能会被转换成多个 word tuple,

            //比如说 "the cow jumped over the moon" 这个句子会被转换成 6 个 "word" tuples

            for(String word: sentence.split(" ")) {

                System.out.println("emit word is :"+word);

                collector.emit(new Values(word));

            }

        }

   

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值