我需要使用Spark SQL从DB2数据库读取数据(因为Sqoop不存在)
我知道这个函数会通过打开多个连接来读取parellel中的数据
jdbc(url: String, table: String, columnName: String, lowerBound: Long,upperBound: Long, numPartitions: Int, connectionProperties: Properties)
我的问题是我没有像这样增量的列。此外,我需要通过查询读取数据,因为我的表非常大。有没有人知道通过API读取数据的方法,或者我必须自己创建
答案 0 :(得分:4)
您不需要标识列并行读取,table
变量仅指定源。注册表后,您可以使用WHERE
子句使用Spark SQL查询限制从中读取的数据。如果这不是一个选项,您可以使用视图,或者如此post中所述,您也可以使用任意子查询作为表输入。
val dataframe = sqlContext.read.format("jdbc").option("url", "jdbc:db2://localhost/sparksql").option("driver", "com.mysql.jdbc.Driver").option("dbtable", "table").option("user", "root").option("password", "root").load()
dataframe.registerTempTable("table")
dataframe.sqlContext.sql("select * from table where dummy_flag=1").collect.foreach(println)
答案 1 :(得分:4)
Saurabh,为了使用标准的Spark JDBC数据源支持并行读取,您确实需要使用numPartitions选项。
但是你需要给Spark一些线索如何将读取SQL语句拆分成多个并行的语句。因此,您需要某种整数分区列,其中您具有明确的最大值和最小值。
如果您的DB2系统是MPP分区的,那么已存在隐式分区,您实际上可以利用这一事实并并行读取每个DB2数据库分区:
var df = spark.read.
format("jdbc").
option("url", "jdbc:db2://<DB2 server>:<DB2 port>/<dbname>").
option("user", "<username>").
option("password", "<password>").
option("dbtable", "<your table>").
option("partitionColumn", "DBPARTITIONNUM(<a column name>)").
option("lowerBound", "<lowest partition number>").
option("upperBound", "<largest partition number>").
option("numPartitions", "<number of partitions>").
load()
因此,您可以看到DBPARTITIONNUM()函数是此处的分区键。
如果您不了解DB2 MPP系统的分区,以下是使用SQL找到它的方法:
SELECT min(member_number), max(member_number), count(member_number)
FROM TABLE(SYSPROC.DB_MEMBERS())
如果您使用多个分区组并且不同的表可以分布在不同的分区集上,您可以使用此SQL来确定每个表的分区列表:
SELECT t2.DBPARTITIONNUM, t3.HOST_NAME
FROM SYSCAT.TABLESPACES as t1, SYSCAT.DBPARTITIONGROUPDEF as t2,
SYSCAT.TABLES t4, TABLE(SYSPROC.DB_MEMBERS()) as t3
WHERE t1.TBSPACEID = t4.TBSPACEID AND
t4.TABSCHEMA='<myschema>' AND
t4.TABNAME='<mytab>' AND
t1.DBPGNAME = t2.DBPGNAME AND
t2.DBPARTITIONNUM = t3.PARTITION_NUMBER;
答案 2 :(得分:0)
如果您没有某种标识列,最好的选择是使用所谓的“谓词”选项(
每个谓词都应该仅使用索引列构建,您应该尝试确保它们均匀分布。 Spark将为您提供的每个谓词创建一个任务,并根据可用的核心并行执行任意数量的任务。
我见过的典型方法是使用哈希函数将唯一字符串列转换为int,希望您的数据库支持(类似https://www.ibm.com/support/knowledgecenter/en/SSEPGG_9.7.0/com.ibm.db2.luw.sql.rtn.doc/doc/r0055167.html)。然后你可以把它分成像
这样的桶mod(abs(yourhashfunction(yourstringid)),numOfBuckets)+ 1 = bucketNumber
如果你有复合唯一性,你可以在散列之前将它们连接起来。
您还可以通过附加匹配其他索引或分区的条件来改进谓词(即AND partitiondate = somemeaningfuldate)。
最后应该注意的是,这通常不如标识列那么好,因为它可能需要对目标索引进行完整或更广泛的扫描 - 但它仍然远远超过其他任何操作。