在项目中,遇到一个场景是,需要从Hive数据仓库中拉取数据,进行过滤、裁剪或者聚合之后生成中间结果导入MySQL。

对于这样一个极其普通的离线计算场景,有多种技术选型可以实现。例如,sqoop,MR,HSQL。

我们这里使用的spark,优点来说是两个:一是灵活性高,二是代码简洁。

1)灵活性高

相比sqoop和HSQL,spark可以更灵活的控制过滤和裁剪逻辑,甚至你可以通过外部的配置或者参数,来动态的调整spark的计算行为,提供定制化。

2)代码简洁

相比MR来说,代码量上少了很多。也无需实现MySQL客户端。

我抽象了一下需求,做了如下一个demo。

涉及的数据源有两个:Hive&MySQL;计算引擎:spark&spark-sql。我们的demo中分为两个步骤:

1)从Hive中读取数据,交给spark计算,最终输出到MySQL;

2)从MySQL中读取数据,交给spark计算,最终再输出到MySQL另一张表。

1、 数据准备

创建了Hive外部分区表

关于分区和外部表这里不说了。

CREATE EXTERNAL TABLE `gulfstream_test.accounts`(
`id` string COMMENT '用户id',
`order_id` string COMMENT '订单id',
`status` bigint COMMENT '用户状态',
`count` decimal(,) COMMENT '订单数')
COMMENT '用户信息'
PARTITIONED BY (
`year` string,
`month` string,
`day` string)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\t'
STORED AS INPUTFORMAT
'org.autonavi.udf.CustomInputFormat'
OUTPUTFORMAT
'org.autonavi.udf.CustomHiveOutputFormat'
LOCATION
'hdfs://mycluster-tj/***/acounts'
TBLPROPERTIES (
'LEVEL'='',
'TTL'='',
'last_modified_by'='yangfan',
'last_modified_time'='2017-10-23',
'transient_lastDdlTime'='')

建立分区,并指定分区路径

这里分区使用的年月日三级分区。通过下面的命令将year=2017/month=10/day=23这个Hive分区的数据指向了location=hdfs://mycluster-tj/***/acounts/2017/10/23

hive> alter table gulfstream_test.accounts add partition(year='', month='', day='') location 'hdfs://mycluster-tj/***/acounts/2017/10/23';

查询一下分区是否建立成功

可以看到分区已经有了。

show partitions gulfstream_test.accounts;
OK
partition
year=/month=/day=

上传本地测试数据到hdfs

hadoop fs -put a.txt  hdfs://mycluster-tj/***/acounts/2017/10/23

看一下数据,取了前10行,原谅我数据比较假。

[data_monitor@bigdata-arch-client10 target]$ hadoop fs -cat hdfs://mycluster-tj/***/acounts/2017/10/23/a | head -10

在Hive中,也查一下前10条,是一样的。只是多了分区字段。

hive (default)> select * from gulfstream_test.accounts where year= and month= and day= limit ;
OK
accounts.id accounts.order_id accounts.status accounts.count accounts.year accounts.month accounts.day Time taken: 1.38 seconds, Fetched: row(s)

至此,测试数据准备好了。一共1000000条,1百万。

2、代码

1)POM依赖

可以通过pom依赖来看一下笔者使用的组件版本。

这里就不赘述了。

<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-core_2.10</artifactId>
<version>1.6.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-hive_2.10</artifactId>
<version>1.6.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-sql_2.10</artifactId>
<version>1.6.0</version>
<scope>provided</scope>
</dependency>

打包方式

<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<!--这里要替换成jar包main方法所在类 -->
<mainClass>com.kangaroo.studio.algorithms.filter.LoadDB</mainClass> </manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id> <!-- this is used for inheritance merges -->
<phase>package</phase> <!-- 指定在打包节点执行jar包合并操作 -->
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>

2)java spark代码

先贴上代码,再说明

package com.kangaroo.studio.algorithms.filter;

import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.sql.DataFrame;
import org.apache.spark.sql.SQLContext;
import org.apache.spark.sql.SaveMode;
import org.apache.spark.sql.hive.HiveContext; import java.io.Serializable;
import java.util.Properties; public class LoadDB implements Serializable { private SparkConf sparkConf;
private JavaSparkContext javaSparkContext;
private HiveContext hiveContext;
private SQLContext sqlContext; /*
* 初始化Load
* 创建sparkContext, sqlContext, hiveContext
* */
public LoadDB() {
initSparckContext();
initSQLContext();
initHiveContext();
} /*
* 创建sparkContext
* */
private void initSparckContext() {
String warehouseLocation = System.getProperty("user.dir");
sparkConf = new SparkConf()
.setAppName("from-to-mysql")
.set("spark.sql.warehouse.dir", warehouseLocation)
.setMaster("yarn-client");
javaSparkContext = new JavaSparkContext(sparkConf);
} /*
* 创建hiveContext
* 用于读取Hive中的数据
* */
private void initHiveContext() {
hiveContext = new HiveContext(javaSparkContext);
} /*
* 创建sqlContext
* 用于读写MySQL中的数据
* */
private void initSQLContext() {
sqlContext = new SQLContext(javaSparkContext);
} /*
* 使用spark-sql从hive中读取数据, 然后写入mysql对应表.
* */
public void hive2db() {
String url = "jdbc:mysql://10.93.84.53:3306/big_data?characterEncoding=UTF-8";
String table = "accounts";
Properties props = new Properties();
props.put("user", "root");
props.put("password", "1234");
String query = "select * from gulfstream_test.accounts where year=2017 and month=10 and day=23";
DataFrame rows = hiveContext.sql(query).select("id", "order_id", "status", "count");;
rows.write().mode(SaveMode.Append).jdbc(url, table, props);
} /*
* 使用spark-sql从db中读取数据, 处理后再回写到db
* */
public void db2db() {
String url = "jdbc:mysql://10.93.84.53:3306/big_data?characterEncoding=UTF-8";
String fromTable = "accounts";
String toTable = "accountsPart";
Properties props = new Properties();
props.put("user", "root");
props.put("password", "1234");
DataFrame rows = sqlContext.read().jdbc(url, fromTable, props).where("count < 1000");
rows.write().mode(SaveMode.Append).jdbc(url, toTable, props);
} public static void main(String[] args) {
LoadDB loadDB = new LoadDB();
System.out.println(" ---------------------- start hive2db ------------------------");
loadDB.hive2db();
System.out.println(" ---------------------- finish hive2db ------------------------");
System.out.println(" ---------------------- start db2db ------------------------");
loadDB.db2db();
System.out.println(" ---------------------- finish db2db ------------------------");
}
}

说明:

  • hive2db

核心动作是使用hiveContext.sql(query)执行了hiveSQL,过滤出Hive表中year=2017/month=10/day=23分钟的数据,返回一个DataFrame对象。

DataFrame是spark-sql数据处理的核心。对DataFrame的操作推荐这样一篇博客。你可以去使用这些方法,实现复杂的逻辑。

对DataFrame对象,我们使用了select裁剪了其中4列数据(id, order_id, status, count)出来,不过不裁剪的话,会有7列(加上分区的year,month,day)。

然后将数据以SaveMode.Append的方式,写入了mysql中的accounts表。

SaveMode.Append方式,数据会追加,而不会覆盖。如果想覆盖,还有一个常用的SaveMode.Overwrite。推荐这样一篇博客

最终accounts中的数据有1000000条,百万。

  • db2db

db2db从刚刚生成的MySQL表accounts中读取出数据,也是返回了一个dataframe对象,通过执行where过滤除了其中id<1000的数据,这里正好是1000条。

然后写入了accountsPart。最终accountsPart数据应该有1000条。

3)编译和执行

编译完成后,生成jar包from-to-mysql-1.0-SNAPSHOT-jar-with-dependencies.jar

使用默认参数提交到yarn队列。

spark-submit --queue=root.zhiliangbu_prod_datamonitor from-to-mysql-1.0-SNAPSHOT-jar-with-dependencies.jar 

片刻之后,观察输出。已经全部finish了。

4)查看一下结果

我们到mysql中瞅一瞅。

accounts表

有没有注意到,其实不用建立mysql表!这个过程会自动给你创建,相当于if not exists。

细心的你可能已经注意到了,hive里的string类型,到了MySQL中变成了Text。有个兄弟说,如果你手动创建了表,并且字段设置为String会报错,我没有试,只是记录了一下。

CREATE TABLE `accounts` (
`id` text,
`order_id` text,
`status` bigint(20) DEFAULT NULL,
`count` decimal(16,9) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8

简单看一下里面有多少数据。1百万

MariaDB [big_data]> select count() from accounts ;
+----------+
| count() |
+----------+
| |
+----------+
row in set (0.32 sec)

acountsPart表

 CREATE TABLE `accountsPart` (
`id` text,
`order_id` text,
`status` bigint() DEFAULT NULL,
`count` decimal(,) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8

查看有多少数据,1000条,果然是没有问题的

MariaDB [big_data]> select count() from accountsPart;
+----------+
| count() |
+----------+
| |
+----------+
row in set (0.00 sec)

到此为止。

使用spark与MySQL进行数据交互的方法的更多相关文章

  1. SpringMVC4+thymeleaf3的一个简单实例(篇五:页面和MySql的数据交互-展示以及存储)

    这一篇将介绍怎样把页面数据保存的MySQL数据库,并将数据库内容展示到页面上.首先做一个基础工作,添加以下jar到lib:1: mysql-connector-Java-5.1.40-bin.jar ...

  2. python与mysql的数据交互

    一 Python 中操作 MySQL 步骤 1.1 安装pymysql命令 sudo pip3 install pymysql 安装软件:sudo apt-get install 软件名称 安装模块: ...

  3. mysql导入数据大小设置方法

    MySQL导入数据库文件最大限制2048KB和phpmyadmin导入数据最大限制2048KB的解决方法 解决办法: 1.打开php.ini.找到 upload_max_filesize . memo ...

  4. 使用Apache Spark 对 mysql 调优 查询速度提升10倍以上

    在这篇文章中我们将讨论如何利用 Apache Spark 来提升 MySQL 的查询性能. 介绍 在我的前一篇文章Apache Spark with MySQL 中介绍了如何利用 Apache Spa ...

  5. 通过mapreduce把mysql的数据读取到hdfs

    前面讲过了怎么通过mapreduce把mysql的一张表的数据放到另外一张表中,这次讲的是把mysql的数据读取到hdfs里面去 具体怎么搭建环境我这里就不多说了.参考 通过mapreduce把mys ...

  6. js前台与后台数据交互-前台调后台

    转自:http://blog.csdn.net/wang379275614/article/details/17033981   网站是围绕数据库来编程的,以数据库中的数据为中心,通过后台来操作这些数 ...

  7. 大数据项目实践:基于hadoop+spark+mongodb+mysql+c#开发医院临床知识库系统

    一.前言 从20世纪90年代数字化医院概念提出到至今的20多年时间,数字化医院(Digital Hospital)在国内各大医院飞速的普及推广发展,并取得骄人成绩.不但有数字化医院管理信息系统(HIS ...

  8. 基于Spark Streaming + Canal + Kafka对Mysql增量数据实时进行监测分析

    Spark Streaming可以用于实时流项目的开发,实时流项目的数据源除了可以来源于日志.文件.网络端口等,常常也有这种需求,那就是实时分析处理MySQL中的增量数据.面对这种需求当然我们可以通过 ...

  9. Spark:读取mysql数据作为DataFrame

    在日常工作中,有时候需要读取mysql的数据作为DataFrame数据源进行后期的Spark处理,Spark自带了一些方法供我们使用,读取mysql我们可以直接使用表的结构信息,而不需要自己再去定义每 ...

随机推荐

  1. Sublime使用Ctrl+`作为快捷键弹出Console没有反映的解决办法

    很多Sublime新人都遇到了这个问题,到网上搜,信息很片面,而且不少都是旧版本的.于是有了这篇文章.       默认Sublime使用Ctrl+`作为快捷键弹出Console,但不同的系统抑或安装 ...

  2. 201521123022 《Java程序设计》 第十三周学习总结

    1. 本周学习总结 2. 书面作业 Q1. 网络基础 Q1.1 比较ping www.baidu.com与ping cec.jmu.edu.cn,分析返回结果有何不同?为什么会有这样的不同? 前者IP ...

  3. Java课程设计 201521123078

    计时器 掌握java图形界面操作以及多线程技术. 1.Mythread1 写一个类Mythread1实现Runnable,当需要开一个线程时就是用这个类.其中的run()通过标记flag和循环实现时间 ...

  4. 201521123026《JAVA程序设计》第11周学习总结

    1. 本章学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多线程相关内容. 1.多线程同步:限制某个资源在同一时刻只能被一个线程访问.. 2.同步代码块:`synchronized(lock ...

  5. 201521123089 《Java程序设计》第13周学习总结

    1. 本周学习总结 以你喜欢的方式(思维导图.OneNote或其他)归纳总结多网络相关内容. 1.协议:网络中为了进行数据交换而建立的原则,标准或约定. 2.域名:Internet上某一台计算机的名称 ...

  6. 关于SVM数学细节逻辑的个人理解(三) :SMO算法理解

    第三部分:SMO算法的个人理解 接下来的这部分我觉得是最难理解的?而且计算也是最难得,就是SMO算法. SMO算法就是帮助我们求解: s.t.   这个优化问题的. 虽然这个优化问题只剩下了α这一个变 ...

  7. Vagrant下共享目录下静态文件(js/jpg/png等)修改完运行报错

    利用Vagrant部署开发环境,使用目录共享模式,在本地磁盘进行开发,通过虚拟机环境运行开发的页面. 接下来打开页面,看上去一切正常,接下来将发生一个神奇的事情,你修改一个css文件,在刷新浏览器,发 ...

  8. RSA原理、ssl认证、Tomcat中配置数字证书以及网络传输数据中的密码学知识

      情形一:接口的加.解密与加.验签 rsa不是只有加密解密,除此外还有加签和验签.之前一直误以为加密就是加签,解密就是验签.这是错误的! 正确的理解是: 数据传输的机密性:公钥加密私钥解密是密送,保 ...

  9. 关于极光推送Jpush的demo

    关于极光推送Jpush 推送是手机app必不可少的一样功能,这次由于公司项目需要研究了一下.由于推送一般写于服务端,所以对于不会Android的javaweb程序员要写出一个完整的demo是一件很头痛 ...

  10. web自动化1-selenium简介及环境搭建

    selenium 开源软件 支持多浏览器Firefox.Chrome.IE 跨平台Windows.Mac.Linux 多语言 java python Ruby php js 对web支持好,多种API ...