In saavn.com, we convert our webserver logs into json format. Lets call these as unprocessed_json_logs. These unprocessed_json_logs need some cleanup before they can be actually used for other data processing. We will perform the cleanup and call the result as processed_json_logs which are also in json format.
Sample row of unprocessed_json_logs looks like :
{'uid': 'user1', 'event' : 'android:click_homepage', 'country': 'IN', k1:v1, k2:v2, k3:v3 .... }
Sample row of processed_json_logs looks like :
{'uid': 'user1', 'event' : 'click_homepage','platform':'android', 'country': 'IN', k1:v1, k2:v2, k3:v3 .... }
{'uid': 'user1', 'event' : 'android:click_homepage', 'country': 'IN', k1:v1, k2:v2, k3:v3 .... }
Sample row of processed_json_logs looks like :
{'uid': 'user1', 'event' : 'click_homepage','platform':'android', 'country': 'IN', k1:v1, k2:v2, k3:v3 .... }
Point to notice here is that in addition to fields of you interest, there are some dont-care key-value pairs that should simply be passed though. They should remain same in unprocessed_json_logs and processed_json_logs.
A Bad solution using Json-serde
CREATE TABLE unprocessed_json_logs (uid string, event string, country string, k1 string, k2 string, k3 string, ..., kn string) LOCATION 's3://mycompany/unprocessed_json_logs';
CREATE TABLE processed_json_logs (uid string, event string, platform string , country string, k1 string, k2 string, k3 string, ..., kn string) LOCATION 's3://mycompany/processed_json_logs';
INSERT OVERWRITE TABLE processed_json_logs
SELECT uid, split(event, '\:')[1] as event , split(event, '\:')[0] as platform country, k1, k2, k3 ... ,kn
FROM unprocessed_json_logs
This solution is bad because eveytime a new key-pair is added to unprocessed_json_logs lets say Kn+1:Vn+1, you will have to update your hive script. This sounds like a maintenance nightmare -doesn't it?
A better solution using Hive Streaming
CREATE TABLE unprocessed_json_logs (jsonstr string) LOCATION 's3://mycompany/unprocessed_json_logs';
CREATE TABLE processed_json_logs (jsonstr string) LOCATION 's3://mycompany/processed_json_logs';
INSERT OVERWRITE TABLE processed_json_logs
SELECT TRANSFORM (jsonstr)
USING 'cleanup.php'
FROM unprocessed_json_logs
Idea here is to read the whole json in one string variable jsonstr. This jsonstr is passed as it is to a reducer cleanup.php. Now all the cleanup takes place inside this reducer. In the reducer you can decode the json, make changes to the fields of your interest while leaving dont-care key-value pars as it is and then print it to stdout. As you must notice, hive query and reducer both do not make any mention of dont care key-value pairs. So when new key-value pairs show up in your logs, you will not have to change your code.
CREATE TABLE unprocessed_json_logs (uid string, event string, country string, k1 string, k2 string, k3 string, ..., kn string) LOCATION 's3://mycompany/unprocessed_json_logs';
INSERT OVERWRITE TABLE processed_json_logs
SELECT uid, split(event, '\:')[1] as event , split(event, '\:')[0] as platform country, k1, k2, k3 ... ,kn
FROM unprocessed_json_logs
This solution is bad because eveytime a new key-pair is added to unprocessed_json_logs lets say Kn+1:Vn+1, you will have to update your hive script. This sounds like a maintenance nightmare -doesn't it?
A better solution using Hive Streaming
CREATE TABLE unprocessed_json_logs (jsonstr string) LOCATION 's3://mycompany/unprocessed_json_logs';
INSERT OVERWRITE TABLE processed_json_logs
SELECT TRANSFORM (jsonstr)
USING 'cleanup.php'
FROM unprocessed_json_logs
Idea here is to read the whole json in one string variable jsonstr. This jsonstr is passed as it is to a reducer cleanup.php. Now all the cleanup takes place inside this reducer. In the reducer you can decode the json, make changes to the fields of your interest while leaving dont-care key-value pars as it is and then print it to stdout. As you must notice, hive query and reducer both do not make any mention of dont care key-value pairs. So when new key-value pairs show up in your logs, you will not have to change your code.
