Java 将分析数据从Spark插入Postgres

Java 将分析数据从Spark插入Postgres,java,postgresql,cassandra,apache-spark,apache-spark-sql,Java,Postgresql,Cassandra,Apache Spark,Apache Spark Sql,我有一个Cassandra数据库,从中我通过ApacheSpark使用SparkSQL分析了数据。现在我想将这些分析过的数据插入到PostgreSQL中。除了使用PostgreSQL驱动程序(我是使用postREST和驱动程序实现的,我想知道是否有类似于saveToCassandra())的方法)之外,还有其他方法可以直接实现这一点吗 目前还没有将RDD写入任何DBMS的本机实现。以下是Spark用户列表中相关讨论的链接: 一般来说,最有效的方法如下: 验证RDD中的分区数,它不应该太低或太高。

我有一个Cassandra数据库,从中我通过ApacheSpark使用SparkSQL分析了数据。现在我想将这些分析过的数据插入到PostgreSQL中。除了使用PostgreSQL驱动程序(我是使用postREST和驱动程序实现的,我想知道是否有类似于
saveToCassandra()
)的方法)之外,还有其他方法可以直接实现这一点吗

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

一般来说,最有效的方法如下:

  • 验证RDD中的分区数,它不应该太低或太高。20-50个分区应该可以,如果数量较低-使用20个分区调用
    重新分区
    ,如果数量较高-调用
    合并
    到50个分区
  • 调用
    mapPartition
    转换,在转换中调用函数,使用JDBC将记录插入DBMS。在这个函数中,您可以打开与数据库的连接并使用COPY命令,这样就不需要为每个记录使用单独的命令,这样插入的处理速度就会更快

  • 通过这种方式,您可以使用最多50个并行连接(取决于您的Spark群集大小及其配置),以并行方式将数据插入Postgres。整个方法可以实现为一个Java/Scala函数,该函数接受RDD,并且连接字符串

    通过0x0FFF应答是好的。这里还有一点很有用

    我使用
    foreachPartition
    保存到外部存储。这也与Spark文档中给出的使用foreachRDD的设计模式
    相一致
    

    例如:

    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
      }
    }
    

    您可以使用Postgres copy api来编写它,这样速度更快。请参阅以下两种方法-一种方法迭代RDD以填充可由copy api保存的缓冲区。唯一需要注意的是以csv格式创建复制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()
            }
        }
    

    上面的答案指的是旧的spark版本,在spark 2中。*有jdbc连接器,允许从数据帧直接写入RDB

    例如:

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

    sb StringBuilder缓冲区是否会根据EventModel RDD中的记录数增长而不绑定?为什么你不会耗尽内存呢?我一直在使用这个解决方案,这个解决方案已经运行了几个月了,到目前为止我还没有看到它耗尽内存。我拥有的数据量也相当大——100000/秒。此外,如果您担心这一点,您可以随时进行另一项检查,在此基础上调用copyIn并清除缓冲区。