我正在尝试使用spark-jdbc在postgres db上读取表。为此,我想出了以下代码:
object PartitionRetrieval {
var conf = new SparkConf().setAppName("Spark-JDBC").set("spark.executor.heartbeatInterval","120s").set("spark.network.timeout","12000s").set("spark.default.parallelism", "20")
val log = LogManager.getLogger("Spark-JDBC Program")
Logger.getLogger("org").setLevel(Level.ERROR)
val conFile = "/home/myuser/ReconTest/inputdir/testconnection.properties"
val properties = new Properties()
properties.load(new FileInputStream(conFile))
val connectionUrl = properties.getProperty("gpDevUrl")
val devUserName = properties.getProperty("devUserName")
val devPassword = properties.getProperty("devPassword")
val driverClass = properties.getProperty("gpDriverClass")
val tableName = "base.ledgers"
try {
Class.forName(driverClass).newInstance()
} catch {
case cnf: ClassNotFoundException =>
log.error("Driver class: " + driverClass + " not found")
System.exit(1)
case e: Exception =>
log.error("Exception: " + e.printStackTrace())
System.exit(1)
}
def main(args: Array[String]): Unit = {
val spark = SparkSession.builder().config(conf).master("yarn").enableHiveSupport().getOrCreate()
import spark.implicits._
val gpTable = spark.read.format("jdbc").option("url", connectionUrl).option("dbtable",tableName).option("user",devUserName).option("password",devPassword).load()
val rc = gpTable.filter(gpTable("source_system_name")==="ORACLE" && gpTable("period_year")==="2017").count()
println("gpTable Count: " + rc)
}
}
现在,我正在获取行数,以查看连接是成功还是失败。这是一个很大的表,并且我无法理解该计数的运行速度,因为没有为应该进行数据分区的分区号和列名提供任何参数。
在很多地方,我看到jdbc对象是通过以下方式创建的:
val gpTable2 = spark.read.jdbc(connectionUrl, tableName, connectionProperties)
,然后我使用options
用另一种格式创建了它。
我无法理解如何在使用'options'形成jdbc连接时给numPartitions分区列名称,我希望在该分区列上进行数据分区:val gpTable = spark.read.format("jdbc").option("url", connectionUrl).option("dbtable",tableName).option("user",devUserName).option("password",devPassword).load()
有人能让我知道吗
如何添加参数:numPartitions, lowerBound, upperBound
到以这种方式编写的jdbc对象:
val gpTable = spark.read.format(“ jdbc”)。option(“ url”,connectionUrl).option(“ dbtable”,tableName).option(“ user”,devUserName).option(“ password”, devPassword).load()
如何仅添加columnname
和numPartition
,因为我想获取
年份中的所有行:2017年,我不需要范围
选择的行数(lowerBound,upperBound)
答案 0 :(得分:3)
选项numPartitions, lowerBound, upperBound and PartitionColumn
控制火花的并行读取。您需要PartitionColumn的整数列。如果表中没有合适的列,则可以使用ROW_NUMBER
作为分区列。
尝试一下
val rowCount = spark.read.format("jdbc").option("url", connectionUrl)
.option("dbtable","(select count(*) AS count * from tableName where source_system_name = "ORACLE" AND "period_year = "2017")")
.option("user",devUserName)
.option("password",devPassword)
.load()
.collect()
.map(row => row.getAs[Int]("count")).head
我们获得了所提供的谓词可以用作upperBount的返回行数。
val gpTable = spark.read.format("jdbc").option("url", connectionUrl)
.option("dbtable","(select ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS RNO, * from tableName source_system_name = "ORACLE" AND "period_year = "2017")")
.option("user",devUserName)
.option("password",devPassword)
.option("numPartitions", 10)
.option("partitionColumn", "RNO")
.option("lowerBound", 1)
.option("upperBound", rowCount)
.load()
numPartitions取决于与Postgres DB的并行连接数。您可以在从数据库中读取数据时根据所需的并行度进行调整。
答案 1 :(得分:1)
要像这样处理查询,依赖Spark聚合是没有意义的。
最好将作业委派给数据库:
val sourceSystemName = "ORACLE"
val gpTable = spark.read.format("jdbc").option("url", connectionUrl)
.option("dbtable",
s"(SELECT COUNT(*) FROM $tableName WHERE source_system_name = '$sourceSystemName') AS t")
.option("user",devUserName)
.option("password",devPassword).load()
无需其他配置,并且可以在数据存在的地方尽可能高效地对其进行处理。