首先介绍一下我做实验的前提,我的数据都是存在Hbase中的,现在我的需求是要对Hbase中的数据进行大数据分析。
这里有一个前提条件,我的Hbase里的数据都是String类型,这个时候就存在一个Hbase排序的问题。因为hbase是根据ascii码进行字典排序,那么比如说:速度这种数字类型的字段,我保存成String以后,速度20,实际上比速度3小。不理解的可以自己去百度Hbase的数据排序规则。由于这个原因,如果我想查询速度<20的全部数据有一些困难,而且只用Hbase的scan进行查询效率也很慢。因此需要用到其他的大数据技术来满足我的需求。
以下我做的实验有很多,目的是找到一个快速的大数据分析方案,目前的阶段,我只需要生成报表,而不进行数据导出。
当然最终的方案是使用spark进行大数据分析,毕竟这是目前的主流技术。
首先介绍下我的实验环境,我这里是用3台机器搭建的最小集群,实习的生产环境至少比我的测试环境快10倍以上,当然现阶段不可能在生产环境上测试效率。我这里用的是linux centos6.5虚拟机,16G内存,8核CPU。
集群版本:我这里用的是HDP的Ambari集成的环境,说下我用到的技术的版本,因为版本不同,代码写法和注意事项也不一样,跟我环境不一样的只能进行参考。
HDFS 2.7.1.2.4
MapReduce2 2.7.1.2.4
YARN 2.7.1.2.4
Hive 1.2.1.2.4
HBase 1.1.2.2.4
Spark 1.6.0.2.4
这里首先我初始化了1000万条数据,作为数据集。
实验一: Hive与HBase结合
Hive可以解决HBase排序问题。因为有必须使用HBase这个前提,所以我创建的是 EXTERNAL 表,即Hive的外部表。具体创建Hive表语句参考我的另外一个帖子,地址如下:
https://blog.csdn.net/lwb314/article/details/80346993
我这里做的实验是查询SOC字段<20;
首先是hive,代码如下
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Statement;
public class HiveTest2 {
/*
* 之前网上有个错误的例子,加载路径是org.apache.hadoop.hive.jdbc.HiveDriver,多了一个hadoop,应该是比较老的版本的
* 我用的hive版本是1.2.1
*/
private static String driverName = "org.apache.hive.jdbc.HiveDriver";
public static void main(String[] args) {
try {
Class.forName(driverName);
Connection con = null;
con = DriverManager.getConnection("jdbc:hive2://10.10.171.169:10000", "hive", "hive");// 之前是jdbc:hive:可能也是老版本的写法
Statement stmt = con.createStatement();
ResultSet res = null;
// String sql =
// "select * from lwb_test1 where vin = 'LBVHY1101JMK00005' and soc<10 limit 10";
String sql = " select count(1) from lwb_test1 where soc<20";
System.out.println("");
System.out.println("Running: " + sql);
long startTime = System.currentTimeMillis();
res = stmt.executeQuery(sql);
// ResultSetMetaData rsm = res.getMetaData(); // 获取列名
// for (int i = 0; i < rsm.getColumnCount(); i++) {
// System.out.print(rsm.getColumnName(i + 1).split("\\.")[1] + "\t");//输出列名
// }
System.out.println();
long k = 0;
while (res.next()) {
k++;
//System.out.println(res.getString(1));
// System.out.println(res.getString(1) + "\t" + res.getString(2) + "\t" + res.getInt(3) + "\t" + res.getInt(4) + "\t"
// +res.getString(5) + "\t" + res.getString(6) );
}
long endTime = System.currentTimeMillis();
System.out.println("用时:" + (endTime - startTime));
System.out.println("总共条数:" + k);
stmt.close();
con.close();
} catch (Exception e) {
e.printStackTrace();
System.out.println("error");
}
}
}
结果:
Running: select count(1) from lwb_test1 where soc<20
记录条数:2001000
用时:50430
这里是从hive的1000万数据条数据里查询出来200万条的数量,条件查询,用时50秒。这是count
我把语句修改成如下,查询全部字段进行遍历
select * from lwb_test1 where soc<23然后屏蔽上循环里的打印语句,打印会降低执行效率
程序执行结果如下:
Running: select * from lwb_test1 where soc<22
用时:160525
总共条数:2201156
以下是我的HBase查询代码
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.NavigableMap;
import java.util.Map.Entry;
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.TableName;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;
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.client.Table;
import org.apache.hadoop.hbase.filter.Filter;
import org.apache.hadoop.hbase.filter.SingleColumnValueFilter;
import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
import org.apache.hadoop.hbase.util.Bytes;
public class SocScan {
public static Configuration configuration;
public static String zkHost = "devhadoop3,devhadoop2,devhadoop1";
public static String zkPort = "2181";
public static String zkParent = "/hbase-unsecure";
private static Connection connection;
static {
configuration = HBaseConfiguration.create();
configuration.set("hbase.zookeeper.quorum", zkHost);
configuration.set("hbase.zookeeper.property.clientPort", zkPort);
configuration.set("zookeeper.znode.parent", zkParent);
try {
connection = ConnectionFactory.createConnection(configuration);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
try {
Table table = connection.getTable(TableName.valueOf("lwb_test1"));
Scan scan = new Scan();
// scan.setStartRow(start.getBytes());
// scan.setStopRow(stop.getBytes());
// scan.setReversed(true);//
// 倒序,倒序时候的开始结束rowkey也得反过来,例如不设置之前start是1,stop是3,那么设置之后start是3,stop是1
Filter filter = new SingleColumnValueFilter("data".getBytes(), "soc".getBytes(), CompareOp.LESS, "29".getBytes());
scan.setFilter(filter);
scan.setCaching(1000);
scan.setCacheBlocks(false);
long startTime = System.currentTimeMillis();
ResultScanner scanner = table.getScanner(scan);
byte[] vin = "vin".getBytes();
byte[] soc = "soc".getBytes();
long k=0;
for (Result result : scanner) {
// NavigableMap<byte[], byte[]> map = result.getFamilyMap("data".getBytes());
// System.out.println(new String(map.get(vin)) + "," + new String(map.get(soc)));
k++;
}
long endTime = System.currentTimeMillis();
System.out.println("用时:"+(endTime-startTime));
System.out.println("总共条数:"+k);
scanner.close();
table.close();
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Hbase查询结果:
用时:83657
总共条数:2200369
实验一结论:
简单条件查询,基数相同,查询结果集相同的条件下,Hive用时基本是Hbase的一倍。但是Hive查询结果是正确的。
实验二:使用hive内部表进行查询
首先创建一张Hive自己的表,就是创建hbase关联表的第一行代码。创建后表里是没有数据的,那么这里复制数据的语句如下:
insert into lwb_test3 select * from lwb_test1;
这是直接从之前的lwb_test1表里查出全部数据,存入lwb_test3;
之后还是运行hive代码,只是把表名换一下。可以看到,时间基本上还要比HbaseScan快一点,多次测试,基本和HbaseScan时间一样。
Running: select * from lwb_test3 where soc<22
用时:79297
总共条数:2201156
实验二结论:
hive使用内部表的查时间是外部表的一半,和HbaseScan的效率基本一样,而且结果正确。