Spark从SAS IOM读取JDBC

时间:2018-08-23 09:24:38

标签: apache-spark sas

我正在尝试使用Spark JDBC从SAS IOM中读取。问题是SAS JDBC驱动程序有点奇怪,因此我需要创建自己的方言:

object SasDialect extends JdbcDialect {
  override def canHandle(url: String): Boolean = url.startsWith("jdbc:sasiom")
  override def quoteIdentifier(colName: String): String = "\"" + colName + "\"n"
}

但是,这还不够。 SAS区分了列标签(=可读名称)和列名称(=在SQL查询中使用的名称),但是似乎spark在表发现中使用了column标签而不是名称,请参见下面的JdbcUtils摘录: / p>

https://github.com/apache/spark/blob/master/sql/core/src/main/scala/org/apache/spark/sql/execution/datasources/jdbc/JdbcUtils.scala#L293

while (i < ncols) {
  val columnName = rsmd.getColumnLabel(i + 1)

这会导致SQL错误,因为它尝试在生成的SQL代码中使用人类可读的列名。

要使SAS IOM JDBC正常工作,它必须是getColumnName而不是getColumnLabel。有方言可以指定此方法吗?除了包装整个com.sas.rio.MVADriver和resultsetmeta

之外,我真的找不到一种方法可以解决这个问题

坦率

1 个答案:

答案 0 :(得分:1)

在此期间,我发现了如何做到这一点,因此仅发布以供参考。诀窍是注册自己的方言,如下所示。

此外,SAS用空格填充所有varchar列,因此我修剪了所有字符串列。

  def getSasTable(sparkSession: org.apache.spark.sql.SparkSession, tablename: String): org.apache.spark.sql.DataFrame = {                                       
    val host : String = "dwhid94.msnet.railb.be";                                                                                                               
    val port : String = "48593";                                                                                                                                
    val props = new java.util.Properties();                                                                                                                     
    props.put("user", CredentialsStore.getUsername("sas"))                                                                                                      
    props.put("password", CredentialsStore.getPassword("sas"))                                                                                                  
    props.setProperty("driver", "com.sas.rio.MVADriver")                                                                                                        
    val sasconurl : String =  String.format("jdbc:sasiom://%s:%s", host, port);                                                                                 
                                                                                                                                                                
    object SasDialect extends JdbcDialect {                                                                                                                     
      override def canHandle(url: String): Boolean = url.startsWith("jdbc:sasiom")                                                                              
      override def quoteIdentifier(colName: String): String = "\"" + colName + "\"n"                                                                            
    }                                                                                                                                                           
    JdbcDialects.registerDialect(SasDialect)                                                                                                                    
    val df = sparkSession.read                                                                                                                                  
      .option("url", sasconurl)                                                                                                                                 
      .option("driver", "com.sas.rio.MVADriver")                                                                                                                
      .option("dbtable", tablename)                                                                                                                             
      .option("user",CredentialsStore.getUsername("sas"))                                                                                                       
      .option("password",CredentialsStore.getPassword("sas"))                                                                                                   
      .option("fetchsize",100)                                                                                                                                  
      .format("jdbc")                                                                                                                                           
      .load()                                                                                                                                                   
                                                                                                                                                                
    val strippedDf = sparkSession.createDataFrame(df.rdd.map(r => Row(r.toSeq.map(x => x match {case s: String => s.trim; case _ => x}): _*)), df.schema);      
    return strippedDf;                                                                                                                                          
  }