我在Scala 2.11中使用spark hive 2.3.0,并建立了一个单元测试框架。spark-hive带有TestHiveContext
和TestHiveSparkSession
,它们可以方便地从单元测试中调用hive,而无需运行Hadoop、spark或集群,这对于自动化测试非常有用。
Hive需要一个数据库作为其元存储,当以这种方式运行时,它使用Derby作为使用javax. jdo.select.ConnectionURL
配置的嵌入式数据库,默认情况下为jdbc:derby:;数据库名称=
另一种选择是在内存中运行 Derby,这通常就像将此 URL 更改为 jdbc:derby:memory:databaseName;create=true
一样简单。Hoewever,这在Hive中是不可能的,因为配置是在内部HiveUtils
类中进行的,不能被覆盖。我尝试在我的Spark Session Builder中更改它,但是当我创建TestHiveContext
时,我的更改被HiveUtils
吹走了。
就我而言,内存数据库更可取,因为我们的开发人员在Windows上运行(绝对不是我/我们的选择),并且当创建这些文件时,通常会出现诸如权限或文件名中无效字符之类的问题(因为Hadoop从未真正打算在Windows上运行),并且这些文件经常被抛在后面,因为它们无法清理(由于这些问题)。我们希望测试是完全独立的,这样它们就可以在没有副作用的情况下运行和完成,因此它们可以在多个环境(开发人员、CI、Jenkins、AWS 等)中运行。
有趣的是,我在TestHive.scala
中看到了这一点:
{ // set the metastore temporary configuration
val metastoreTempConf = HiveUtils.newTemporaryConfiguration(useInMemoryDerby = false) ++ Map(
因此,有一个使用内存数据库的标志,但这是不可配置的,并且没有代码路径将其设置为< code>true。
有没有办法配置或编写它,以便TestHive
的Derby可以在内存中?尝试通过 hive-site 或 hdfs-site 设置javax.jdo.option.ConnectionURL
的值.xml.xml不起作用,我认为这是因为TestHive,TestHiveContext和
TestHiveSparkSession
的初始化方式,它们有自己的代码路径与非测试路径分开。它们提供的功能对于测试框架非常有用,但显然没有提供覆盖此值和其他一些设置的方法。
到目前为止,我能看到的最好的选择是重写或编写我自己的<code>TestHiveContext</code>类,该类从该类中借用了一系列功能并重写了我所需要的部分,但对于我认为可以通过简单的配置更改来完成的任务来说,这是一个相对较大的任务。
我终于想出了如何做到这一点,并希望分享答案,以防其他人试图做同样的事情。
我的测试类使用 SharedSparkContext
特征,它通过 var sc
提供 SparkContext
引用。
初始化SparkContext后(我使用了< code>scalatest测试框架中可用的< code>beforeAll挂钩),我创建了一个< code>TestHiveContext,如下所示:
hc = new TestHiveContext(sc, false)
然后立即,我可以设置javax. jdo.select.ConnectionURL
以及其他一些Hadoop和Hive配置,如下所示:
sc.hadoopConfiguration.set("javax.jdo.option.ConnectionURL",
"jdbc:derby:memory:db;create=true")
Hive使用此配置参数,但显然必须添加到Hadoop配置中,该配置用于构建Hive测试上下文。
诀窍是时机,这必须在Hadoop和Hive初始化自己之后完成(使用配置文件等),并且scalate框架也被初始化,最后在TestHive框架初始化之后,但在你运行任何测试之前。尝试在这些其他初始化之前设置此参数意味着您的设置将在测试运行之前被覆盖。