Thursday, 13 June 2013

Cassandra-sstableloader

Steps to import column family from one cassandra cluster to another using sstableloader
a) Static Column Family Import
 
       1. Export existing column family into a csv file from source cluster. Login to cqlsh and run following command to export columnfamily into csv
        copy columnfamily_name into ‘/home/user/cf.csv’
            Also, you can export some specific columnns to csv as follows:
                         copy columnfamily_name(column1,column2) into ‘/home/user/cf.csv’
 
       2. Generate sstables from csv file as follows:
 
             i) Creating sstable Writer
 
                                      SSTableSimpleUnsortedWriter columnfamilyWriter = new SSTableSimpleUnsortedWriter(
                                      directory, new RandomPartitioner(), keySpace, columnFamily,
                                      AsciiType.instance, null, 64);
 
                   • The directory is the directory where to put the sstables ,this directory is object of File class in java                 • SSTableSimpleUnsortedWriter buffers whatever input it gets in memory and “flush” everything in one sstable once the buffer size is reached
 
 
           ii) Parsing each CSV line as per column types
 
                          boolean parse(String line) {                           String[] columns = line.split(",");                           try {                           key= columns[0].trim();
                          id = Integer.parseInt(columns[1].trim());                          name= columns[2].trim();                          salary = Long.valueOf(columns[3].trim());

                       
                                                 return true;                         } catch (Exception e) {                         return false;

                       }
 
 
                     •  For example, column type of salary is “Long “ , so parsed it with Long value. Similarly  , column type of id is int so parsed it with Integer value
 
              iii) Generating sstables and closing writer
                               
                                      while ((line = reader.readLine()) != null) {
                                         if (entry.parse(line)) {
                                            columnfamilyWriter.addColumn(bytes("nasport"), bytes(entry.nasport),tmestamp);
                                            columnfamilyWriter.addColumn(bytes("acctstarttime"),bytes(entry.acctstarttime), timestamp);
                                           columnfamilyWriter.addColumn(bytes("bin"), bytes(entry.bin), timestamp);
                                           columnfamilyWriter.addColumn(bytes("bout"), bytes(entry.bout),timestamp);               
                                           columnfamilyWriter.addColumn(bytes("src"), bytes(entry.src), timestamp);                                            }
       
                                                    }
                                      columnfamilyWriter.close();
 

       3. Use sstableloader to upload the sstables into the column family of the target cluster
                   $CASSANDRA_HOME/bin/sstableloader –d $target_cassandra_ip /path/to/sstables                    Note : sstables have to be in a directory whose name is the name of the column family of the sstables which should be the sub-directory of a directory whose name is the name of the keyspace of the column family                    For example, /home/user/keyspace_name/column_family_name
 
 
 b) Dynamic Column Family Import
  Now, in case your table is Dynamic , then its csv would be difficult to parse.Also, no need to worry about indexes here. So those can be imported without using sstableloader as follows:

       1. Copy the sstables from Cassandra data directory from source to target cluster            For example,  cassandra's data directory is /var/lib/cassandra and column family is testtable in testkeyspace. Then copy all the sstable from /var/lib/cassandra/testkeyspace/testtable to targetcluster        2. Use sstableloader to upload the sstables into the column family of the target cluster                  $CASSANDRA_HOME/bin/sstableloader –d $target_cassandra_ip /path/to/sstables 
 
          Note : sstables have to be in a directory whose name is the name of the column family of the sstables which should be the sub-directory of a directory whose name is the name of the keyspace of the column family                    For example, /home/user/keyspace_name/column_family_name

Wednesday, 29 May 2013

Quick fix:/nagios/cgi-bin/statusmap.cgi was not found on this server(nagios on ubuntu)


If you get "/nagios/cgi-bin/statusmap.cgi was not found on this server " error when you click on "Map" option on Nagios web-ui, the reason could be that you are missing following libraries:


libgd2-xpm libgd2-xpm-dev


Following are the steps to fox the issue:


1) Install missing libraries:

 sudo apt-get install libgd2-xpm libgd2-xpm-dev

2) Go to Nagios Folder and re-configure it as follows:
      

     cd /usr/nagios-3.2.3/
   ./configure -with-gd-lib=/usr/local/lib/   

3) make cgis

4) sudo make install cgis


5) sudo /etc/init.d/nagios reload



It will fix the issue


Thursday, 23 May 2013

Cassandra-Map Reduce Over Cassandra

Following is the Map Reduce program that will read a column from Cassandra table and the column values to HDFS .

I have only written a Mapper class , because Reducer is not required .

Here is the Driver Class:
public class CassandraDriver {
    private static final String CASSANDRA_HOST = "192.168.213.1";
    private static final String CASSANDRA_PORT = "9160";
    private static final String KEYSPACE = "mykeyspace";
    private static final String COLUMN_FAMILY = "testhadoop1";
    private static final String CONF_COLUMN_NAME1 = "value1";
    private static final String CONF_COLUMN_NAME2 = "value2";

    public static void main(String[] args) throws IOException,
            InterruptedException, ClassNotFoundException {

        Configuration conf = new Configuration();
        Job job = new Job(conf, "Cassandra");
        job.setJarByClass(CassandraDriver.class);
        job.setMapperClass(CassandraMapper.class);

        job.setOutputKeyClass(NullWritable.class);
        job.setOutputValueClass(Text.class);
        job.setInputFormatClass(ColumnFamilyInputFormat.class);

        FileOutputFormat.setOutputPath(job, new Path(
                args[0]));
        ConfigHelper.setRangeBatchSize(job.getConfiguration(), 99);
        ConfigHelper.setInputRpcPort(job.getConfiguration(), CASSANDRA_PORT);
        ConfigHelper.setInputInitialAddress(job.getConfiguration(),
                CASSANDRA_HOST);
        ConfigHelper.setInputPartitioner(job.getConfiguration(),
                "RandomPartitioner");
        ConfigHelper.setInputColumnFamily(job.getConfiguration(), KEYSPACE,
                COLUMN_FAMILY);
        SlicePredicate predicate = new SlicePredicate().setColumn_names(Arrays
                .asList(ByteBufferUtil.bytes(CONF_COLUMN_NAME1),
                        ByteBufferUtil.bytes(CONF_COLUMN_NAME2)));
        ConfigHelper.setInputSlicePredicate(job.getConfiguration(), predicate);

        job.waitForCompletion(true);
    }
}


Here is the Cassandra Mapper:




public class CassandraMapper extends
        Mapper<ByteBuffer, SortedMap<ByteBuffer, IColumn>, NullWritable, Text> {
    private NullWritable mapkey = NullWritable.get();
    private Text word = new Text();

    public void map(ByteBuffer key, SortedMap<ByteBuffer, IColumn> columns,
            Context context) throws IOException, InterruptedException {
        for (IColumn column : columns.values()) {
        
          
               String  value = ByteBufferUtil.string(column.value());
           

            StringTokenizer itr = new StringTokenizer(value);
            while (itr.hasMoreTokens()) {
                word.set(itr.nextToken());
                context.write(mapkey, word);
            }
        }
    }

}

Tuesday, 7 May 2013

Hive: Accessing Hive Array: Custom UDF


Following is an example Hive Table:

hive> select * from test_jsontable;
OK
id    name    contact    depts    sal
1    emp1    9999999999    ["IT","Electronics"]    10000
2    emp2    9999999929    ["IT","Mechanical"]    10000
3    emp4    9999999989    ["IT","Electronics"]    10000
4    emp4    9999999979    ["IT","Electronics"]    10000
5    emp5    9999999969    ["IT","Mechanical"]    10000
6    emp6    9999999949    ["IT","Mechanical","Production"]    10000
Time taken: 0.086 seconds


If you want to get all records where array "depts" contains  "Electronics" , it can be done as follows:

hive> select * from test_jsontable where depts[0]="Electronics" or depts[1]="Electronics" or depts[2]="Electronics";

However, what if your array contains 100 elements or more , you have to hard code every element of array.So better way to use a custom UDF as follows:

package com.impetus.hive;
import java.util.ArrayList;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.exec.UDF;
@Description(name = "arraycontains", value = "arraycontains(ArrayList list,String value) - returns true if list contains value ", extended = "Example:\n"
        + " > SELECT * FROM src where arraycontains(arrayname,stringvalue;\n")
public class ArrayContains extends UDF {
    public boolean evaluate(ArrayList list, String value) {
        if (list == null || list.size() < 1) {
            return false;
        }
        if (list.contains(value)) {
            return true;
        } else {
            return false;
        }
    }
}

Create jar file of the project and add it in hive as follows:

hive>add jar /pathto/jar;

Then you create your custom function as follows:

hive>create temporary function arraycontains as 'com.test.hive.ArrayContains';

Now , your UDF is available to use

hive> select * from test_jsontable where arraycontains(depts,"Production");
id    name    contact    depts    sal
6    emp6    9999999949    ["IT","Mechanical","Production"]    10000
Time taken: 11.807 seconds

Hive:Loading Json Array in Hive Table

To load JSON Data in Hive , you would need to use JsonSerde .
Download JsonSerde source code from following link and build it using Maven. Advantage of using this JsonSerde is that you can also handle Hive Array and Maps which will not be handled if you use default JSonSerde.

Once you have build it ,add this jar to Hive

hive>add jar /home/impadmin/hive/hive-0.8.1/jsonserde/Hive-JSON-Serde-1/target/json-serde-1.1-jar-with-dependencies.jar;

Now, for example you have following Json file on HDFS or your local system consists of Json Array

$ cat file1.json
 { "id": "1",  "name": "emp1",  "contact":"9999999999",  "depts":["IT","Electronics"], "sal":"10000" }
 { "id": "2",  "name": "emp2",  "contact":"9999999929",  "depts":["IT","Mechanical"], "sal":"10000" }
 { "id": "3",  "name": "emp4",  "contact":"9999999989",  "depts":["IT","Electronics"], "sal":"10000" }
 { "id": "4",  "name": "emp4",  "contact":"9999999979",  "depts":["IT","Electronics"], "sal":"10000" }
 { "id": "5",  "name": "emp5",  "contact":"9999999969",  "depts":["IT","Mechanical"], "sal":"10000" }



Now create a Hive Table using JsonSerde as follows  :

hive> create table test_jsontable (id string, name string,contact string,depts array<string>,sal string) ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe';
OK
Time taken: 0.417 seconds

 Now, load the JSON Data into the table as follows:

hive> load data local inpath '/path/to/file.json' into table test_jsontable;                                                                
Copying data from file:'/path/to/file.json'
Copying file: file:'/path/to/file.json'
Loading data to table default.test_jsontable
OK
Time taken: 0.18 seconds

hive> select * from test_jsontable;                                                     
OK
id    name    contact    depts    sal
1    emp1    9999999999    ["IT","Electronics"]    10000
2    emp2    9999999929    ["IT","Mechanical"]    10000
3    emp4    9999999989    ["IT","Electronics"]    10000
4    emp4    9999999979    ["IT","Electronics"]    10000
5    emp5    9999999969    ["IT","Mechanical"]    10000
Time taken: 0.089 seconds


 
If the file resides on HDFS , you can load the data as follows:

hive> load data  inpath '/path/to/file.json' into table test_jsontable;

Also, you can create external table as follows:

hive>create external table test_jsontable (id string, name string,contact string,depts array<string>,sal string)
ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe' location '/path/to/dir/of/jsonfile';

Hive:Loading Json Data in Hive Table


To load JSON Data in Hive , you would need to use JsonSerde .
Download JsonSerde source code from following link and build it using Maven. Advantage of using this JsonSerde is that you can also handle Hive Array and Maps which will not be handled if you use default JSonSerde.
https://github.com/foursquare/Hive-JSON-Serde-1

Once you have build it ,add this jar to Hive

hive>add jar /home/impadmin/hive/hive-0.8.1/jsonserde/Hive-JSON-Serde-1/target/json-serde-1.1-jar-with-dependencies.jar;

Now, for example you have following Json file on HDFS or your local system

$ cat file.json
 { "id": "1",  "name": "emp1",  "contact":"9999999999",  "dept":"IT", "sal":"10000" }
 { "id": "2",  "name": "emp2",  "contact":"9999999929",  "dept":"IT", "sal":"10000" }
 { "id": "3",  "name": "emp4",  "contact":"9999999989",  "dept":"IT", "sal":"10000" }
 { "id": "4",  "name": "emp4",  "contact":"9999999979",  "dept":"IT", "sal":"10000" }

Now create a Hive Table using JsonSerde as follows  :

hive> create table test_jsontable (id string, name string,contact string,dept string,sal string) ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe';
OK
Time taken: 0.057 seconds

Now, load the JSON Data into the table as follows:

hive> load data local inpath '/patht/to/file.json' into table test_jsontable;                                                                
Copying data from file:'/patht/to/file.json'
Copying file: file:'/patht/to/file.json'
Loading data to table default.test_jsontable
OK
Time taken: 0.18 seconds

hive> select * from test_jsontable;                                                                                                                    
OK
id    name    contact    dept    sal
1    emp1    9999999999    IT    10000
2    emp2    9999999929    IT    10000
3    emp4    9999999989    IT    10000
4    emp4    9999999979    IT    10000
Time taken: 0.081 seconds

If the file resides on HDFS , you can load the data as follows:

hive> load data  inpath '/patht/to/file.json' into table test_jsontable;

Also, you can create external table as follows:

hive>create external table test_jsontable (id string, name string,contact string,dept String,sal string)
ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe' location '/path/to/dir/of/jsonfile';


Cassandra: Alternative of IN clause in CQL


In CQL, IN clause only works if a column is indexed.
For example, here is a  table in cassandra with "rowkey" as primary key

 
cqlsh:mykeyspace> select * from hbtable;
 rowkey | cf      | quantifier | value
--------+---------+------------+-------
  row-2 | colfam1 |      quan2 |  val2
  row-8 | colfam1 |      quan4 |  val8
  row-6 | colfam1 |      quan2 |  val6
  row-3 | colfam1 |      quan3 |  val3
  row-7 | colfam1 |      quan3 |  val7
  row-1 | colfam1 |      quan1 |  val1
  row-5 | colfam1 |      quan4 |  val5
  row-4 | colfam1 |      quan1 |  val4

 
Now, if you execute IN clause on "rowkey", it will work

cqlsh:mykeyspace> select * from hbtable where rowkey in ('row-2','row-3');
 rowkey | cf      | quantifier | value
--------+---------+------------+-------
  row-2 | colfam1 |      quan2 |  val2
  row-3 | colfam1 |      quan3 |  val3

 
However, if you try it on some other column where index is not created it will not work
 

cqlsh:mykeyspace> select * from hbtable where quantifier in ('quan1');
Bad Request: No indexed columns present in by-columns clause with Equal operator

Since you cannot create index on every table, so I have written a Java code that will help to run IN clause on Cassandra table. This code runs in sets of rows, one set contains 50000 so that process does not go out of memory


import me.prettyprint.cassandra.serializers.StringSerializer;
import me.prettyprint.hector.api.Cluster;
import me.prettyprint.hector.api.Keyspace;
import me.prettyprint.hector.api.Serializer;
import me.prettyprint.hector.api.beans.OrderedRows;
import me.prettyprint.hector.api.beans.Row;
import me.prettyprint.hector.api.factory.HFactory;
import me.prettyprint.hector.api.query.QueryResult;
import me.prettyprint.hector.api.query.RangeSlicesQuery;
/*
 *
 * arguments list should be cluster_name, keyspace_name, table_name,column_name,value1,value2  and so on
 *
 *
 *
 * */
public class InFunction {
    public static void main(String[] args) {
        if (args.length < 5) {
            System.out.println("usage <args>");
            System.out
                    .println("args list should be cluster_name,keyspace_name,table_name,column_name,value1,value2,...");
            System.exit(1);
        }
        Cluster cluster = HFactory.getOrCreateCluster(args[0],"192.168.213.11:9160,192.168.213.24:9160,");
        Keyspace keyspace = HFactory.createKeyspace(args[1], cluster);
        Serializer<String> se = StringSerializer.get();
        String r1 = "";
        int rowcount = 50000;// default row count
        RangeSlicesQuery<String, String, String> rangeSlicesQuery = HFactory.createRangeSlicesQuery(keyspace, se, se, se);
        while (rowcount == 50000) {
            rangeSlicesQuery.setColumnFamily(args[2]);
            rangeSlicesQuery.setKeys(r1, "");
            rangeSlicesQuery.setRange("", "", false, 2000000000); // Maximum
                                                                    // number of
                                                                    // columns
                                                                    // that
                                                                    // Cassandra
                                                                    // permits
                                                                    // in a line
            rangeSlicesQuery.setRowCount(50000);
            QueryResult<OrderedRows<String, String, String>> result = rangeSlicesQuery
                    .execute();
            OrderedRows<String, String, String> orderedRows = result.get();
            for (Row<String, String, String> r : orderedRows) {
                if (r.getColumnSlice().getColumnByName(args[3]) != null) {
                    String value = (r.getColumnSlice().getColumnByName(args[3])
                            .getValue());
                    for (int i = 4; i < args.length; i++) {
                        if (value.compareTo(args[i]) == 0) {
                            System.out.println(" " + r);
                        }
                    }
                }
            }
            rowcount = orderedRows.getCount();
            r1 = orderedRows.peekLast().getKey();
        }
    }
}