[Solved-1 Solution] Equivalent of linux 'diff' in Apache Pig ?



Problem :

We want to be able to do a standard diff on two large files.

A = load 'A' as (line);
B = load 'B' as (line);
JOINED = join A by line full outer, B by line;
DIFF = FILTER JOINED by A::line is null or B::line is null;
DIFF2 = FOREACH DIFF GENERATE (A::line is null?B::line : A::line), (A::line is null?'REMOVED':'ADDED');
STORE DIFF2 into 'diff';

The above code will work but it's not nearly as quick as diff on the command line.

Solution 1:

We use the following approaches , perhaps we were using only one reducer

We use the pig that has algorithm that adjust the reducers

  • Both approaches we use are within a few percent of each other in performance but do not treat duplicates the same
  • The JOIN approach collapses duplicates
  • The UNION approach works like the Unix diff(1) tool and will return the correct number of extra duplicates for the correct file
  • Unlike the Unix diff(1) tool, order is not important (effectively the JOIN approach performs sort -u <foo.txt> | diff while UNION performs sort &</foo> | diff)
  • If we have an incredible (~thousands) number of duplicate lines, then things will slow down due to the joins.
  • If your lines are very long (e.g. >1KB in size), then it would be recommended to use the DataFu MD5 UDF and only difference over hashes then JOIN with your original files to get the original row back before outputting.

The below code is given by using JOIN approach

SET job.name 'Diff(1) Via Join'

-- Erase Outputs
rmf first_only
rmf second_only

-- Process Inputs
a = LOAD 'a.csv.lzo' USING com.twitter.elephantbird.pig.load.LzoPigStorage('\n') AS First: chararray;
b = LOAD 'b.csv.lzo' USING com.twitter.elephantbird.pig.load.LzoPigStorage('\n') AS Second: chararray;

-- Combine Data
combined = JOIN a BY First FULL OUTER, b BY Second;

-- Output Data
SPLIT combined INTO first_raw IF Second IS NULL,
                    second_raw IF First IS NULL;
first_only = FOREACH first_raw GENERATE First;
second_only = FOREACH second_raw GENERATE Second;
STORE first_only INTO 'first_only' USING Pi

Here is the code that using UNION approach

SET job.name 'Diff(1)'

-- Erase Outputs
rmf first_only
rmf second_only

a_raw = LOAD 'a.csv.lzo' USING com.twitter.elephantbird.pig.load.LzoPigStorage('\n') AS Row: chararray;
b_raw = LOAD 'b.csv.lzo' USING com.twitter.elephantbird.pig.load.LzoPigStorage('\n') AS Row: chararray;

a_tagged = FOREACH a_raw GENERATE Row, (int)1 AS File;
b_tagged = FOREACH b_raw GENERATE Row, (int)2 AS File;

-- Combine Data
combined = UNION a_tagged, b_tagged;
c_group = GROUP combined BY Row;

  • It takes roughly 10 minutes to difference over 200GB (1,055,687,930 rows) using LZO compressed input with 18 nodes.
  • Each approach only takes one Map/Reduce cycle.
  • This results in roughly 1.8GB differ per node, per minute (not a great throughput but on my system it seems diff(1) only operates in-memory, while Hadoop leverages streaming disks.

Related Searches to Equivalent of linux 'diff' in Apache Pig