【Spark】MySQL使用Spark SQL实现多表关联

此处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。

原创文章 88 获赞 41 访问量 16万+

猜你喜欢

转载自blog.csdn.net/Damionew/article/details/103918688