Storm高级原语(四) — Trident API 综述

来源:互联网 发布:什么是人工智能英文 编辑:程序博客网 时间:2024/05/02 04:20

本文翻译自Storm wiki中的Trident API,部分地方加入了笔者自己的理解。

“Stream”是Trident中的核心数据模型,它被当做一系列的batch来处理。在Storm集群的节点之间,一个stream被划分成很多partition(分区),对流的操作(operation)是在每个partition上并行进行的。

注:

①“Stream”是Trident中的核心数据模型:有些地方也说是TridentTuple,没有个标准的说法。

②一个stream被划分成很多partition:partition是stream的一个子集,里面可能有多个batch,一个batch也可能位于不同的partition上

Trident有五类操作(operation):

1、Partition-local operations,对每个partition的局部操作,不产生网络传输

2、Repartitioning operations:对数据流的重新划分(仅仅是划分,但不改变内容),产生网络传输

3、Aggregation operations:聚合操作

4、Operations on grouped streams:作用在分组流上的操作

5、Merge、Join操作

Partition-local operations

对每个partition的局部操作包括:function、filter、partitionAggregate、stateQuery、partitionPersist、project等。

Functions

一个function收到一个输入tuple后可以输出0或多个tuple,输出tuple的字段被追加到接收到的输入tuple后面。如果对某个tuple执行function后没有输出tuple,则该tuple被过滤(filter),否则,就会为每个输出tuple复制一份输入tuple的副本。假设有如下的function:

1
2
3
4
5
6
7
publicclass MyFunction extendsBaseFunction {
    publicvoid execute(TridentTuple tuple, TridentCollector collector) {
        for(inti=0; i < tuple.getInteger(0); i++) {
            collector.emit(newValues(i));
        }
    }
}

假设有个叫“mystream”的流(stream),该流中有如下tuple( tuple的字段为["a", "b", "c"] ),

[1, 2, 3]

[4, 1, 6]

[3, 0, 8]

运行下面的代码:

1
mystream.each(newFields("b"),newMyFunction(), newFields("d")))

则输出tuple中的字段为["a", "b", "c", "d"],如下所示

[1, 2, 3, 0]

[1, 2, 3, 1]

[4, 1, 6, 0]

Filters

fileter收到一个输入tuple后可以决定是否留着这个tuple,看下面的filter:

1
2
3
4
5
publicclass MyFilter extendsBaseFunction {
    publicboolean isKeep(TridentTuple tuple) {
        returntuple.getInteger(0) == 1&& tuple.getInteger(1) == 2;
    }
}

假设你有如下这些tuple(包含的字段为["a", "b", "c"]):

[1, 2, 3]

[2, 1, 1]

[2, 3, 4]

运行下面的代码:

1
mystream.each(newFields("b","a"),newMyFilter())

则得到的输出tuple为:

[2, 1, 1]

partitionAggregate

partitionAggregate对每个partition执行一个function操作(实际上是聚合操作),但它又不同于上面的functions操作,partitionAggregate的输出tuple将会取代收到的输入tuple,如下面的例子:

1
mystream.partitionAggregate(newFields("b"),newSum(), newFields("sum"))

假设输入流包括字段 ["a", "b"] ,并有下面的partitions:

Partition 0:

["a", 1]

["b", 2]

Partition 1:

["a", 3]

["c", 8]

Partition 2:

["e", 1]

["d", 9]

["d", 10]

则这段代码的输出流包含如下tuple,且只有一个”sum”的字段:

Partition 0:

[3]

Partition 1:

[11]

Partition 2:

[20]

上面代码中的new Sum()实际上是一个聚合器(aggregator),定义一个聚合器有三种不同的接口:CombinerAggregator、ReducerAggregator 和 Aggregator。

下面是CombinerAggregator接口:

1
2
3
4
5
publicinterface CombinerAggregator extendsSerializable {
    T init(TridentTuple tuple);
    T combine(T val1, T val2);
    T zero();
}

一个CombinerAggregator仅输出一个tuple(该tuple也只有一个字段)。每收到一个输入tuple,CombinerAggregator就会执行init()方法(该方法返回一个初始值),并且用combine()方法汇总这些值,直到剩下一个值为止(聚合值)。如果partition中没有tuple,CombinerAggregator会发送zero()的返回值。下面是聚合器Count的实现:

01
02
03
04
05
06
07
08
09
10
11
12
13
publicclass Count implementsCombinerAggregator {
    publicLong init(TridentTuple tuple) {
        return1L;
    }
 
    publicLong combine(Long val1, Long val2) {
        returnval1 + val2;
    }
 
    publicLong zero() {
        return0L;
    }
}

当使用aggregate()方法代替partitionAggregate()方法时,就能看到CombinerAggregation带来的好处。这种情况下,Trident会自动优化计算:先做局部聚合操作,然后再通过网络传输tuple进行全局聚合。

ReducerAggregator接口如下:

1
2
3
4
publicinterface ReducerAggregator extendsSerializable {
    T init();
    T reduce(T curr, TridentTuple tuple);
}

ReducerAggregator使用init()方法产生一个初始值,对于每个输入tuple,依次迭代这个初始值,最终产生一个单值输出tuple。下面示例了如何将Count定义为ReducerAggregator:

1
2
3
4
5
6
7
8
9
publicclass Count implementsReducerAggregator {
    publicLong init() {
        return0L;
    }
 
    publicLong reduce(Long curr, TridentTuple tuple) {
        returncurr + 1;
    }
}

最通用的聚合接口是Aggregator,如下:

1
2
3
4
5
publicinterface Aggregator extendsOperation {
    T init(Object batchId, TridentCollector collector);
    voidaggregate(T state, TridentTuple tuple, TridentCollector collector);
    voidcomplete(T state, TridentCollector collector);
}

Aggregator可以输出任意数量的tuple,且这些tuple的字段也可以有多个。执行过程中的任何时候都可以输出tuple(三个方法的参数中都有collector)。Aggregator的执行方式如下:

1、处理每个batch之前调用一次init()方法,该方法的返回值是一个对象,代表aggregation的状态,并且会传递给下面的aggregate()和complete()方法。

2、每个收到一个该batch中的输入tuple就会调用一次aggregate,该方法中可以更新状态(第一点中init()方法的返回值)。

3、当该batch partition中的所有tuple都被aggregate()方法处理完之后调用complete方法。

注:理解batch、partition之间的区别将会更好的理解上面的几个方法。

下面的代码将Count作为Aggregator实现:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
publicclass CountAgg extendsBaseAggregator {
    staticclass CountState {
        longcount = 0;
    }
 
    publicCountState init(Object batchId, TridentCollector collector) {
        returnnew CountState();
    }
 
    publicvoid aggregate(CountState state, TridentTuple tuple, TridentCollector collector) {
        state.count+=1;
    }
 
    publicvoid complete(CountState state, TridentCollector collector) {
        collector.emit(newValues(state.count));
    }
}

有时需要同时执行多个聚合操作,这个可以使用链式操作完成:

1
2
3
4
mystream.chainedAgg()
        .partitionAggregate(newCount(), newFields("count"))
        .partitionAggregate(newFields("b"),newSum(), newFields("sum"))
        .chainEnd()

这段代码将会对每个partition执行Count和Sum聚合器,并输出一个tuple(字段为 ["count", "sum"])。

stateQuery and partitionPersist

参见Trident state一文。

projection

经Stream中的project方法处理后的tuple仅保持指定字段(相当于过滤字段)。例如,mystream中的字段为 ["a", "b", "c", "d"],执行下面代码:

1
mystream.project(newFields("b","d"))

则输出流将仅包含["b", "d"]字段。

Repartitioning operations

Repartition操作可以改变tuple在各个task之上的划分。Repartition也可以改变Partition的数量。Repartition需要网络传输。下面都是repartition操作:

1、shuffle:随机将tuple均匀地分发到目标partition里。

2、broadcast:每个tuple被复制到所有的目标partition里,在DRPC中有用 — 你可以在每个partition上使用stateQuery。

3、partitionBy:对每个tuple选择partition的方法是:(该tuple指定字段的hash值) mod (目标partition的个数),该方法确保指定字段相同的tuple能够被发送到同一个partition。(但同一个partition里可能有字段不同的tuple)

4、global:所有的tuple都被发送到同一个partition。

5、batchGlobal:确保同一个batch中的tuple被发送到相同的partition中。

6、patition:该方法接受一个自定义分区的function(实现backtype.storm.grouping.CustomStreamGrouping)

Aggregation operations

Trident中有aggregate()和persistentAggregate()方法对流进行聚合操作。aggregate()在每个batch上独立的执行,persistemAggregate() 对所有batch中的所有tuple进行聚合,并将结果存入state源中。

aggregate()对流做全局聚合,当使用ReduceAggregator或者Aggregator聚合器时,流先被重新划分成一个大分区(仅有一个partition),然后对这个partition做聚合操作;另外,当使用CombinerAggregator时,Trident首先对每个partition局部聚合,然后将所有这些partition重新划分到一个partition中,完成全局聚合。相比而言,CombinerAggregator更高效,推荐使用。

下面的例子使用aggregate()对一个batch操作得到一个全局的count:

1
mystream.aggregate(newCount(), newFields("count"))

同在partitionAggregate中一样,aggregate中的聚合器也可以使用链式用法。但是,如果你将一个CombinerAggregator链到一个非CombinerAggregator后面,Trident就不能做局部聚合优化。

关于persistentAggregate的用法请参见Trident state一文。

Operations on grouped streams

groupBy操作先对流中的指定字段做partitionBy操作,让指定字段相同的tuple能被发送到同一个partition里。然后在每个partition里根据指定字段值对该分区里的tuple进行分组。下面演示了groupBy操作的过程:

Operations on grouped streams

如果你在一个grouped stream上做聚合操作,聚合操作将会在每个分组(group)内进行,而不是整个batch上。GroupStream类中也有persistentAggregate方法,该方法聚合的结果将会存储在一个key值为分组字段(即groupBy中指定的字段)的MapState中,这些还是在Trident state一文中讲解。

和普通的stream一样,groupstream上的聚合操作也可以使用链式语法。

Merges(合并) and joins(连接)

最后一部分内容是关于将几个stream汇总到一起,最简单的汇总方法是将他们合并成一个stream,这个可以通过TridentTopology中德merge方法完成,就像这样:

1
topology.merge(stream1, stream2, stream3);

Trident指定新的合并之后的流中的字段为stream1中的字段。

另一种汇总方法是使用join(连接,类似于sql中的连接操作)。下面的在stream1( ["key", "val1", "val2"] ) 和 stream2[, "val1"]

两个流之间做连接操作:

1
topology.join(stream1,newFields("key"), stream2, newFields("x"),newFields("key","a","b","c"));

上面这个连接操作使用”key”和”x”字段作为连接字段。由于输入流中有重叠的字段名(如上面的val1字段在stream1和stream2中都有),Trident要求指定输出的新流中的所有字段。输出流中的tuple要包含下面这些字段:

1、连接字段列表:如本例中的输出流中的”key”字段对应stream1中的”key”和stream2中的”x”。

2、来自所有输入流中的非连接字段列表,按照传入join方法中的输入流的顺序:如本例中的”a”和”b”对应于stream1中的”val1″ 和 “val2″,”c” 对应stream2中的 “val1″。

Over.

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 微信里保密柜密码忘记了怎么办 qq漫游记录密码忘了怎么办 当你很烦的时候怎么办 当你烦的时候怎么办 面对刁蛮不讲理的老婆怎么办 老是想以前的事怎么办 被心机婊陷害了怎么办 分手了还被骚扰怎么办 苹果手机屏幕出现冷暖屏怎么办 我感觉媳妇不漂亮怎么办 90后赚不到钱怎么办 处对象感觉好累怎么办 谈朋友感觉好累怎么办 家庭条件不好娶老婆难办怎么办? 异地恋闹矛盾了怎么办 有人威胁要杀我全家怎么办 分手了借我的钱怎么办 脸打架打肿了怎么办 人家不加我qq好友怎么办 一个好友被删了怎么办 dnf脸黑怎么办还有办法 我想登别人微信怎么办 昌硕工资没到怎么办 昌硕离职不批怎么办 昌硕工资不到卡怎么办 上海人去苏州工作社保怎么办 娶个个脾气暴躁的媳妇怎么办 满脸的黑头痘痘怎么办 脚底磨起泡不敢走路怎么办 老婆老是找异性朋友怎么办 喜欢的人有对象怎么办 遇到了更喜欢的怎么办 8岁骨龄11岁怎么办啊 13岁初中生有思想不听话怎么办 交朋友找对象喜欢颜值高的怎么办 儿子找对象不听父母怎么办 缺爱怎么办的搞笑回答 对象说有人追她怎么办 说了一句话媳妇非常生气怎么办 柔顺后头发太臭怎么办 积分兑换手机被骗了怎么办