此处Spark使用Java代码实现:
一、需求:
有user表(id,name)和role表(id,role),想要通过SparkSQL将两个表通过id关联后展示所有字段
SELECT t1.id,t1.name,t2.role FROM USER t1 LEFT JOIN role t2 ON t1.id = t2.id
二、实现:
首先Maven需要引入spark依赖和mysql驱动
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-core_2.12</artifactId>
<version>2.4.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.spark/spark-sql -->
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-sql_2.12</artifactId>
<version>2.4.4</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
然后可以参考Spark Doc:https://spark.apache.org/docs/latest/sql-getting-started.html
但是显然这是建立在已经有Hive的环境下,而我们使用的是本地Mysql关系型数据库,所以还需要建立数据连接。
import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.SparkSession;
public class JavaSparkSqlDemo {
public static void main(String[] args){
SparkSession sparkSession = SparkSession
.builder()
.appName("JavaSparkSqlDemo") //Sets a name for the application
.master("local") //Sets the Spark master URL to connect to
.getOrCreate(); //获取或者新建一个 sparkSession
//设置sparkSession数据连接
Dataset userDataset = sparkSession.read()
.format("jdbc")
.option("url","jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8")
.option("dbtable","user")
.option("driver","com.mysql.cj.jdbc.Driver")
.option("user","root")
.option("password","root")
.load();
Dataset roleDataset = sparkSession.read()
.format("jdbc")
.option("url","jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8")
.option("dbtable","role")
.option("driver","com.mysql.cj.jdbc.Driver")
.option("user","root")
.option("password","root")
.load();
//注册临时表后才能进行select等操作,必需,否则not found in database 'default'
userDataset.registerTempTable("user");
roleDataset.registerTempTable("role");
//SQL查询操作
//注意:1.所有用到的表需要在option和registerTempTable注册
Dataset<Row> sqlDF = sparkSession.sql("SELECT t1.id,t1.name,t2.role FROM USER t1 LEFT JOIN role t2 ON t1.id = t2.id ");
sqlDF.show();
}
}
三、遇到的问题
看到两个DataSet你可能会好奇为什么非要根据dbtable的user和role配置两次呢
以上是最终版本,在此之前我也进行测试过,代码如下:
Dataset dataset = sparkSession.read()
.format("jdbc")
.option("url","jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8")
.option("dbtable","user")
.option("dbtable","role")
.option("driver","com.mysql.cj.jdbc.Driver")
.option("user","root")
.option("password","root")
.load();
//注册临时表后才能进行select等操作,必需,否则not found in database 'default'
dataset.registerTempTable("user");
dataset.registerTempTable("role");
//SQL查询操作
//注意:1.所有用到的表需要在option和registerTempTable注册
Dataset<Row> sqlDF = sparkSession.sql("SELECT t1.id,t1.name,t2.role FROM USER t1 LEFT JOIN role t2 ON t1.id = t2.id ");
sqlDF.show();
则会报出
cannot resolve '`t1.name`' given input columns: [t1.id, t1.role, t2.id, t2.role],仅取了第二个table的字段
因此可见,DataSet对于其同一个option:dbtale的设置,后一个会覆盖前一个,因为name是属于user(id,name)的
还试过另一种方式
.option("dbtable","user,role")
使用这种写法两个表不能有相同名称的字段,但在我们使用join关联的时候,一般情况on的字段都是同名的,这就尴尬了呀,因此在没有找到更好的方式之前只能设置两个DataSet。