The way Twitter's search function works, we can end up having tweets in the stream that have no words that we were monitoring for. We can solve this problem by adding some additional filtering based on the text and the keywords that we are following.
There are a few ways to do that but, for the sake of the exercise, we will make use of a way that doesn't involve for loops and if statements. This approach might come in handy for other problems that might require a reactive way to solve them.
First of all, let's extract the monitored keywords to a separate variable--trackingKeywords:
final String[] trackingKeywords = {"Yahoo", "Google", "Microsoft"};
final FilterQuery filterQuery = new FilterQuery()
.track(trackingKeywords)
.language("en");
Next, we will add a filtering block to the tweet generating Observable. Consider the following block:
observeTwitterStream(configuration, filterQuery)
.sample(2700, TimeUnit.MILLISECONDS)
.map(StockUpdate::create)
It will be appended with this:
.flatMapMaybe(update -> Observable.fromArray(trackingKeywords)
.filter(keyword -> update.getTwitterStatus()
.toLowerCase().contains(keyword.toLowerCase()))
.map(keyword -> update)
.firstElement()
)
Let's break this down into parts. First of all, the following line changes the element that we are working with from StockUpdate to the stream of keywords that we are monitoring:
update -> Observable.fromArray(trackingKeywords)
By doing this, we can iterate (filter) through each of the keywords and check it against the update object with this:
.filter(keyword -> update.getTwitterStatus().toLowerCase().contains(keyword.toLowerCase()))
Since we have transformed the stream of StockUpdate items into keywords, we need to convert it back using this:
.map(keyword -> update)
Finally, the following line ensures that only one StockUpdate object is returned even if there are multiple keywords that match the content inside the tweet:
.firstElement()
Obviously, everything could have been done with a simple if statement and a for loop inside the .filter() block, as shown:
.filter(stockUpdate -> {
for(String keyword : trackingKeywords) {
if (stockUpdate.getTwitterStatus().contains(keyword)) {
return true;
}
}
return false;
})
However, it's no fun, and we would have learned much less.