Java Developers Guide to ETL with Cascading

Part 5: Advanced Aggregation: Implementing moving averages

What You Will See

Part 5 is an advanced aggregation exercise that performs rolling averages in an ETL flow. There are no new Cascading constructs introduced, rather this exercise illustrates the design pattern to implement rolling averages and other trending computations so often used in data applications.

Run and Validate Your Program

Step 1: Compile your program

$ cd etl-log/part5
$ gradle clean jar

Step 2: If you have not done it already from the Part 1, copy the log file to Hadoop:

$ hadoop dfs -mkdir /logs
$ hadoop dfs -put ../data/NASA_access_log_Aug95.txt /logs

Step 3: Run your ETL flow

$ hadoop jar ./build/libs/etl.jar /logs/NASA_access_log_Aug95.txt /output

Step 4: View the execution of your ETL flow in real-time through Driven

Depending on how you configured your Driven Plugin, either click the Driven URL from your console or log into the Driven application.

14/08/28 12:01:53 INFO state.AppStats: shutdown hook finished.
14/08/28 12:01:53 INFO rest.DrivenDocumentService: http://localhost:8080/driven/3B8BE330F87B4DF9BA9C7CABB3E1BC16
14/08/28 12:01:53 INFO rest.DrivenDocumentService: messaging version 1.0-eap-57:JSON

Attached is a live Driven link to execute Part 5 exercise on the Concurrent cloud service.


Figure 1: An example of the performance view in Driven.


Driven exposes three views of the DAG — Logical, Physical and Contracted. The Logical View lets you inspect and visualize the Tap, Pipe and other Cascading constructs that you specified in your code. With Physical View, you can also inspect intermediate Tap and Pipe Assemblies embedded in your code. In our case, we can see that the Retain function was used in the subassembly.

Step 5: View contents of the result file that contain the moving average by bandwidth size.

$ hadoop fs -cat /output/part-00000

What’s Going On?

Note: The comments in the snippet explain the moving average operation.

// Create a new Each named moving_avgSizeByMinPipe to augment the tuple with hour of the day for time
Pipe moving_avgSizeByMinPipe = new Each( filterResponsePipe, new Fields( "time" ), new DayForTimestamp(), Fields.ALL );

// Calculates moving average 60 mins based on bandwith
// Groups by min, calculates 60 mins moving average on field size
moving_avgSizeByMinPipe = new GroupBy( moving_avgSizeByMinPipe, new Fields( "day" ) );
moving_avgSizeByMinPipe = new Every( moving_avgSizeByMinPipe, new Fields( "size", "time" ),
                                        new MovingAverageBuffer( new Fields( "min", "moving_average" ) ), Fields.RESULTS );