用于 Cloud Spanner 的 Simba JDBC 驱动程序与 Spark JDBC DataFrame 阅读器一起使用

Posted

技术标签:

【中文标题】用于 Cloud Spanner 的 Simba JDBC 驱动程序与 Spark JDBC DataFrame 阅读器一起使用【英文标题】:Simba JDBC driver For Cloud Spanner used with Spark JDBC DataFrame reader 【发布时间】:2017-12-03 03:29:05 【问题描述】:

我正在使用 Simba Technologies Inc 的 JDBC 驱动程序来连接 Google Cloud Spanner。它使用 Java.sql 按预期运行。什么时候,我尝试将 simba JDBC 驱动程序与 Spark 的 JDBC 阅读器一起使用,以便将查询输出读取为 DataFrame,但是它给出了错误的输出。

这是我的扳手表

UserID  UserName
1   Vaijnath
2   Ganesh
3   Rahul

元数据: 用户 ID(字符串) 用户名(字符串)

我正在执行 Query 为:SELECT * FROM users

当我将 Simba JDBC 驱动程序与 Java Sql 一起使用时,此查询获取正确的数据,但当我将其与 Spark SQL 的 JDBC 阅读器一起使用时,它无法获取数据。

它将DataFrame返回为

+------+--------+
|UserID|UserName|
+------+--------+
|UserID|UserName|
|UserID|UserName|
|UserID|UserName|
+------+--------+

正如我们所见,它返回了正确的元数据和行数,但是,行包含列名。

这是我正在使用的代码:

import java.util.Properties
import org.apache.spark.sql.DataFrame, SparkSession

object  spannerIn 
    val sparkSession =SparkSession
            .builder()
            .appName("Spark SQL basic example").master("local")
            .config("spark.sql.warehouse.dir", "file:///tmp")
            .config("spark.sql.shuffle.partitions", 1)
            .getOrCreate()

    val properties =new Properties()
    properties.setProperty("user", "")
    properties.setProperty("password", "")
    properties.setProperty("driver", "com.simba.cloudspanner.core.jdbc42.CloudSpanner42Driver")

    val connectionURL="jdbc:cloudspanner://localhost;Project=abc;Instance=pqr;Database=xyz;PvtKeyPath=FilePath"
    val selectQuery="(select * from users)"
    def main(args: Array[String]): Unit = 
            val df = createJdbcDataframe()
            df.show()
    
    def createJdbcDataframe(): DataFrame = 
    sparkSession.read.jdbc(connectionURL, selectQuery, properties)
    

我的问题是,我可以将 Simba JDBC 驱动程序与 Spark 一起使用吗? 如果是,那么我需要添加什么额外的东西。 任何帮助表示赞赏。

【问题讨论】:

【参考方案1】:

这是因为 Spark 默认使用双引号 (") 引用所有标识符,这意味着正在生成以下查询:

SELECT "UserID", "UserName" FROM USERS

这被 Cloud Spanner 解释为选择两个固定字符串。在大多数其他数据库中它与此基本相同:

SELECT 'UserID', 'UserName' FROM USERS

Google Cloud Spanner 使用反引号 (`) 来引用标识符,并期望这样:

SELECT `UserID`, `UserName` FROM USERS

要解决此问题,您需要为 Google Cloud Spanner 注册特定的 JDBC 方言并注册反引号以进行如下引用:

    Class.forName("nl.topicus.jdbc.CloudSpannerDriver");
    SparkSession spark = SparkSession.builder().appName("Java Spark SQL basic example")
                .config("spark.some.config.option", "some-value").master("local").getOrCreate();
    String sparkURL = "jdbc:cloudspanner://localhost;Project=project-id;Instance=instance-id;Database=db;PvtKeyPath=pathToKeyFile.json";
    JdbcDialects.registerDialect(new JdbcDialect()
    
        private static final long serialVersionUID = 1L;

        @Override
        public boolean canHandle(String url)
        
            return url.toLowerCase().startsWith("jdbc:cloudspanner:");
        

        @Override
        public String quoteIdentifier(String column)
        
            return "`" + column + "`";
        
    );
    Dataset<Row> dataset = spark.read().jdbc(sparkURL, "ACCOUNT", new Properties());
    dataset.show();

请注意,我没有使用 Simba 驱动程序测试过上述内容,而仅使用此驱动程序:https://github.com/olavloite/spanner-jdbc 我想它也应该适用于 Simba 驱动程序。

【讨论】:

以上是关于用于 Cloud Spanner 的 Simba JDBC 驱动程序与 Spark JDBC DataFrame 阅读器一起使用的主要内容,如果未能解决你的问题,请参考以下文章

Cloud Spanner 读取与 Cloud Spanner SQL API

Cloud Spanner - `SHOW TABLES` 的等效语法?

Cloud Spanner:拆分“太大”的含义

Google Cloud Firestore 与 Google Cloud Spanner 的区别?

如何有效地与多个线程并行查询 google-cloud-spanner?

Cloud spanner 最佳实践 INTERLEAVE 问题