Wednesday, July 13, 2016

Identifying Emotions from tweets for a Social Event using R in IBM Data Scientist Workbench


This blog describes the steps on - How to identify the emotions from tweets for an event. As an example, I have taken the event "Britian Exit".  I am using IBM Data Scientist Workbench, that is an online platform where you can directly execute R statements using RStudio. I would recommend you to use the  Data Scientist Workbench because it has RStudio and Apache Spark in a single platform without installing it, in your machine.

The blog covers

1) Setting up the infrastructure IBM Data Scientist Workbench
2) Setting up Twitter App for OAuth.
3) Connecting to Twitter using R
4) Cleansing the tweets
5) Identifying the emotions
6) Plot the graph with emotions & tweets


1) Setting up the infrastructure - IBM Data Scientist Workbench

Create an online account in https://my.datascientistworkbench.com/login

Login to Data Scientist Workbench and click on RStudio IDE


  

 





















2) Setting up Twitter App for OAuth

Login to  to https://apps.twitter.com/app/new and create an Application.


























Open the "Keys and Access Tokens" Tab and get the Consumer Key, Consumer Secret, Access Token, Access Token Secret.


 
 3) Connecting to Twitter using R

We are using existing R Libraries to connect to Twitter. Install the required libraries

install.packages("twitteR")
install.packages("ROAuth")


Below statements will load the libraries & Connect to twitter. We are doing a search for some popular hashtags.

> library("twitteR")
>
> library("ROAuth") 
>
> dir.create(file.path("/resources", "BRExit"), mode = "0777")
>
> setwd("/resources/BRExit")
>
> getwd()
[1] "/resources/BRExit"
>
> download.file(url="http://curl.haxx.se/ca/cacert.pem", destfile="cacert.pem")
trying URL 'http://curl.haxx.se/ca/cacert.pem'
Content type 'unknown' length 250607 bytes (244 KB)
==================================================
downloaded 244 KB

>## Provide the proper keys & token got from step 2.
> consumer_key <- 'xxxxxxxxxxx'
>
> consumer_secret <- 'xxxxxxxxxxxxxxxxxxxxxxx'
>
> access_token <- 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
>
> access_secret <- 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
>
> twiter_handle <- setup_twitter_oauth(consumer_key,consumer_secret,access_token,access_secret)
[1] "Using direct authentication"
Use a local file ('.httr-oauth'), to cache OAuth access credentials between R sessions?

1: Yes
2: No

Selection: 1
Adding .httr-oauth to .gitignore




Now, we query the Twitter to get the tweets related to hashtags.

> search_term <- "#brexit,#strongerin,#yes2eu"
> 
> search_term <- unlist(strsplit(search_term,","))
> 
> tweets = list()
>  
> ## You may get warning because of Twitter rate limit.
> ## If there is many hashtags, then you may need to stop it after sometime since
> ## Twitter will impose the Rate Limit and you will be getting the exception to 
> ## getting the tweets. 
> for(i in 1:length(search_term)){
     result<-searchTwitter(search_term[i],n=1500,lang="en")
     tweets <- c(tweets,result)
     tweets <- unique(tweets)
 }
Warning message:
In doRppAPICall("search/tweets", n, params = params, retryOnRateLimit = retryOnRateLimit,  :
  1500 tweets were requested but the API can only return 107
>
> ## Collected 3107 tweets  
> length(tweets)
[1] 3107
>  
> ## Display 5 tweets
> head(tweets)
[[1]]
[1] "AAPLRoom: AAPL Trading Room Newsletter is out! https://t.co/cXzBstbEI1 #trading #brexit"

[[2]]
[1] "DVATW: If #TheresaMay becomes PM then the hope and optimism of a fast clean #Brexit is over."

[[3]]
[1] "melvine: RT @RoubiniGlobal: #Brexit Circus: Which branch of the #EU line will the UK take? #MindTheGap https://t.co/mvFceRuJpy"
























Save the tweets to a file for other types of analytics on the data.


> file<-NULL
> 
> if (file.exists("tweetsBRExit.csv")){file<- read.csv("tweetsBRExit.csv")}
> 
> df <- do.call("rbind", lapply(tweets, as.data.frame))
> 
> df<-rbind(df,file)
> 
> df <- df[!duplicated(df[c("id")]),]
> 
> write.csv(df,file="tweetsBRExit.csv",row.names=FALSE)
> 





















You could see the tweet is exported to /resources/BRExit/tweetsBRExit.csv. It has various informations that can be helpfull for building another insights like influencers, geo influence etc.

I am sharing the column names for your reference.

"text","favorited","favoriteCount","replyToSN","created","truncated","replyToSID","id",
"replyToUID","statusSource","screenName","retweetCount","isRetweet",
"retweeted","longitude","latitude"



4) Cleansing the tweets 

We do some cleansing of tweets like removing the whitespace, numbers, punctuatoions etc.

> library(tm)
Loading required package: NLP
> 
> twitter_brexit_df = twListToDF(tweets)
> 
> r_text_corpus <- Corpus(VectorSource(twitter_brexit_df$text))
> 
> r_text_cleansing <- tm_map(r_text_corpus, stripWhitespace)
> 
> r_text_cleansing <- tm_map(r_text_cleansing, removeNumbers)
> 
> r_text_cleansing <- tm_map(r_text_cleansing, removePunctuation)
> 
> r_text_cleansing <- tm_map(r_text_cleansing, content_transformer(tolower))
> 






















5) Identifying the emotions

We are using the Library syuzhet to identify the emotions of the tweets. The get_nrc_sentiment implements Saif Mohammad’s NRC Emotion lexicon
Refer: http://www.purl.org/net/NRCemotionlexicon

> install.packages("syuzhet")
>
> library(syuzhet)
> 
> isNull <- function(data) {
     if(is.null(data))
         return(0)
     else
         return(data)
 }
> 
> text_vec = c()
> anger = c() ; anticipation=c() ; disgust=c() ; fear=c() ; joy=c() ;
> sadness=c() ; surprise=c() ; rust=c() ; nrc_negative=c() ; nrc_positive=c();
> 
> for(i in 1:length(r_text_cleansing)){
     text <- lapply(r_text_cleansing[i], as.character)
     text <- gsub("http\\w+", "", text)
     nrc_emotions <- get_nrc_sentiment(text)
     
     text_vec[i] <- text
     anger[i] <- isNull(nrc_emotions$anger)
     anticipation[i] <- isNull(nrc_emotions$anticipation)
     disgust[i] <- isNull(nrc_emotions$disgust)
     fear[i] <- isNull(nrc_emotions$fear)
     joy[i] <- isNull(nrc_emotions$joy)
     sadness[i] <- isNull(nrc_emotions$sadness)
     surprise[i] <- isNull(nrc_emotions$surprise)
     rust[i] <- isNull(nrc_emotions$rust)
     nrc_negative[i] <- isNull(nrc_emotions$negative)
     nrc_positive[i] <- isNull(nrc_emotions$positive)
 }
> 
> nrc_df <- data.frame(text_vec,anger,anticipation,disgust,fear,joy,sadness,surprise,
                      rust,nrc_negative,nrc_positive)
> 
>
> nrc_df[1:2,2:11]
  anger anticipation disgust fear joy sadness surprise rust nrc_negative nrc_positive
1     0            0       0    0   0       0        0    0            0            0
2     0            2       0    0   3       0        2    0            0            3
>
 







Plot the graph with Emotions & Tweets

Plot the graph in R.

> par(mar=c(5.1,5,4.1,2.1))
> 
> barplot(
     sort(colSums(prop.table(nrc_df[, 2:9]))), 
     horiz = TRUE, 
     cex.names = 0.7,
     las = 1, 
     main = "Emotions for Britian Exit", 
     xlab="Percentage",
     col="lightblue"
 )
>













































I was tracking the tweets for last couple of weeks and I could see the change in emotions as time progressed.





















Sunday, June 26, 2016

Reinstalling the Services from Apache Ambari

This blog discusses on how to reinstall a component from Amabri. As an example, I have taken reinstallation of Knox.

IT IS RECOMMENDED TO GET PRODUCT TEAM INVOLVED BEFORE RUNNING THE BELOW PROCEDURE. PLEASE DO NOT TRY THIS PROCEDURE ON PRODUCTION CLUSTER DIRECTLY BEFORE TRYING IT IN YOUR DEVELOPMENT CLUSTER.

1) Stop the Knox


Syntax: curl -u admin:admin -H 'X-Requested-By: ambari' -i -X PUT -d '{"RequestInfo": {"context": "Stop KNOX REST"}, "Body": {"ServiceInfo": {"state": "INSTALLED"}}}' http://<AMBARI_IP>:8080/api/v1/clusters/<Cluster_Name>/services/KNOX


[root@bdavm621 nisan]# curl -u admin:admin -H 'X-Requested-By: ambari' -i -X PUT -d '{"RequestInfo": {"context": "Stop KNOX REST"}, "Body": {"ServiceInfo": {"state": "INSTALLED"}}}' http://bdavm621.com:8080/api/v1/clusters/BI_41/services/KNOX
HTTP/1.1 202 Accepted
User: admin
Set-Cookie: AMBARISESSIONID=1th1qyghm8v7vu39twhsrtpli;Path=/;HttpOnly
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Content-Type: text/plain
Vary: Accept-Encoding, User-Agent
Content-Length: 148
Server: Jetty(8.1.17.v20150415)

{
  "href" : "http://bdavm621.com:8080/api/v1/clusters/BI_41/requests/179",
  "Requests" : {
    "id" : 179,
    "status" : "Accepted"
  }
}[root@bdavm621 nisan]#


2) Check the KNOX is stopped

Syntax: curl -u admin:admin -H "X-Requested-by:ambari" -i -k -X GET http://<AMBARI_IP>:8080/api/v1/clusters/<Cluster_Name>/services/KNOX

 If the component is stopped the state will be INSTALLED ("state" : "INSTALLED") in the output.


[root@bdavm621 nisan]# curl -u admin:admin -H "X-Requested-by:ambari" -i -k -X GET http://bdavm621.com:8080/api/v1/clusters/BI_41/services/KNOX
HTTP/1.1 200 OK
User: admin
Set-Cookie: AMBARISESSIONID=1x0zxckld3asbozro4jmw6c55;Path=/;HttpOnly
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Content-Type: text/plain
Vary: Accept-Encoding, User-Agent
Content-Length: 1039
Server: Jetty(8.1.17.v20150415)

{
  "href" : "http://bdavm621.com:8080/api/v1/clusters/BI_41/services/KNOX",
  "ServiceInfo" : {
    "cluster_name" : "BI_41",
    "maintenance_state" : "OFF",
    "service_name" : "KNOX",
    "state" : "INSTALLED"
  },
  "alerts_summary" : {
    "CRITICAL" : 1,
    "MAINTENANCE" : 0,
    "OK" : 0,
    "UNKNOWN" : 0,
    "WARNING" : 0
  },
  "alerts" : [
    {
      "href" : "http://bdavm621.com:8080/api/v1/clusters/BI_41/services/KNOX/alerts/251",
      "Alert" : {
        "cluster_name" : "BI_41",
        "definition_id" : 101,
        "definition_name" : "knox_gateway_process",
        "host_name" : "bdavm621.com",
        "id" : 251,
        "service_name" : "KNOX"
      }
    }
  ],
  "components" : [
    {
      "href" : "http://bdavm621.com:8080/api/v1/clusters/BI_41/services/KNOX/components/KNOX_GATEWAY",
      "ServiceComponentInfo" : {
        "cluster_name" : "BI_41",
        "component_name" : "KNOX_GATEWAY",
        "service_name" : "KNOX"
      }
    }
  ],
  "artifacts" : [ ]
}[root@bdavm621 nisan]#

3) Remove KNOX

Take the backup of the knox config files under /etc/knox/conf.

Ensure all the repo files under /etc/yum.repos.d able to access the corresponding repository. Check the repository is pointing to KNOX setup. If you are using the local mirror repository then you need to start the HTTP Server ( by apachectl start ). This will ensure after you remove the KNOX, you able to install the KNOX.

If all the above prerequisite is met, remove the knoxusing below command.

Syntax: curl -u admin:admin -H "X-Requested-By: ambari" -X DELETE http://<AMBARI_IP>:8080/api/v1/clusters/<Cluster_Name>/services/KNOX

[root@bdavm621 nisan]# curl -u admin:admin -H "X-Requested-By: ambari" -X DELETE http://bdavm621.com:8080/api/v1/clusters/BI_41/services/KNOX
[root@bdavm621 nisan]#

Login to Amabri UI to confirm KNOX is removed from the UI.

3) Remove KNOX RPM's

Login to node where KNOX installed and remove the knox rpm's.

You can use any of the below commands to search the KNOX RPM's.

Syntax for searching rpm's:
yum list installed | grep knox
rpm -qa knox*
yum list installed | grep @ <repoName>

[root@bdavm621 nisan]# yum list installed | grep knox
knox_4_1_0_0.noarch                        0.6.0_TEST_23.4.1.0.0-3.el6  @TEST-4.1



Syntax to remove rpm's : yum remove <rpm_Name>

[root@bdavm621 nisan]# yum remove knox_4_1_0_0.noarch

Run the clean all command :

[root@bdavm621 nisan]# yum clean all

4) Install KNOX from Ambari UI

Re-Login to Amabri UI --> Actions --> Add Services Wizard, select KNOX and install the service again.





















Thus, we are able to reinstall the KNOX. You can try similar steps to reinstall other services in Amabri.

Wednesday, May 4, 2016

Building Apache Nutch Job & Running the WebCrawler in Hadoop

This blog talks on - How to compile / build the Nutch Job from Apache Nutch Source code and executing it in Hadoop.


1) Setup the Apache Nutch

Download the Apache Nutch source code from http://nutch.apache.org/downloads.html to Linux Machine. 

[root@rvm ~]# cd /opt

[root@rvm opt]# mkdir nutch_build


[root@rvm opt]# cd nutch_build/


[root@rvm nutch_build]# wget apache.mirror.digitalpacific.com.au/nutch/1.11/apache-nutch-1.11-src.tar.gz
--2016-05-03 17:51:02--  http://apache.mirror.digitalpacific.com.au/nutch/1.11/apache-nutch-1.11-src.tar.gz
Resolving apache.mirror.digitalpacific.com.au... 101.0.120.90, 2401:fc00:0:20e::a0
Connecting to apache.mirror.digitalpacific.com.au|101.0.120.90|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 3807144 (3.6M) [application/x-gzip]
Saving to: âapache-nutch-1.11-src.tar.gzâ

100%[========================================>] 3,807,144   1.34M/s   in 2.7s

2016-05-03 17:51:07 (1.34 MB/s) - âapache-nutch-1.11-src.tar.gzâ

[root@rvm nutch_build]# ls
apache-nutch-1.11-src.tar.gz



[root@rvm nutch_build]# tar -xvzf apache-nutch-1.11-src.tar.gz -C /opt/nutch_build/

[root@rvm nutch_build]# ls
apache-nutch-1.11  apache-nutch-1.11-src.tar.gz




2) Install the Apache Ant

Ensure Java is installed.

[root@rvm nutch_build]# java -version
openjdk version "1.8.0_45"
OpenJDK Runtime Environment (build 1.8.0_45-b13)
OpenJDK 64-Bit Server VM (build 25.45-b02, mixed mode)
[root@rvm nutch_build]#


Download the Apache ANT Binaries. 

[root@rvm nutch_build]# pwd
/opt/nutch_build


[root@rvm nutch_build]# ls
apache-nutch-1.11  apache-nutch-1.11-src.tar.gz


[root@rvm nutch_build]# wget mirror.ventraip.net.au/apache//ant/binaries/apache-ant-1.9.7-bin.tar.gz
--2016-05-03 18:13:57--  http://mirror.ventraip.net.au/apache//ant/binaries/apache-ant-1.9.7-bin.tar.gz
Resolving mirror.ventraip.net.au... 103.252.152.2, 2400:8f80:0:11::1
Connecting to mirror.ventraip.net.au|103.252.152.2|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 5601575 (5.3M) [application/x-gzip]
Saving to: âapache-ant-1.9.7-bin.tar.gzâ

100%[=========================================>] 5,601,575   1.90M/s   in 2.8s

2016-05-03 18:14:02 (1.90 MB/s) - âapache-ant-1.9.7-bin.tar.gzâ

[root@rvm nutch_build]# ls
apache-ant-1.9.7-bin.tar.gz  apache-nutch-1.11  apache-nutch-1.11-src.tar.gz
[root@rvm nutch_build]#


Move the downloaded ANT binary to Java Home and untar it. 

[root@rvm nutch_build]# mv apache-ant-1.9.7-bin.tar.gz /usr/jdk64/java-1.8.0-openjdk-1.8.0.45-28.b13.el6_6.x86_64/

[root@rvm nutch_build]# cd /usr/jdk64/java-1.8.0-openjdk-1.8.0.45-28.b13.el6_6.x86_64/

[root@rvm java-1.8.0-openjdk-1.8.0.45-28.b13.el6_6.x86_64]# tar xzf apache-ant-1.9.7-bin.tar.gz


[root@rvm java-1.8.0-openjdk-1.8.0.45-28.b13.el6_6.x86_64]# rm -rf apache-ant-1.9.7-bin.tar.gz



3) Building the Apache Nutch

Set the JAVA_HOME and NUTCH_JAVA_HOME. 

[root@rvm apache-nutch-1.11]# pwd
/opt/nutch_build/apache-nutch-1.11


[root@rvm apache-nutch-1.11]# export JAVA_HOME=/usr/jdk64/java-1.8.0-openjdk-1.8.0.45-28.b13.el6_6.x86_64/


[root@rvm apache-nutch-1.11]# export NUTCH_JAVA_HOME=/usr/jdk64/java-1.8.0-openjdk-1.8.0.45-28.b13.el6_6.x86_64/
[root@rvm apache-nutch-1.11]#


Add the property http.agent.name in /opt/nutch_build/apache-nutch-1.11/conf/nutch-site.xml 

[root@rvm nutch_build]# pwd
/opt/nutch_build


[root@rvm nutch_build]# cat apache-nutch-1.11/conf/nutch-site.xml
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<!-- Put site-specific property overrides in this file. -->
         <configuration>

        </configuration>


[root@rvm nutch_build]# vi apache-nutch-1.11/conf/nutch-site.xml


 

[root@rvm nutch_build]# cat apache-nutch-1.11/conf/nutch-site.xml
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<!-- Put site-specific property overrides in this file. -->
<configuration>
      <property>
                   <name>http.agent.name</name>
                    <value>WebCrawler</value>
                    <description></description>
       </property>
</configuration>
[root@rvm nutch_build]#


Run the makescript using ant. The execution takes more than 45 mins and it will download required jars from external repositories. Ensure that the system has the internet access.

[root@rvm apache-nutch-1.11]# /usr/jdk64/java-1.8.0-openjdk-1.8.0.45-28.b13.el6_6.x86_64/apache-ant-1.9.7/bin/ant runtime

The Nutch job will be generated under /opt/nutch_build/apache-nutch-1.11/runtime/deploy

[root@rvm deploy]# pwd
/opt/nutch_build/apache-nutch-1.11/runtime/deploy


[root@rvm deploy]# ls
apache-nutch-1.11.job  bin
[root@rvm deploy]#



4) Modifying the Nutch code to use the class org.apache.nutch.crawl.Crawl

In older version of Nutch, we had a class org.apache.nutch.crawl.Crawl that perform all the crawling operations using one single API call, that is removed in latest Nutch versions. If your application uses that class org.apache.nutch.crawl.Crawl then you can build the job with that code also.

For that, download the Crawl.java from Apache. In below, I am getting the Crawl.java from Nutch 1.7 branch.

[root@rvm crawl]# pwd
/opt/nutch_build/apache-nutch-1.11/src/java/org/apache/nutch/crawl


[root@rvm crawl]# wget http://svn.apache.org/viewvc/nutch/branches/branch-1.7/src/java/org/apache/nutch/crawl/Crawl.java?view=co -O Crawl.java

--2016-05-03 23:14:50--  http://svn.apache.org/viewvc/nutch/branches/branch-1.7/src/java/org/apache/nutch/crawl/Crawl.java?view=co
Resolving svn.apache.org... 209.188.14.144
Connecting to svn.apache.org|209.188.14.144|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/plain]
Saving to: âCrawl.javaâ

    [ <=>                                                                                                                                                ] 5,895       --.-K/s   in 0.04s

2016-05-03 23:14:53 (137 KB/s) - âCrawl.javaâ


In /opt/nutch_build/apache-nutch-1.11/src/java/org/apache/nutch/crawl/Crawl.java, remove the references of solr. Remove the below lines, from the code

a)
import org.apache.nutch.indexer.solr.SolrDeleteDuplicates;

b)
else if ("-solr".equals(args[i])) {
        solrUrl = args[i + 1];
        i++;
      }

c)
if (solrUrl != null) {
        // index, dedup & merge
        FileStatus[] fstats = fs.listStatus(segments, HadoopFSUtil.getPassDirectoriesFilter(fs));
     
        IndexingJob indexer = new IndexingJob(getConf());
        indexer.index(crawlDb, linkDb,
                Arrays.asList(HadoopFSUtil.getPaths(fstats)));

        SolrDeleteDuplicates dedup = new SolrDeleteDuplicates();
        dedup.setConf(getConf());
        dedup.dedup(solrUrl);
      }

d)
LOG.info("solrUrl=" + solrUrl);

e)

if (solrUrl == null) {
      LOG.warn("solrUrl is not set, indexing will be skipped...");
    }
    else {
        // for simplicity assume that SOLR is used
        // and pass its URL via conf
        getConf().set("solr.server.url", solrUrl);
    }

f)
 String solrUrl = null;

g) Modify the line
System.out.println
      ("Usage: Crawl <urlDir> -solr <solrURL> [-dir d] [-threads n] [-depth i] [-topN N]");
to
System.out.println
      ("Usage: Crawl <urlDir> [-dir d] [-threads n] [-depth i] [-topN N]");


Rebuild the code.

[root@rvm apache-nutch-1.11]# pwd
/opt/nutch_build/apache-nutch-1.11


[root@rvm apache-nutch-1.11]# /usr/jdk64/java-1.8.0-openjdk-1.8.0.45-28.b13.el6_6.x86_64/apache-ant-1.9.7/bin/ant runtime




5) Running the generted nutch job from Hadoop

Create the output and input directory in HDFS

[root@rvm apache-nutch-1.11]# hadoop fs -mkdir /tmp/testNutchJob
[root@rvm apache-nutch-1.11]# hadoop fs -mkdir /tmp/testNutchJob/input
[root@rvm apache-nutch-1.11]# hadoop fs -mkdir /tmp/testNutchJob/output
[root@rvm apache-nutch-1.11]#


Create a file that have set of seed URLs and load to HDFS

[root@rvm apache-nutch-1.11]# vi /opt/nutch_build/urllist.txt
[root@rvm apache-nutch-1.11]#
[root@rvm apache-nutch-1.11]# cat /opt/nutch_build/urllist.txt
http://www.ibm.com/
http://www.ibm.com/developerworks/
 


[root@rvm apache-nutch-1.11]#
[root@rvm apache-nutch-1.11]# hadoop fs -put /opt/nutch_build/urllist.txt /tmp/testNutchJob/input
[root@rvm apache-nutch-1.11]#
[root@rvm apache-nutch-1.11]# hadoop fs -tail /tmp/testNutchJob/input/urllist.txt
http://www.ibm.com/
http://www.ibm.com/developerworks/



Run the nutch.job from hadoop as hdfs user.

The org.apache.nutch.crawl.Crawl takes the arguments <urlDirContainingSeedURL> [-dir d] [-threads n] [-depth i] [-topN N] Refer: https://wiki.apache.org/nutch/bin/nutch%20crawl


[root@rvm apache-nutch-1.11]# su hdfs

[hdfs@rvm apache-nutch-1.11]$
[hdfs@rvm apache-nutch-1.11]$ hadoop jar /opt/nutch_build/apache-nutch-1.11/runtime/deploy/apache-nutch-1.11.job org.apache.nutch.crawl.Crawl /tmp/testNutchJob/input -dir /tmp/testNutchJob/output -depth 2 -topN 10




6) Viewing the crawled data

Copy the generated output from Hadoop file system to Linux file system.

[hdfs@rvm apache-nutch-1.11]$ hadoop fs -copyToLocal /tmp/testNutchJob/output /tmp

[hdfs@rvm apache-nutch-1.11]$ cd /tmp/output/
 
[hdfs@rvm output]$ ls
crawldb  linkdb  segments
[hdfs@rvm output]$


The below command convert the crawled output in sequence format to an html output for testing.

[hdfs@rvm bin]$ su root
Password:
[root@rvm bin]#
[root@rvm bin]# ./nutch commoncrawldump -outputDir /tmp/commoncrawlOutput -segment /tmp/output/segments
[root@rvm bin]#

If you want to change the Nutch configurations, you can manually open the apache-nutch-1.11.job using 7zip and update the nutch-site.xml.

In my next blog, I will be covering how to set these properties & URL filter dynamically.

Tuesday, March 29, 2016

Automated Java code to read the BigInsights Web Crawler output


 
I have heard this requirement from multiple customers, where they were looking for a java code to read the output from the BigInsights WebCrawler Application and convert to csv file for further processing.

This blog talks on how to read the web crawler output using Java. The WebCrawler application writes the output as a sequence file hence, we are using the Sequence File Reader to read the output.

1)  Create a Java project with the below code then generate a runnable jar.


package com.test;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.SequenceFile;
import org.apache.hadoop.io.Text;
import org.apache.nutch.protocol.Content;
import org.apache.nutch.util.NutchConfiguration;

public class NutchConverter {

public void readData(String coreSitePath, String inputDirPath)
throws Exception {

Configuration conf = NutchConfiguration.create();
conf.addResource(coreSitePath);
FileSystem fs = FileSystem.get(conf);
FileStatus[] statuses = fs.globStatus(new Path(inputDirPath
+ "/segments/*/content/part-*/data"));

for (FileStatus status : statuses) {
System.out.println("Processing file: " + status.getPath());
SequenceFile.Reader reader = new SequenceFile.Reader(fs,
status.getPath(), conf);
Text key = new Text();
Content content = new Content();
while (reader.next(key, content)) {
System.out.println("Key :" + key);
System.out.println("content :" + content);
}
reader.close();
}
fs.close();

}

public static void main(String[] args) throws Exception {

System.out.println("Testing... .... ");
NutchConverter sam = new NutchConverter();

String coreSitePath = args[0];
String inputDirPath = args[1];
sam.readData(coreSitePath, inputDirPath);
System.out.println("\nDone");
}

}
  




Following jar files are required to compile the java class

$BIGINSIGHTS_HOME/sheets/libext/nutch-1.4.jar
$BIGINSIGHTS_HOME/IHC/share/hadoop/common/hadoop-common-2.2.0.jar


 Generate the runnable jar.
  


  

2) Running the jar from BigInsights Cluster

Copy the jar to Cluster, then run the below command

export HADOOP_CLASSPATH=$BIGINSIGHTS_HOME/sheets/libext/nutch-1.4.jar:$HADOOP_CLASSPATH

hadoop jar /opt/Webcrawler/NutchConverter.jar $BIGINSIGHTS_HOME/hadoop-conf/core-site.xml /user/biadmin/IBMCrawlTest1

hadoop jar  <passTheCoreSiteXML> <OutputFolderUsedInWebCrawlerApplication>


 





How to run the BigInsights WebCrawler Application as an Oozie Job in BigInsights 3.2

This blog is the continuation of my previous blog. Here we discuss on, How to port the BigInsights WebCrawler Application has an Oozie Job.

1) Setup the WebCrawler Application in Eclipse as mentioned in my previous blog

2) Modify the NutchApp.java file and generate the jar file.

a) Open the NutchApp.java in /webcrawlerapp/src/main/java/com/ibm/biginsights/apps/nutch/NutchApp.java


 

Comment the Line RunJar.main (runJarArgs); and add below line

             //RunJar.main (runJarArgs);
              RunJar.unJar(new File ("./nutch-1.4.job.new"), new File("/tmp/unpack"));

             RunJar.main (runJarArgs);


import the FileUtils class

               import org.apache.commons.io.FileUtils;


In finally block, add

              FileUtils.deleteDirectory(new File("/tmp/unpack"));
 



 b) Generate the java jar into webcrawlerapp\BIApp\workflow\lib\NutchCrawler.jar





 

3) Creating an Oozie workflow

a) Copy the files under /webcrawlerapp/BIApp/workflow to BigInsights Cluster. Ensure you give proper permission for files in Linux.




















b) Create job.properties file with below detail. You need to change the hostname and port (highlighted in blue)  based your cluster.

# JobTracker and NodeName Details
jobTracker=bivm:9001
nameNode=hdfs://bivm:9000

#HDFS path where you need to copy workflow.xml and lib/*.jar to
oozie.wf.application.path=hdfs://bivm:9000/user/biadmin/NutchCrawlOozie1/


#one of the values from Hadoop mapred.queue.names
queueName=default

## urls are delimited by \n
urls=www.ibm.com/developerworks\nhttps://play.google.com/store?hl=en\n
topN=10
outputDir=/user/biadmin/IBMCrawlTest1
depth=2
filters=+.



























  
4) Running the Oozie Workflow - Run the below command from Linux terminal


# Remove the output and input folders
hadoop fs -rmr /user/biadmin/NutchCrawlOozie1
hadoop fs -rmr /user/biadmin/IBMCrawlTest1

# Move the workflow to hdfs
hadoop fs -put /opt/Webcrawler /user/biadmin/NutchCrawlOozie1

# Create outpit folder in HDFS
hadoop fs -mkdir /user/biadmin/IBMCrawlTest1

# Invoke your Oozie workflow from command line.

cd $BIGINSIGHTS_HOME/oozie/bin

# Change the hostname & port based on your cluster 
export OOZIE_URL=http://bivm:8280/oozie

./oozie job -run -config /opt/Webcrawler/job.properties 




















 
5) Testing the output - Login to Web Console then open the output folder with sheet & Basic Crawl Data reader.
 




I will be covering - How to setup the Web Crawler in BigInsights 4, in my next blog.

Wednesday, November 18, 2015

Creating Ambari Hive Views in IBM Open Platform

This blogs talks on how to create the Amabri Hive Views in IBM Open Platform.

Step 1: Login to Ambari UI, then go to HDFS --> Config --> Advanced --> Custom core-site

Update or Add the property
hadoop.proxyuser.hive.groups = *
hadoop.proxyuser.root.groups=*
hadoop.proxyuser.root.hosts=*

  





            
              Save the Configurations and Restart the HDFS.


Step 2: Go to Hive --> Config --> Setting --> Security, set "Run as end user instead of Hive user" as false.


 
 This will internally add the property hive.server2.enable.doAs to false. Save the Configuration and Restart the Hive.

Step 3: Create the directory under /user/admin under HDFS and provide proper permissions.

[root@rvm ~]# su - hdfs
[hdfs@rvm ~]$ hadoop fs -mkdir /user/admin
[hdfs@rvm ~]$ hadoop fs -chown admin:hadoop /user/admin
 


Step 4:  Click on Admin --> Manage Ambari --> Views --> Hive --> Create Instance






 Create the instance with the below details and save.


Step 5: Go to the new Hive view Instance and run the queries.





Finally you are able to create Hive Views from Ambari.

Wednesday, November 11, 2015

Building BigSQL Ad Hoc Application for running Ad Hoc Queries using IBM BigInsights

This blog talks on - How to build a BigInsights Application to run the Adhoc BigSQL Queries. You will be able to schedule these application so that it will be running on scheduled intervals.

Step 1: Create a BigInsights project in Eclipse

Refer http://big-analytics.blogspot.com.au/2015/07/building-web-crawler-in-ibm-biginsights.html to install Text Analytics Plugin in Eclipse.






Step 2:  Update the Oozie workflow.

Here, I create a temp folder in Linux filesystem and create a sql script to store the query. After that, I will be be passing it to JSQSH Client to run the query.

Update the /BigSQLAdhocQuery/BIApp/workflow/workflow.xml

<workflow-app name="wfapp" xmlns="uri:oozie:workflow:0.4">
    <start to="create-folder"/>
        <action name="create-folder">
        <shell xmlns="uri:oozie:shell-action:0.2" >
            <job-tracker>${jobTracker}</job-tracker>
            <name-node>${nameNode}</name-node>
            <configuration>
                <property>
                    <name>mapred.job.queue.name</name>
                    <value>${queueName}</value>
                </property>
            </configuration>
            <exec>bash</exec>
            <argument>-c</argument>
               <argument>/bin/mkdir -m 777 /tmp/bigSQLAdhocQuery_${wf:id()}</argument>
            <capture-output/>
        </shell>
         <ok to="create-query-file"/>
        <error to="failed-job-cleanup"/>
    </action>
    <action name="create-query-file">
        <shell xmlns="uri:oozie:shell-action:0.2" >
            <job-tracker>${jobTracker}</job-tracker>
            <name-node>${nameNode}</name-node>
            <configuration>
                <property>
                    <name>mapred.job.queue.name</name>
                    <value>${queueName}</value>
                </property>
            </configuration>
            <exec>bash</exec>
            <argument>-c</argument>
               <argument>/bin/echo "${query}" >> /tmp/bigSQLAdhocQuery_${wf:id()}/test.sql</argument>
            <capture-output/>
        </shell>
        <ok to="run-jsqsh"/>
        <error to="failed-job-cleanup"/>
    </action>
    <action name="run-jsqsh">
        <shell xmlns="uri:oozie:shell-action:0.2" >
            <job-tracker>${jobTracker}</job-tracker>
            <name-node>${nameNode}</name-node>
            <configuration>
                <property>
                    <name>mapred.job.queue.name</name>
                    <value>${queueName}</value>
                </property>
            </configuration>
            <exec>bash</exec>
            <argument>-c</argument>
               <argument>$JSQSH_HOME/bin/jsqsh -U ${user} -P ${password} -i /tmp/bigSQLAdhocQuery_${wf:id()}/test.sql -n -e ${connectionName}</argument>
            <capture-output/>
        </shell>
        <ok to="cleanup"/>
        <error to="failed-job-cleanup"/>
    </action>
   
    <action name="failed-job-cleanup">
        <shell xmlns="uri:oozie:shell-action:0.2" >
            <job-tracker>${jobTracker}</job-tracker>
            <name-node>${nameNode}</name-node>
            <configuration>
                <property>
                    <name>mapred.job.queue.name</name>
                    <value>${queueName}</value>
                </property>
            </configuration>
            <exec>bash</exec>
            <argument>-c</argument>
               <argument>rm -rf /tmp/bigSQLAdhocQuery_${wf:id()}</argument>
            <capture-output/>
        </shell>
        <ok to="fail"/>
        <error to="fail"/>
    </action>
   
    <action name="cleanup">
        <shell xmlns="uri:oozie:shell-action:0.2" >
            <job-tracker>${jobTracker}</job-tracker>
            <name-node>${nameNode}</name-node>
            <configuration>
                <property>
                    <name>mapred.job.queue.name</name>
                    <value>${queueName}</value>
                </property>
            </configuration>
            <exec>bash</exec>
            <argument>-c</argument>
               <argument>rm -rf /tmp/bigSQLAdhocQuery_${wf:id()}</argument>
            <capture-output/>
        </shell>
        <ok to="end"/>
        <error to="end"/>
    </action>
   
    <kill name="fail">
        <message>error message[${wf:errorMessage(wf:lastErrorNode())}]</message>
    </kill>
    <end name="end"/>
</workflow-app>


Step 3:  Update the /BigSQLAdhocQuery/BIApp/workflow/config-default.xml

<configuration>
<property>
        <name>connectionName</name>
        <value>null</value>
    </property>
    <property>
        <name>user</name>
        <value>null</value>
    </property>
    <property>
        <name>password</name>
        <value>null</value>
    </property>
    <property>
        <name>query</name>
        <value>null</value>
    </property>
</configuration>



Step 4:  Update the /BigSQLAdhocQuery/BIApp/application/application.xml

<application-template xmlns="http://biginsights.ibm.com/application" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <name>BigSQLAdhocQuery</name>
    <properties>
        <property defaultValue="bigsql" isInputPath="false" isOutputPath="false" isRequired="true" label="JSQSHConnectionName" name="connectionName" paramtype="STRING" uitype="textfield"/>
        <property isInputPath="false" isOutputPath="false" isRequired="true" label="User" name="user" paramtype="STRING" uitype="textfield"/>
        <property isInputPath="false" isOutputPath="false" isRequired="true" label="Password" name="password" paramtype="PASSWORD" uitype="textfield"/>
        <property isInputPath="false" isOutputPath="false" isRequired="true" label="Query" name="query" paramtype="TEXTAREA" uitype="textfield"/>
    </properties>
    <assets>
        <asset id="BigSQLAdhocQuery" type="WORKFLOW"/>
    </assets>
    <imagePath>defaultApp_L.png</imagePath>
</application-template>


Step 5: Publish the BigInsights Application.

 Refer http://big-analytics.blogspot.com.au/2015/07/building-web-crawler-in-ibm-biginsights.html for steps to publish the application.








Step 6: Deploy the App from Web Console & Run it from Console.

You can run the BigSQLv1 or BigSQL queries by creating a JSQSH Connection and passing it as input.

You can provide the Ad hoc BigSQL Queries and can schedule to run at fixed intervals.