// Copyright 2016 Twitter. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.twitter.heron.integration_test.common.bolt; import java.io.IOException; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.twitter.heron.api.bolt.BaseBasicBolt; import com.twitter.heron.api.bolt.BasicOutputCollector; import com.twitter.heron.api.topology.OutputFieldsDeclarer; import com.twitter.heron.api.tuple.Fields; import com.twitter.heron.api.tuple.Tuple; import com.twitter.heron.api.tuple.Values; /** * A bolt that read a tweet in json format, and then filter out the tweets, whose * the top-level property given is equal to the value given, and emit it. * Example, given the property "lang" and value "zh", this bolt will read a tweet and emit the tweet * , whose "lang" is "zh" */ public class JSONTweetFilterBolt extends BaseBasicBolt { private static final long serialVersionUID = -7159267336583563993L; private static final Logger LOG = Logger.getLogger(JSONTweetFilterBolt.class.getName()); private static final ObjectMapper MAPPER = new ObjectMapper(); private String propName; private Object propValue; public JSONTweetFilterBolt(String propName, Object propValue) { this.propName = propName; this.propValue = propValue; } @Override public void execute(Tuple tuple, BasicOutputCollector basicOutputCollector) { String tweet = tuple.getString(0); if (isFiltered(tweet)) { basicOutputCollector.emit(new Values(tweet)); } } @Override public void declareOutputFields(OutputFieldsDeclarer declarer) { declarer.declare(new Fields(propName)); } /** * Judge whether filter a tweet or not */ private boolean isFiltered(String tweet) { // Parse JSON entry Map<String, Object> tweetJson = null; try { tweetJson = MAPPER.readValue(tweet, new TypeReference<Map<String, Object>>() { }); } catch (IOException e) { LOG.log(Level.SEVERE, "Failed to parse the String into map: " + tweet, e); } Object propVal = null; if (tweetJson == null) { propVal = ""; } else { // Is this a tweet if (tweetJson.containsKey("id") && tweetJson.containsKey("created_at") && tweetJson.containsKey("text") && tweetJson.containsKey("user")) { propVal = tweetJson.get(this.propName); if (propVal.equals(this.propValue)) { return true; } } } return false; } }