HBase之四--(1):Java操作Hbase進行建表、刪表以及對資料進行增刪改查,條件查詢...

weixin_34377065發表於2015-05-19

1、搭建環境

  新建JAVA專案,新增的包有:

   有關Hadoop的hadoop-core-0.20.204.0.jar

   有關Hbase的hbase-0.90.4.jar、hbase-0.90.4-tests.jar以及Hbase資源包中lib目錄下的所有jar包

 

2、主要程式

package com.sf.study.hbase;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.KeyValue;
import org.apache.hadoop.hbase.MasterNotRunningException;
import org.apache.hadoop.hbase.ZooKeeperConnectionException;
import org.apache.hadoop.hbase.client.Delete;
import org.apache.hadoop.hbase.client.Get;
import org.apache.hadoop.hbase.client.HBaseAdmin;
import org.apache.hadoop.hbase.client.HTable;
import org.apache.hadoop.hbase.client.HTablePool;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.ResultScanner;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
import org.apache.hadoop.hbase.filter.Filter;
import org.apache.hadoop.hbase.filter.FilterList;
import org.apache.hadoop.hbase.filter.SingleColumnValueFilter;
import org.apache.hadoop.hbase.util.Bytes;

public class HbaseOperateTest {

    public static Configuration configuration;
    static {
        configuration = HBaseConfiguration.create();
        configuration.set("hbase.zookeeper.property.clientPort", "2181");
        configuration.set("hbase.zookeeper.quorum", "10.202.34.200");
        configuration.set("hbase.master", "http://10.202.34.200:16010");
    }

    public static void main(String[] args) {
         createTable("sfabc");
         insertData("sfabc");
         QueryAll("sfabc");
         QueryByCondition1("sfabc");
         QueryByCondition2("sfabc");
         QueryByCondition3("sfabc");
         deleteRow("sfabc","abcdef");
        deleteByCondition("sfabc", "abcdef");
    }

    /**
     * 建立表
     * 
     * @param tableName
     */
    public static void createTable(String tableName) {
        System.out.println("start create table ......");
        try {
            HBaseAdmin hBaseAdmin = new HBaseAdmin(configuration);
            if (hBaseAdmin.tableExists(tableName)) {// 如果存在要建立的表,那麼先刪除,再建立
                hBaseAdmin.disableTable(tableName);
                hBaseAdmin.deleteTable(tableName);
                System.out.println(tableName + " is exist,detele....");
            }
            HTableDescriptor tableDescriptor = new HTableDescriptor(tableName);
            tableDescriptor.addFamily(new HColumnDescriptor("column1"));
            tableDescriptor.addFamily(new HColumnDescriptor("column2"));
            tableDescriptor.addFamily(new HColumnDescriptor("column3"));
            hBaseAdmin.createTable(tableDescriptor);
        } catch (MasterNotRunningException e) {
            e.printStackTrace();
        } catch (ZooKeeperConnectionException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("end create table ......");
    }

    /**
     * 插入資料
     * 
     * @param tableName
     */
    public static void insertData(String tableName) {
        System.out.println("start insert data ......");
        HTablePool pool = new HTablePool(configuration, 1000);
        HTable table = (HTable) pool.getTable(tableName);
        Put put = new Put("112233bbbcccc".getBytes());// 一個PUT代表一行資料,再NEW一個PUT表示第二行資料,每行一個唯一的ROWKEY,此處rowkey為put構造方法中傳入的值
        put.add("column1".getBytes(), null, "aaa".getBytes());// 本行資料的第一列
        put.add("column2".getBytes(), null, "bbb".getBytes());// 本行資料的第三列
        put.add("column3".getBytes(), null, "ccc".getBytes());// 本行資料的第三列
        try {
            table.put(put);
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("end insert data ......");
    }

    /**
     * 刪除一張表
     * 
     * @param tableName
     */
    public static void dropTable(String tableName) {
        try {
            HBaseAdmin admin = new HBaseAdmin(configuration);
            admin.disableTable(tableName);
            admin.deleteTable(tableName);
        } catch (MasterNotRunningException e) {
            e.printStackTrace();
        } catch (ZooKeeperConnectionException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /**
     * 根據 rowkey刪除一條記錄
     * 
     * @param tablename
     * @param rowkey
     */
    public static void deleteRow(String tablename, String rowkey) {
        try {
            HTable table = new HTable(configuration, tablename);
            List list = new ArrayList();
            Delete d1 = new Delete(rowkey.getBytes());
            list.add(d1);

            table.delete(list);
            System.out.println("刪除行成功!");

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /**
     * 組合條件刪除
     * 
     * @param tablename
     * @param rowkey
     */
    public static void deleteByCondition(String tablename, String rowkey) {
        // 目前還沒有發現有效的API能夠實現 根據非rowkey的條件刪除 這個功能能,還有清空表全部資料的API操作

    }

    /**
     * 查詢所有資料
     * 
     * @param tableName
     */
    public static void QueryAll(String tableName) {
        HTablePool pool = new HTablePool(configuration, 1000);
        HTable table = (HTable) pool.getTable(tableName);
        try {
            ResultScanner rs = table.getScanner(new Scan());
            for (Result r : rs) {
                System.out.println("獲得到rowkey:" + new String(r.getRow()));
                for (KeyValue keyValue : r.raw()) {
                    System.out.println(
                            "列:" + new String(keyValue.getFamily()) + "====值:" + new String(keyValue.getValue()));
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 單條件查詢,根據rowkey查詢唯一一條記錄
     * 
     * @param tableName
     */
    public static void QueryByCondition1(String tableName) {

        HTablePool pool = new HTablePool(configuration, 1000);
        HTable table = (HTable) pool.getTable(tableName);
        try {
            Get scan = new Get("abcdef".getBytes());// 根據rowkey查詢
            Result r = table.get(scan);
            System.out.println("獲得到rowkey:" + new String(r.getRow()));
            for (KeyValue keyValue : r.raw()) {
                System.out
                        .println("列:" + new String(keyValue.getFamily()) + "====值:" + new String(keyValue.getValue()));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 單條件按查詢,查詢多條記錄
     * 
     * @param tableName
     */
    public static void QueryByCondition2(String tableName) {

        try {
            HTablePool pool = new HTablePool(configuration, 1000);
            HTable table = (HTable) pool.getTable(tableName);
            Filter filter = new SingleColumnValueFilter(Bytes.toBytes("column1"), null, CompareOp.EQUAL,
                    Bytes.toBytes("aaa")); // 當列column1的值為aaa時進行查詢
            Scan s = new Scan();
            s.setFilter(filter);
            ResultScanner rs = table.getScanner(s);
            for (Result r : rs) {
                System.out.println("獲得到rowkey:" + new String(r.getRow()));
                for (KeyValue keyValue : r.raw()) {
                    System.out.println(
                            "列:" + new String(keyValue.getFamily()) + "====值:" + new String(keyValue.getValue()));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * 組合條件查詢
     * 
     * @param tableName
     */
    public static void QueryByCondition3(String tableName) {

        try {
            HTablePool pool = new HTablePool(configuration, 1000);
            HTable table = (HTable) pool.getTable(tableName);

            List<Filter> filters = new ArrayList<Filter>();

            Filter filter1 = new SingleColumnValueFilter(Bytes.toBytes("column1"), null, CompareOp.EQUAL,
                    Bytes.toBytes("aaa"));
            filters.add(filter1);

            Filter filter2 = new SingleColumnValueFilter(Bytes.toBytes("column2"), null, CompareOp.EQUAL,
                    Bytes.toBytes("bbb"));
            filters.add(filter2);

            Filter filter3 = new SingleColumnValueFilter(Bytes.toBytes("column3"), null, CompareOp.EQUAL,
                    Bytes.toBytes("ccc"));
            filters.add(filter3);

            FilterList filterList1 = new FilterList(filters);

            Scan scan = new Scan();
            scan.setFilter(filterList1);
            ResultScanner rs = table.getScanner(scan);
            for (Result r : rs) {
                System.out.println("獲得到rowkey:" + new String(r.getRow()));
                for (KeyValue keyValue : r.raw()) {
                    System.out.println(
                            "列:" + new String(keyValue.getFamily()) + "====值:" + new String(keyValue.getValue()));
                }
            }
            rs.close();

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

}

 注意:可能大家沒看到更新資料的操作,其實更新的操作跟新增完全一致,只不過是新增呢rowkey不存在,更新呢rowkey已經存在,並且timstamp相同的情況下,還有就是目前好像還沒辦法實現hbase資料的分頁查詢,不知道有沒有人知道怎麼做

 

HBase效能優化建議:

 針對前面的程式碼,有很多不足之處,在此我就不修改上面的程式碼了,只是提出建議的地方,大家自己加上

   1)配置

  當你呼叫create方法時將會載入兩個配置檔案:hbase-default.xml and hbase-site.xml,利用的是當前的java類路徑, 程式碼中configuration設定的這些配置將會覆蓋hbase-default.xml和hbase-site.xml中相同的配置,如果兩個配置 檔案都存在並且都設定好了相應參上面的屬性下面的屬性即可

 

 2)關於建表

public void createTable(HTableDescriptor desc)

HTableDescriptor 代表的是表的schema, 提供的方法中比較有用的有

setMaxFileSize,指定最大的region size

setMemStoreFlushSize 指定memstore flush到HDFS上的檔案大小

增加family通過 addFamily方法

public void addFamily(final HColumnDescriptor family)

 

HColumnDescriptor代表的是column的schema,提供的方法比較常用的有

setTimeToLive:指定最大的TTL,單位是ms,過期資料會被自動刪除。

setInMemory:指定是否放在記憶體中,對小表有用,可用於提高效率。預設關閉

setBloomFilter:指定是否使用BloomFilter,可提高隨機查詢效率。預設關閉

setCompressionType:設定資料壓縮型別。預設無壓縮。

setMaxVersions:指定資料最大儲存的版本個數。預設為3。

 

注意的是,一般我們不去setInMemory為true,預設是關閉的

 

3)關於入庫

   官方建議

 table.setAutoFlush(false); //資料入庫之前先設定此項為false

 table.setflushCommits();//入庫完成後,手動刷入資料

注意:

  在入庫過程中,put.setWriteToWAL(true/flase);

  關於這一項如果不希望大量資料在儲存過程中丟失,建議設定為true,如果僅是在測試演練階段,為了節省入庫時間建議設定為false

 

4)關於獲取表例項

HTablePool pool = new HTablePool(configuration, Integer.MAX_VALUE);

HTable table = (HTable) pool.getTable(tableName);

建議用表連線池的方式獲取表,具體池有什麼作用,我想用過資料庫連線池的同學都知道,我就不再重複

不建議使用new HTable(configuration,tableName);的方式獲取表

 

5)關於查詢

 建議每個查詢語句都放入try catch語句塊,並且finally中要進行關閉ResultScanner例項以及將不使用的表重新放入到HTablePool中的操作,具體做法如下

Java程式碼  
public static void QueryAll2(String tableName) throws IOException {  
        HTablePool pool = new HTablePool(configuration, Integer.MAX_VALUE);  
        HTable table = null;  
        ResultScanner rs = null;  
        try {  
            Scan scan = new Scan();  
            table = (HTable) pool.getTable(tableName);  
            rs = table.getScanner(scan);  
            for (Result r : rs) {  
                System.out.println("獲得到rowkey:" + new String(r.getRow()));  
                for (KeyValue keyValue : r.raw()) {  
                    System.out.println("列:" + new String(keyValue.getFamily())  
                            + "====值:" + new String(keyValue.getValue()));  
                }  
            }  
        } catch (IOException e) {  
            e.printStackTrace();  
        }finally{  
            rs.close();// 最後還得關閉  
            pool.putTable(table); //實際應用過程中,pool獲取例項的方式應該抽取為單例模式的,不應在每個方法都重新獲取一次(單例明白?就是抽取到專門獲取pool的邏輯類中,具體邏輯為如果pool存在著直接使用,如果不存在則new)  
        }  
    } 

 所以,以上程式碼有缺陷的地方,感興趣的同學可以針對優化建議作出相應修改

相關文章