将分析数据从Spark插入Postgres

时间:2015-02-03 12:17:49

标签: java postgresql cassandra apache-spark apache-spark-sql

我有Cassandra数据库,我通过Apache Spark使用SparkSQL分析数据。现在我想将这些分析的数据插入到PostgreSQL中。有没有办法直接实现这一点,除了使用PostgreSQL驱动程序(我使用postREST和驱动程序实现它我想知道是否有任何方法,如saveToCassandra())?

4 个答案:

答案 0 :(得分:13)

目前还没有将RDD写入任何DBMS的本机实现。以下是Spark用户列表中相关讨论的链接:onetwo

一般来说,性能最佳的方法如下:

  1. 验证RDD中的分区数,不应该太低和太高。 20-50个分区应该没问题,如果数量较少 - 请拨打repartition 20个分区,如果更高 - 请拨打coalesce到50个分区
  2. 调用mapPartition转换,在其内部调用函数以使用JDBC将记录插入到DBMS中。在此函数中,您打开与数据库的连接并使用带有this API的COPY命令,这将允许您消除对每条记录单独命令的需要 - 这样可以更快地处理插入
  3. 这样,您可以使用最多50个并行连接以并行方式将数据插入Postgres(取决于您的Spark群集大小及其配置)。整个方法可以实现为接受RDD和连接字符串

    的Java / Scala函数

答案 1 :(得分:1)

通过0x0FFF回答是好的。这是一个有用的附加点。

我使用foreachPartition来持久存储到外部商店。这也与Spark文档中给出的设计模式Design Patterns for using foreachRDD一致 https://spark.apache.org/docs/1.3.0/streaming-programming-guide.html#output-operations-on-dstreams

示例:

dstream.foreachRDD { rdd =>
  rdd.foreachPartition { partitionOfRecords =>
    // ConnectionPool is a static, lazily initialized pool of connections
    val connection = ConnectionPool.getConnection()
    partitionOfRecords.foreach(record => connection.send(record))
    ConnectionPool.returnConnection(connection)  // return to the pool for future reuse
  }
}

答案 2 :(得分:1)

你可以使用Postgres copy api来编写它,它的速度要快得多。请参阅以下两种方法 - 一种迭代RDD以填充可通过复制API保存的缓冲区。您唯一需要注意的是以csv格式创建正确的语句,该语句将由copy api使用。

def saveToDB(rdd: RDD[Iterable[EventModel]]): Unit = {
        val sb = mutable.StringBuilder.newBuilder
        val now = System.currentTimeMillis()

        rdd.collect().foreach(itr => {
            itr.foreach(_.createCSV(sb, now).append("\n"))
        })

        copyIn("myTable",  new StringReader(sb.toString), "statement")
        sb.clear
    }


def copyIn(tableName: String, reader: java.io.Reader, columnStmt: String = "") = {
        val conn = connectionPool.getConnection()
        try {
            conn.unwrap(classOf[PGConnection]).getCopyAPI.copyIn(s"COPY $tableName $columnStmt FROM STDIN WITH CSV", reader)
        } catch {
            case se: SQLException => logWarning(se.getMessage)
            case t: Throwable => logWarning(t.getMessage)
        } finally {
            conn.close()
        }
    }

答案 3 :(得分:0)

上面的答案是针对旧的spark版本的,在spark 2. *中有jdbc连接器,可以从dataFrame直接写入RDBS。

示例:

jdbcDF2.write.jdbc("jdbc:postgresql:dbserver", "schema.tablename",
          properties={"user": "username", "password": "password"})

https://spark.apache.org/docs/latest/sql-data-sources-jdbc.html