Practical Guide to HBase Database Programming

This laboratory exercise focuses on practical HBase database operations, covering both command-line interfaces and Java programming implementations. You will learn how to perform essential database administration tasks, transform relational data structures for NoSQL storage, and develop Java applications that interact with HBase clusters.

Learning Objectives

Upon completing this laboratory, you will be able to:

  • Execute fundamental HBase Shell commands for table management and data manipulation
  • Convert relational database schemas into HBase-compatible table structures
  • Develop Java applications that create tables, add records, and query data
  • Implement row-level operations including data modification and deletion
  • Understand the core data models and components of HBase

Experimental Environment

The following software components are required for this laboratory:

  • CentOS 6.5 operating system
  • Java Development Kit version 1.7
  • VMware Workstation for virtualization
  • Hadoop pseudo-distributed mode installation
  • HBase version 0.98.12.1 compatible with Hadoop 2

Environment Configuration

HBase Installation Steps

Begin by transferring the HBase distribution archive to your target directory. The following commands demonstrate the complete installation process.

tar -zxvf hbase-0.98.12.1-hadoop2-bin.tar.gz -C /opt/labdata/

Configure system environment variables to enable HBase commands from any terminal session. Edit the profile configuration file and add the following entries:

export HBASE_HOME=/opt/labdata/hbase-0.98.12.1-hadoop2
export PATH=$PATH:$HBASE_HOME/bin

Apply the updated configuration using the source command to make changes effective immediately.

Core Configuration Files

Modify the hbase-env.sh file located in the HBase conf directory. This file controls the execution environment for HBase services:

export JAVA_HOME=/usr/java/jdk1.7.0_67
export HBASE_MANAGES_ZK=true

The hbase-site.xml configuration file defines critical HBase operational parameters. Configure the following properties based on your cluster setup:

<property>
    <name>hbase.rootdir</name>
    <value>hdfs://labnode01:9000/hbase</value>
</property>

<property>
    <name>hbase.cluster.distributed</name>
    <value>true</value>
</property>

<property>
    <name>hbase.zookeeper.quorum</name>
    <value>labnode01</value>
</property>

<property>
    <name>hbase.master.info.port</name>
    <value>60010</value>
</property>

<property>
    <name>hbase.zookeeper.property.dataDir</name>
    <value>/var/labdata/zk</value>
</property>

Starting HBase Services

Initiate all HBase services using the provided startup script. The built-in ZooKeeper coordinator will start automatically:

start-hbase.sh

Verify successful startup by examining running Java processes:

jps

HBase Shell Command Operations

This section covers essential HBase Shell commands for database administration. The backspace key functions normally within the HBase Shell environment.

Listing All Tables

Retrieve comprehensive information about all tables within the current HBase namespace:

list

Managing Column Families

Add a new column family named info3 to an existing student table:

alter 'student', {NAME=>'info3'}

Truncating Table Data

Remove all records from the student table while preserving the table structure:

truncate 'student'

Counting Table Rows

Obtain the total number of rows stored in the student table:

count 'student'

Scanning Table Contents

Display all records stored within the student table:

scan 'student'

Schema Conversion from Relational to HBase

Traditional relational dataabse schemas require careful redesign for effective HBase storage. This section demonstrates converting three normalized tables into appropriate HBase structures.

Student Table

The following table represents student information in a relational format:

Student ID Name Gender Age
2015001 Zhangsan male 23
2015002 Mary female 22
2015003 Lisi male 24

Create the HBase table and populate it with data using the following commands:

create 'Student','StudentID','PersonName','Gender','Age'

put 'Student','stu001','StudentID','2015001'
put 'Student','stu001','PersonName','Zhangsan'
put 'Student','stu001','Gender','male'
put 'Student','stu001','Age','23'

put 'Student','stu002','StudentID','2015002'
put 'Student','stu002','PersonName','Mary'
put 'Student','stu002','Gender','female'
put 'Student','stu002','Age','22'

put 'Student','stu003','StudentID','2015003'
put 'Student','stu003','PersonName','Lisi'
put 'Student','stu003','Gender','male'
put 'Student','stu003','Age','24'

Course Table

The course information structure appears as follows:

Course Code Course Name Credits
123001 Mathematics 2.0
123002 Computer Science 5.0
123003 English 3.0

Create and populate the Course table accordingly:

create 'Course','CourseCode','CourseName','Credits'

put 'Course','crs001','CourseCode','123001'
put 'Course','crs001','CourseName','Mathematics'
put 'Course','crs001','Credits','2.0'

put 'Course','crs002','CourseCode','123002'
put 'Course','crs002','CourseName','Computer Science'
put 'Course','crs002','Credits','5.0'

put 'Course','crs003','CourseCode','123003'
put 'Course','crs003','CourseName','English'
put 'Course','crs003','Credits','3.0'

Student-Course Enrollment Table

The enrollment table captures course registration and grades:

Student ID Course Code Grade
2015001 123001 86
2015001 123003 69
2015002 123002 77
2015002 123003 99
2015003 123001 98
2015003 123002 95

Construct the enrollment table with the following operations:

create 'Enrollment','StudentNum','CourseNum','Grade'

put 'Enrollment','enr001','StudentNum','2015001'
put 'Enrollment','enr001','CourseNum','123001'
put 'Enrollment','enr001','Grade','86'

put 'Enrollment','enr002','StudentNum','2015001'
put 'Enrollment','enr002','CourseNum','123003'
put 'Enrollment','enr002','Grade','69'

put 'Enrollment','enr003','StudentNum','2015002'
put 'Enrollment','enr003','CourseNum','123002'
put 'Enrollment','enr003','Grade','77'

put 'Enrollment','enr004','StudentNum','2015002'
put 'Enrollment','enr004','CourseNum','123003'
put 'Enrollment','enr004','Grade','99'

put 'Enrollment','enr005','StudentNum','2015003'
put 'Enrollment','enr005','CourseNum','123001'
put 'Enrollment','enr005','Grade','98'

put 'Enrollment','enr006','StudentNum','2015003'
put 'Enrollment','enr006','CourseNum','123002'
put 'Enrollment','enr006','Grade','95'

Java Application Development

This section implements a Java application for HBase operations. Set up a new Java project and include the following dependencies:

  • All JAR files from the HBase lib directory (excluding Ruby-related libraries)
  • JUnit testing framework for unit testing capabilities

Project Configuration

Configure the build path to include external JAR archives from your HBase installation. Ensure the configuration files hbase-site.xml and regionservers are accessible to your application classpath.

Implementation Requirements

Develop the following core functionalities within your Java application:

Table Creation Method
The initializeTable method accepts a table name and array of column family names. If a table with the specified name already exists, the method removes the existing table before creating a new one with the provided configuration.

Record Insertion Method
The insertRecord method populates a specified table with data. It takes parameters for table name, row identifier, field names, and corresponding values. Field names use the columnFamily:columnQualifier format when data belongs to specific columns within a column family.

Column Scanning Method
The queryColumnData method retrieves values from a specific column. When provided with a column family name, it returns data from all column qualifiers within that family. When given a fully qualified column name, it returns only that specific column's data. The method returns null for rows lacking the specified column.

Data Modification Method
The updateCellValue method modifies existing cell values within a specified table, row, and column coordinate.

Row Deletion Method
The removeRowEntry method eliminates an entire row and all its associated column data from a specified table.

Complete Java Implementation

package com.hbase.lab;

import java.io.IOException;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.MasterNotRunningException;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.TableNotFoundException;
import org.apache.hadoop.hbase.ZooKeeperConnectionException;
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.Put;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.util.Bytes;


public class HBaseOperations {
    private static Configuration hadoopConfig;
    private static HBaseAdmin clusterAdmin;
    private static HTable dataTable;

    public static void main(String[] args) throws MasterNotRunningException, 
            ZooKeeperConnectionException, IOException {
        String targetTable = "StudentRegistry";
        String[] columnFamilies = {"PersonalInfo", "AcademicRecord"};
        
        setupConnection();
        initializeTable(targetTable, columnFamilies);
        
        String[] fields = {"PersonalInfo:FullName", "PersonalInfo:Age"};
        String[] values = {"AlexJohnson", "21"};
        insertRecord(targetTable, "student2024001", fields, values);
        
        queryColumnData(targetTable, "FullName");
    }

    private static void setupConnection() throws MasterNotRunningException, 
            ZooKeeperConnectionException, IOException {
        hadoopConfig = HBaseConfiguration.create();
        clusterAdmin = new HBaseAdmin(hadoopConfig);
    }

    private static void initializeTable(String tableName, String[] families) 
            throws IOException {
        if (clusterAdmin.tableExists(tableName)) {
            clusterAdmin.disableTable(tableName);
            clusterAdmin.deleteTable(tableName);
        }

        HTableDescriptor tableDescriptor = new HTableDescriptor(
                TableName.valueOf(tableName));
        
        for (String family : families) {
            HColumnDescriptor columnDef = new HColumnDescriptor(
                    family.getBytes());
            tableDescriptor.addFamily(columnDef);
        }
        
        clusterAdmin.createTable(tableDescriptor);
    }

    private static void insertRecord(String tableName, String rowKey, 
            String[] fields, String[] values) throws IOException {
        dataTable = new HTable(hadoopConfig, tableName.getBytes());
        Put rowOperation = new Put(rowKey.getBytes());
        
        for (int i = 0; i < fields.length; i++) {
            String[] columnParts = fields[i].split(":");
            String family = columnParts[0];
            String qualifier = columnParts.length > 1 ? columnParts[1] : "";
            String cellValue = i < values.length ? values[i] : "N/A";
            
            rowOperation.add(family.getBytes(), qualifier.getBytes(), 
                    cellValue.getBytes());
        }
        
        dataTable.put(rowOperation);
    }

    private static void queryColumnData(String tableName, String columnName) 
            throws TableNotFoundException, IOException {
        dataTable = new HTable(hadoopConfig, tableName.getBytes());
        String targetRow = "student2024001";
        
        Get rowQuery = new Get(Bytes.toBytes(targetRow));
        Result rowResult = dataTable.get(rowQuery);
        
        String[] columnParts = columnName.split(":");
        byte[] family = columnParts[0].getBytes();
        byte[] qualifier = columnParts.length > 1 ? columnParts[1].getBytes() : null;
        
        Cell cellData = rowResult.getColumnLatestCell(family, qualifier);
        if (cellData != null) {
            System.out.println("Retrieved Value: " + 
                    new String(CellUtil.cloneValue(cellData)));
        } else {
            System.out.println("Column data not found for specified row.");
        }
    }

    private static void updateCellValue(String tableName, String rowKey, 
            String column, String newValue) throws IOException {
        dataTable = new HTable(hadoopConfig, tableName.getBytes());
        
        String[] parts = column.split(":");
        Put updateOperation = new Put(rowKey.getBytes());
        updateOperation.add(parts[0].getBytes(), 
                parts.length > 1 ? parts[1].getBytes() : null, 
                newValue.getBytes());
        
        dataTable.put(updateOperation);
    }

    private static void removeRowEntry(String tableName, String rowKey) 
            throws IOException {
        dataTable = new HTable(hadoopConfig, tableName.getBytes());
        dataTable.delete(new org.apache.hadoop.hbase.client.Delete(
                rowKey.getBytes()));
    }
}

Review Questions

Question 1: HBase Data Types and Their Characteristics

HBase employs a flexible data model with several distinct components that together form the fundamental building blocks of data storage:

Row Key serves as the primary identifier for each record in an HBase table. Row keys are stored as byte arrays and function similarly to primary keys in traditional databases. They determine the physical ordering of data and enable efficient single-row retrieval operations.

Column Family represents a logical grouping of related columns within an HBase table. All column qualifiers belonging to the same family share storage characteristics and are stored together in the underlying file system. Strategic column family design significantly impacts storage efficiency and query performance.

Column Qualifier identifies specific data columns within a column family. While column families are defined during table creation, column qualifiers can be dynamically added at runtime. This flexibility allows applications to store varying attributes for different rows without schema modifications.

Cell represents the intersection of a row key, column family, and column qualifier. Each cell contains a specific value along with timestamp metadata for versioning support. Cells are the smallest addressable data units within the HBase architecture.

Practical Example: Consider a grade management system with a column family named AcademicPerformance containing qualifiers such as Mathematics, Physics, and Literature. Each cell stores a specific grade value for a particular student, addressed by the student's identifier as the row key.

Question 2: Processes Started by start-hbase.sh

When executing the HBase startup script, three critical processes initialize to form a functional cluster environment:

HMaster operates as the primary cluster coordinator, managing region server assignments, monitoring node health, and handling administrative operations including table creation and schema modifications. In distributed deployments, backup masters provide high availability.

HRegionServer processes handle actual data storage and retrieval operations. Each region server manages specific table regions, processing client requests and coordinating with the HMaster for load balancing and failover scenarios.

HQuorumPeer represents the embedded ZooKeeper instance that maintains cluster state information. This process coordinates leader election, tracks region server availability, and manages configuration synchronization across cluster nodes.

Question 3: Java Objects Created During HBase Programming

Several core Java objects are essential for HBase application development:

Configuration encapsulates connection parameters and client settings required to establish communication with HBase clusters. This object typically specifies ZooKeeper quorum locations and retry policies.

HBaseAdmin serves as the primary interface for administrative operations. Through this object, developers create tables, modify column family configurations, and manage cluster resources.

HTable provides the client-side representation of an HBase table. This object supports CRUD operations including put, get, scan, and delete operations against table data.

HColumnDescriptor defines properties for column families includign compression algorithms, time-to-live settings, and bloom filter configurations.

Put represents a mutation operation for inserting or updating cell values within a specific row. This object accumulates multiple column modifications before batch submission.

Get constructs a retrieval request specifying which row, columns, and timestamps to retrieve from the underlying table.

Result contains the data returned from a Get operation, providing access to individual cell values through the KeyValue structure.

Cell represents an individual key-value pair from the underlying storage, containing row key, column family, column qualifier, timestamp, and value components.

Tags: HBase java Hadoop NoSQL database

Posted on Sun, 30 Aug 2026 16:46:49 +0000 by Entanio