Java 将分析数据从Spark插入Postgres
我有一个Cassandra数据库,从中我通过ApacheSpark使用SparkSQL分析了数据。现在我想将这些分析过的数据插入到PostgreSQL中。除了使用PostgreSQL驱动程序(我是使用postREST和驱动程序实现的,我想知道是否有类似于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中的分区数,它不应该太低或太高。
saveToCassandra()
)的方法)之外,还有其他方法可以直接实现这一点吗 目前还没有将RDD写入任何DBMS的本机实现。以下是Spark用户列表中相关讨论的链接:
一般来说,最有效的方法如下:
重新分区
,如果数量较高-调用合并
到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并清除缓冲区。