Spark 2.4写入库表到spark-warehouse后无法识别非default数据库问题
问题根因
该问题本质是Spark SQL的元数据与数据存储分离导致的:
spark.sql.warehouse.dir仅配置了Parquet等数据文件的存储路径,你创建的数据库、表结构定义等元数据,在未显式启用Hive支持的场景下,默认存储在嵌入式Derby数据库中- 嵌入式Derby的默认存储路径是你启动Spark程序的当前工作目录下的
metastore_db文件夹,如果你第二次启动程序的工作目录和第一次不一致,或者用repl启动的目录和程序运行目录不一致,Spark就会创建全新的空元数据库,自然只能识别到默认的default库,找不到之前创建的其他库 - 另外默认的嵌入式Derby仅支持单会话访问,同一时间只能有一个Spark进程读取写入元数据,也会导致多进程访问时找不到元数据的问题
解决方案
方案1:本地测试场景(不启用Hive)
固定Derby元数据库的存储路径,确保每次启动Spark都读取同一个元数据文件,修改SparkSession初始化代码即可:
val spark: SparkSession = SparkSession.builder() .master("local[*]") .config("spark.debug.maxToStringFields", 100) .config("spark.sql.warehouse.dir", "D:/Demo/spark-warehouse/") // 固定元数据存储路径,和数据目录放在同层级即可 .config("javax.jdo.option.ConnectionURL", "jdbc:derby:;databaseName=D:/Demo/metastore_db;create=true") .getOrCreate()
配置后不管你在哪个目录启动程序,都会读取同一个元数据库,就能找到之前创建的所有库表了。
方案2:生产/多进程访问场景
启用Spark的Hive支持,使用独立的Hive Metastore存储元数据,支持多进程并发访问,修改SparkSession初始化代码:
val spark: SparkSession = SparkSession.builder() .master("local[*]") .config("spark.debug.maxToStringFields", 100) .config("spark.sql.warehouse.dir", "D:/Demo/spark-warehouse/") // 启用Hive支持,会自动读取classpath下的hive-site.xml配置的元数据库地址 .enableHiveSupport() .getOrCreate()
你只需要把Hive服务端的hive-site.xml放到项目的resources目录下即可,不需要修改现有业务代码。
临时补救方案
如果之前的元数据库已经损坏丢失,但数据文件还在spark-warehouse目录下,可以用以下SQL重新挂载库表,不需要重新导入数据:
-- 重新创建数据库 CREATE DATABASE IF NOT EXISTS <database_name> LOCATION 'D:/Demo/spark-warehouse/<database_name>.db'; -- 挂载已有的分区表 MSCK REPAIR TABLE <database_name>.<table_name>;
内容的提问来源于stack exchange,提问作者Ria Arora
相关产品推荐
相关产品推荐

