3. Cascading, what is it?
Java framework
Apache License, Version 2.0
To build data-oriented applications
e.g. ETL-like applications
4. Cascading key features
Java API
Mature (runs on MapReduce for years)
Testability
Re-usability
Built-in features (filter, join, aggregator, etc)
5. Cascading simple flow
Fields usersFields = new Fields(
"name","country","gender"
);
Pipe users = new Pipe("users");
users = new Unique(users,new Fields("name"));
jason US M
arnaud FR M
cynthia US F
mike US M
paul GB M
anna RU F
clare GB F
input file
6. Connecting flow to source and sink
Fields usersFields = new Fields("name","country","gender");
Pipe users = new Pipe("users");
users = new Unique(users,new Fields("name"));
Tap usersIn = ... // file’s location and structure abstraction
Tap usersOut = ...
FlowDef flowDef = FlowDef.flowDef()
.addSource(users, usersIn)
.addTailSink(users, usersOut);
7. Taps and schemes
Fields usersFields = new Fields("name","country","gender");
Pipe users = new Pipe("users");
users = new Unique(users,new Fields("name"));
Tap usersIn = new Hfs(
new TextDelimited(usersFields,false,"t"), // structure
"/in" // location
);
Tap usersOut = new Hfs(
new TextDelimited(usersFields, false, "t"),"/out"
);
8. Executing a MapReduce flow
FlowDef flowDef = FlowDef.flowDef()
.addSource(users, usersIn)
.addTailSink(users, usersOut);
new Hadoop2MR1FlowConnector().connect(flowDef).complete();
9. My first MapReduce flow
Fields usersFields = new Fields("name","country","gender");
Pipe users = new Pipe("users");
users = new Unique(users,new Fields("name"));
Tap usersIn = new Hfs(...);
Tap usersOut = new Hfs(...);
FlowDef flowDef = FlowDef.flowDef()
.addSource(users, usersIn)
.addTailSink(users, usersOut);
new Hadoop2MR1FlowConnector().connect(flowDef).complete();
10. Changing the output
Fields usersFields = new Fields("name","country","gender");
Pipe users = new Pipe("users");
users = new Unique(users,new Fields("name"));
Tap usersIn = new Hfs(...);
Tap usersOut = new Hfs( new SequenceFile(usersFields),"/out");
FlowDef flowDef = FlowDef.flowDef()
.addSource(users, usersIn)
.addTailSink(users, usersOut);
new Hadoop2MR1FlowConnector().connect(flowDef).complete();
17. Local connector for testing
Fields usersFields = new Fields("name","country","gender");
Pipe users = new Pipe("users");
users = new Unique(users,new Fields("name"));
Tap usersIn = new FileTap(new TextDelimited(usersFields,false,"t"),"in.txt");
Tap usersOut = new FileTap(
new TextDelimited(usersFields, false, "t"), "out.txt"
);
FlowDef flowDef = FlowDef.flowDef()
.addSource(users, usersIn)
.addTailSink(users, usersOut);
new LocalFlowConnector().connect(flowDef).complete();
18. Users by countries
Fields usersFields = new Fields("name","country","gender");
Pipe users = new Pipe("users");
users = new GroupBy(users,new Fields("country"));
users = new Every(users,new Count(new Fields("count")));
Tap usersOut = new FileTap(
new TextDelimited(new Fields("country","count"), false, "t"),"/out.txt"
);
jason US M
arnaud FR M
cynthia US F
mike US M
paul GB M
anna RU F
clare GB F
FR 1
RU 1
GB 2
US 3
19. Usage by countries?
jason US M
arnaud FR M
cynthia US F
mike US M
paul GB M
anna RU F
clare GB F
jason login
mike newcontract
cynthia login
anna logout
jason newcontract
jason logout
...
logs users
20. Join logs and users
Fields usersFields = new Fields("name","country","gender");
Fields logsFields = new Fields("username","action");
Pipe users = new Pipe("users");
Pipe logs = new Pipe("logs");
Pipe logsUsers = new CoGroup(
logs,new Fields("username"),
users,new Fields("name")
);
21. Join logs and users
Pipe logsUsers = new CoGroup(
logs,new Fields("username"),
users,new Fields("name")
);
jason login
mike newcontract
cynthia login
anna logout
jason newcontract
jason logout
...
jason US M
arnaud FR M
cynthia US F
mike US M
paul GB M
anna RU F
clare GB F
anna RU F logout
cynthia US F login
jason US M login
jason US M newcontract
jason US M logout
mike US M newcontract
22. Usage by country
logsUsers = new GroupBy(logsUsers,new Fields("country"));
logsUsers = new Every(logsUsers,new Count(new Fields("count")));
23. Usage by countries
Tap usersIn = new FileTap(new TextDelimited(usersFields,false,"t"),"users.txt");
Tap logsIn = new FileTap(new TextDelimited(logsFields,false,"t"),"logs.txt");
Tap usageOut = new FileTap(
new TextDelimited(new Fields("country","count"), false, "t"),
"usage.txt"
);
FlowDef flowDef = FlowDef.flowDef()
.addSource(users, usersIn)
.addSource(logs,logsIn)
.addTailSink(logsUsers, usageOut);
RU 1
US 5
26. Optimization in Cascading CoGroup
“During co-grouping, for any given unique grouping key, all of the rightmost
pipes will accumulate the current grouping values into memory so they
may be iterated across for every value in the left hand side pipe.
(...)
There is no accumulation for the left hand side pipe, only for those to the
"right".
Thus, for the pipe that has the largest number of values per unique key
grouping, on average, it should be made the "left hand side" pipe (lhs).”
28. Function
users = new Each(
users,
new Fields("country"), // argument
new CountryFullnameFunction(new Fields("countryFullname")), // function output
new Fields("name","countryFullname","gender") // what we keep
);
jason United States M
arnaud France M
cynthia United States F
mike United States M
paul United Kingdom M
anna Russia F
clare United Kingdom F
29. Function (naive) implementation
public static class CountryFullnameFunction extends BaseOperation implements Function {
public CountryFullnameFunction(Fields fields) {
super(fields);
}
@Override
public void operate(FlowProcess flowProcess, FunctionCall functionCall) {
String country = functionCall.getArguments().getString(0);
Locale locale = new Locale("",country);
Tuple tuple = new Tuple();
tuple.add(locale.getDisplayCountry(Locale.ENGLISH));
functionCall.getOutputCollector().add(tuple);
}
}
30. Functions
public static class CountryFullnameFunction extends BaseOperation implements Function {
public CountryFullnameFunction(Fields fields) {
super(fields);
}
@Override
public void operate(FlowProcess flowProcess, FunctionCall functionCall) {
// this is executed remotely
// tips: initialize (small) caches, re-use objects, etc.
// functions have callbacks for this
}
}
31. Re-using objects in a function
public static class CountryFullnameFunction extends BaseOperation implements Function {
Tuple tuple = new Tuple();
public CountryFullnameFunction(Fields fields) {
super(fields);
}
@Override
public void operate(FlowProcess flowProcess, FunctionCall functionCall) {
String country = functionCall.getArguments().getString(0);
Locale locale = new Locale("",country);
tuple.clear();
tuple.add(locale.getDisplayCountry(Locale.ENGLISH));
functionCall.getOutputCollector().add(tuple);
}
}
32. Using Avro with Cascading
// Avro is splittable, supports compression,
// and has schemas
Schema schema = new Schema.Parser().parse(schemaAsJson);
AvroScheme avroScheme = new AvroScheme(schema);
Tap tap = new Hfs(avroScheme,"/out");
33. Using Parquet files
// Parquet is column-oriented
// it supports splits and compression
MessageType type = ... // ~ the schema
Scheme parquetScheme = new ParquetTupleScheme(
fields, // fields to read
fields, // fields to write
type.toString()
);
Tap tap = new Hfs(
parquetScheme,
"/out"
);
40. Join generated and reference data
Hadoop
Processing
(join, transformation)
Generated data
Reporting
Reference data
41. Data handling
Raw data Parsed data
Processing and
insertion
Archives View on data Transformations
Avro, GZIP
Keep it for forever
Parquet, Snappy
Keep 2 years of data
Processing (Cascading)
HDFS Real time DB
42. Flow handling with Spring Batch
Archiving
Processing Processing Processing
Cleaning
Java, API HDFS
Cascading
MapReduce