SparkSQL前身是Shark,Shark强烈依赖于Hive。Spark原来没有做SQL多维度数据查询工具,后来开发了Shark,Shark依赖于Hive的解释引擎,部分在Spark中运行,还有一部分在Hadoop中运行。所以讲SparkSQL必须讲Hive。
1)Hive是分布式数据仓库,同时又是查询引擎,所以SparkSQL取代的只是Hives的查询引擎,在企业实际生产环境下,Hive+SparkSQL是目前最为经典的数据分析组合。
2)Hive本身就是一个简单单机版本的软件,主要负责:
A) 把HQL翻译成Mapper(s)-Reducer-Mapper(s)的代码,并且可能产生很多MapReduce的JOB。
B)把生成的MapReduce代码及相关资源打包成jar并发布到Hadoop集群中运行(这一切都是自动的)
3)Hive本身的架构如下所示:
hive架构
可以通过CLI(命令终端)、JDBC/ODBC、Web GUI访问Hive。
JavaEE或.net程序可以通过Hive处理,再把处理的结果展示给用户。
也可以直接通过Web页面操作Hive。
※ Hive本身只是一个单机版本的的软件,怎么访问HDFS的呢?
=> 在Hive用Table的方式插入数据、检索数据等,这就需要知道数据放在HDFS的什么地方以及什么地方属于什么数据,Metastore就是保存这些元数据信息的。Hive通过访问元数据信息再去访问HDFS上的数据。
可以看出HDFS不是一个真实的文件系统,是虚拟的,是逻辑上的,HDFS只是一套软件而已,它是管理不同机器上的数据的,所以需要NameNode去管理元数据。DataNode去管理数据。
Hive通过Metastore和NameNode打交道。
Spark1.6.1中SparkSQL可以指定具体的Hive的版本。
1) 从apache官网下载hive-1.2.1,并解压到/home/richard目录。
http://mirrors.cnnic.cn/apache/hive/hive-1.2.1/
2) 配置.bashrc,追加以下内容,或者/etc/profile:
export HIVE_HOME=/home/richard/hive-1.2.1
export HIVE_CONF_DIR=/$HIVE_HOME/conf
export PATH=$PATH:$HIVE_HOME/bin
3)进入/home/richard/hive-1.2.1/conf目录,生成hive-env.sh:
cp hive-default.xml.template hive-site.xml
配置:
export HADOOP_HOME=/opt/hadoop-2.6.0
export HIVE_HOME=/opt/hive-1.2.1/
export HIVE_CONF_DIR=/opt/hive-1.2.1/conf
Hive默认情况下放元数据的数据库是Derby,遗憾的是Derby是单用户,所以在生产环境下一般会采用支持多用户的数据库来进行MetaStore,且进行Master-Slaves主从读写分离和备份(一般Master节点负责写数据,Slaves节点负责读数据)。最常用的是MySQL。
cp hive-env.sh.template hive-env.sh
再生成hive-site.xml,并配置如下:
javax.jdo.option.ConnectionURL
jdbc:mysql://master:3306/hive?createDatabaseIfNotExist=true
JDBC connect string for a JDBC metastore
javax.jdo.option.ConnectionDriverName
com.mysql.jdbc.Driver
Driver class name for a JDBC metastore
javax.jdo.option.ConnectionUserName
root
username to use against metastore database
javax.jdo.option.ConnectionPassword
778899..
password to use against metastore database
hive.metastore.warehouse.dir
/user/hive/warehouse
location of default database for the warehouse
Hive中的DataBase和表其实就是HDFS上的目录和简单的文本文件。简单的文本文件中有几列数据,每列数据的类型无法直接从文本文件中得知。但当数据放入Hive中,Hive就把元数据放入Mysql中了,这样就可以基于数据的表进行查询了。
4) MYSQL的安装和配置
root用户下执行yum -y install mysql-server即可自动安装
执行rpm -qa mysql-server可以查看是否安装成功及安装的mysql版本。
参考redhat4.4.7如何安装mysql(非yum 安装)
http://blog.csdn.net/choice_jj/article/details/8827649
http://jingyan.baidu.com/article/1974b289acebd0f4b0f77469.html
设置密码问题:
http://blog.csdn.net/rogerzhanglijie/article/details/9182125
hive打开错误参考:
主要是按照《DT-大数据 hive1.2.1用mysql作为元数据库搭建》文档
http://www.aboutyun.com/thread-11131-1-1.html
另外还需要下载驱动包(mysql-connector-java-5.1.35.tar.gz)将.jar文件放到这个目录下:
cd /usr/local/hive/apache-hive-1.2.1/lib/
Logging initialized using configuration in jar:file:/opt/hive-1.2.1/lib/hive-common-1.2.1.jar!/hive-log4j.properties
Exception in thread "main" java.lang.RuntimeException: java.lang.RuntimeException: Unable to instantiate org.apache.hadoop.hive.ql.metadata.SessionHiveMetaStoreClient
Caused by: java.lang.RuntimeException: Unable to instantiate org.apache.hadoop.hive.ql.metadata.SessionHiveMetaStoreClient
Caused by: java.lang.reflect.InvocationTargetException
Caused by: javax.jdo.JDOFatalDataStoreException: Unable to open a test connection to the given database. JDBC url = jdbc:mysql://master:3306/hive?createDatabaseIfNotExist=true, username = hive. Terminating connection pool (set lazyInit to true if you expect to start your database after
...
root@master:/opt# netstat -tnlp | grep 3306
tcp 0 0 127.0.0.1:3306 0.0.0.0:* LISTEN 5090/mysqld
//mysql的监听IP应该是0.0.0.0
//在vi /etc/mysql/my.cnf 中修改
killall mysqld 后守护进程还会启动mysql,等于重启
另外报错:
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.slf4j.impl.Log4jLoggerFactory]
[ERROR] Terminal initialization failed; falling back to unsupported
原因是hadoop目录下存在老版本jline:
/hadoop-2.5.2/share/hadoop/yarn/lib:
-rw-r--r-- 1 root root 87325 Mar 10 18:10 jline-0.9.94.jar
解决方法是:
将hive下的新版本jline的JAR包拷贝到hadoop下:
cp /hive/apache-hive-1.1.0-bin/lib/jline-2.12.jar ./
5) Hive的表有两种基本类型:一种是内部表(这种表数据属于Hive本身,即如果原来的数据在HDFS的其他地方,此时数据会通过HDFS移动到Hive所在目录,如果删除Hive中的该表的话数据和元数据均会被删除),一种是外部表(这种表数据不属于Hive数据仓库,元数据中会表达具体数据在哪里,使用时和内部表的使用一样,只是如果通过Hive去删除的话,删除的只是元数据,并没有删除数据本身)
6)Hive扩展(Hive的数据存储-转载)
Hive是基于Hadoop分布式文件系统的,它的数据存储在Hadoop分布式文件系统中。Hive本身是没有专门的数据存储格式,也没有为数据建立索引,只需要在创建表的时候告诉Hive数据中的列分隔符和行分隔符,Hive就可以解析数据。所以往Hive表里面导入数据只是简单的将数据移动到表所在的目录中(如果数据是在HDFS上;但如果数据是在本地文件系统中,那么是将数据复制到表所在的目录中)。
Hive中主要包含以下几种数据模型:Table(表),External Table(外部表),Partition(分区),Bucket(桶)(本博客会专门写几篇博文来介绍分区和桶)。
1、表:Hive中的表和关系型数据库中的表在概念上很类似,每个表在HDFS中都有相应的目录用来存储表的数据,这个目录可以通过${HIVE_HOME}/conf/hive-site.xml配置文件中的 hive.metastore.warehouse.dir属性来配置,这个属性默认的值是/user/hive/warehouse(这个目录在 HDFS上),我们可以根据实际的情况来修改这个配置。如果我有一个表wyp,那么在HDFS中会创建/user/hive/warehouse/wyp 目录(这里假定hive.metastore.warehouse.dir配置为/user/hive/warehouse);wyp表所有的数据都存放在这个目录中。这个例外是外部表。
2、外部表:外部表指向已经在HDFS中存在的数据,可以创建Partition。它和内部表在元数据的组织上是相同的,而实际数据的存储则有较大的差异。内部表的创建过程和数据加载过程这两个过程可以分别独立完成,也可以在同一个语句中完成,在加载数据的过程中,实际数据会被移动到数据仓库目录中;之后对数据对访问将会直接在数据仓库目录中完成。删除表时,表中的数据和元数据将会被同时删除。而外部表只有一个过程,加载数据和创建表同时完成(CREATE EXTERNAL TABLE ……LOCATION),实际数据是存储在LOCATION后面指定的 HDFS 路径中,并不会移动到数据仓库目录中。当删除一个External Table时,仅删除该链接。
3、分区:在Hive中,表的每一个分区对应表下的相应目录,所有分区的数据都是存储在对应的目录中。比如wyp 表有dt和city两个分区,则对应dt=20131218,city=BJ对应表的目录为/user/hive/warehouse /dt=20131218/city=BJ,所有属于这个分区的数据都存放在这个目录中。
4、桶:对指定的列计算其hash,根据hash值切分数据,目的是为了并行,每一个桶对应一个文件(注意和分区的区别)。比如将wyp表id列分散至16个桶中,首先对id列的值计算hash,对应hash值为0和16的数据存储的HDFS目录为:/user /hive/warehouse/wyp/part-00000;而hash值为2的数据存储的HDFS 目录为:/user/hive/warehouse/wyp/part-00002。如果想应用很多的Map任务这样是不错的选择。
Hive数据抽象结构图
参考:
http://lqding.blog.51cto.com/9123978/1751030
启动HDFS/Yarn。注意如果要使用Hive进行查询就需要启动Yarn。
启动Hive。
通过show databases;可以查看数据库。默认database只有default。
选取搜狗实验的三个数据源:http://download.labs.sogou.com/dl/q.html
hadoop dfs -mkdir /library/sogou
hadoop dfs -put ./SogouQ1.txt /library/sogou
hadoop dfs -put ./SogouQ2.txt /library/sogou
hadoop dfs -put ./SogouQ3.txt /library/sogou
create table SogouQ3(ID STRING, WEBSESSION STRING, WORD STRING, S_SEQ INT, C_SEQ INT, WEBSITE STRING) ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' LINES TERMINATED BY '\n'; //建表
LOAD DATA INPATH '/library/sogou/SogouQ3.txt' OVERWRITE INTO TABLE SogouQ3; //加载数据
查询搜索排名第一,点击排名为第一的结果:
select count(*) from sogouq1 where S_SEQ=1 and C_SEQ=1;
搜索日志中,关注排名前五的内容,并且给出分别为多少次:
select WORD, count(WORD) as COUNTWord from SogouQ1 group by WORD order by COUNTWord desc limit 5
mysql -u root -p
creeate database hive;
use hive;
create table person(name String,age int);
insert into person values(‘richard’,’34’);
select * from person;即可查询。
到此不需要启动spark,只需要启动HDFS。
hive.metastore.uris
thrift://master:9083
thrift URI for the remote metastore.Used by metastore client to connect to remote metastore.
因为用sparksql操作hive实际上是把hive 当做数据仓库。数据仓库肯定有元数据和数据本身。要访问真正的数据就要访问他的元数据。所以只需要配置hive.metastore.uris即可。(不需在每台机器上配置)
val hiveContext= new org.apache.spark.sql.hive.HiveContext(sc)
hiveContext.sql("use hive") //使用hive 数据库
hiveContext.sql("show tables").collect.foreach(println) // 查询数据库中的表
hiveContext.sql("select count(*) from sogouq1").collect.foreach(println)//(注意此时使用的是spark的引擎)
hiveContext.sql(“select count(*) from sogouq2 where website like '%baidu%'”).collect.foreach(println)
hiveContext.sql(“select count(*) from sogouq2 where s_seq=1 and c_seq=1 and website like '%baidu%'”).collect.foreach(println)
scala> sqlContext
res8: org.apache.spark.sql.SQLContext = org.apache.spark.sql.hive.HiveContext@35920655(可以创建很多hiveContext,hivecongtext连接的是数据仓库,程序本身(spark中的job),job在程序中并行运行,如果都hive的数据,如果用句柄,对句柄的占用比较麻烦,所有用多个实例。从查询的角度来说,有多个实例也很正常)
val df =sqlcontext.read.json(“library/examples/src/main/resources/people.json”) //读取json 数据
df.show()
df.printSchema
df.select(“name”).show()
df.select(df(“name”),df(“age”)+1).show()