首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >不会耗尽内存的Spark打印数据帧

不会耗尽内存的Spark打印数据帧
EN

Stack Overflow用户
提问于 2019-03-13 00:02:28
回答 2查看 613关注 0票数 2

如何在不耗尽内存的情况下用Java打印整个数据帧?

代码语言:javascript
复制
Dataset<Row> df = ...

我知道:

代码语言:javascript
复制
df.show() 

将显示数据帧,但对于足够大的数据帧,这可能会耗尽内存。

我知道我可以使用以下命令限制内容:

代码语言:javascript
复制
df.show(rowCount, false)

但是想要打印整个数据帧,我不想限制内容...

我试过了:

代码语言:javascript
复制
df.foreachPartition(iter -> {
    while(iter.hasNext()){
       System.out.println(rowIter.next().mkString(",");)
     }
});

但这将在每个相应的节点上打印,而不是在驱动程序上打印...

有没有办法在不耗尽内存的情况下打印驱动程序中的所有内容?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-03-13 03:26:59

你将不得不把所有的数据带给驱动程序,这会占用你的内存一点:(...

一种解决方案可能是在驱动程序中拆分数据帧并逐个打印。当然,这取决于数据本身的结构,如下所示:

代码语言:javascript
复制
long count = df.count();
long inc = count / 10;
for (long i = 0; i < count; i += inc) {
  Dataset<Row> filteredDf =
      df.where("id>=" + i + " AND id<" + (i + inc));

  List<Row> rows = filteredDf.collectAsList();
  for (Row r : rows) {
    System.out.printf("%d: %s\n", r.getAs(0), r.getString(1));
  }
}

我将数据集拆分为10个,但我知道我的ids是从1到100……

完整的示例可以是:

代码语言:javascript
复制
package net.jgp.books.sparkWithJava.ch20.lab900_splitting_dataframe;

import java.util.ArrayList;
import java.util.List;

import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.RowFactory;
import org.apache.spark.sql.SparkSession;
import org.apache.spark.sql.types.DataTypes;
import org.apache.spark.sql.types.StructField;
import org.apache.spark.sql.types.StructType;

/**
 * Splitting a dataframe to bring it back to the driver for local
 * processing.
 * 
 * @author jgp
 */
public class SplittingDataframeApp {

  /**
   * main() is your entry point to the application.
   * 
   * @param args
   */
  public static void main(String[] args) {
    SplittingDataframeApp app = new SplittingDataframeApp();
    app.start();
  }

  /**
   * The processing code.
   */
  private void start() {
    // Creates a session on a local master
    SparkSession spark = SparkSession.builder()
        .appName("Splitting a dataframe to collect it")
        .master("local")
        .getOrCreate();

    Dataset<Row> df = createRandomDataframe(spark);
    df = df.cache();

    df.show();
    long count = df.count();
    long inc = count / 10;
    for (long i = 0; i < count; i += inc) {
      Dataset<Row> filteredDf =
          df.where("id>=" + i + " AND id<" + (i + inc));

      List<Row> rows = filteredDf.collectAsList();
      for (Row r : rows) {
        System.out.printf("%d: %s\n", r.getAs(0), r.getString(1));
      }
    }
  }

  private static Dataset<Row> createRandomDataframe(SparkSession spark) {
    StructType schema = DataTypes.createStructType(new StructField[] {
        DataTypes.createStructField(
            "id",
            DataTypes.IntegerType,
            false),
        DataTypes.createStructField(
            "value",
            DataTypes.StringType,
            false) });

    List<Row> rows = new ArrayList<Row>();
    for (int i = 0; i < 100; i++) {
      rows.add(RowFactory.create(i, "Row #" + i));
    }
    Dataset<Row> df = spark.createDataFrame(rows, schema);
    return df;
  }
}

你觉得这能帮上忙吗?

它不像将其保存在数据库中那样优雅,但它允许在您的体系结构中避免额外的组件。这段代码不是很通用,我不确定你能不能让它在当前版本的Spark中通用。

票数 1
EN

Stack Overflow用户

发布于 2019-03-13 00:31:10

AFAIK,打印数据框的想法是为了查看数据。

不建议基于内存不足的数据帧大小打印大型数据帧。

我会提供下面的方法,如果你想要查看内容,那么你可以保存在hive表中并查询内容。或者写入可读的csv或json。

示例:

1)保存在配置单元表中

代码语言:javascript
复制
df.write.mode("overwrite").saveAsTable("database.tableName")

稍后从配置单元表中查询。

2) csv或json

代码语言:javascript
复制
df.write.csv("/your/location/data.csv")
 df.write.json("/your/location/data.json")

如果您希望单个文件使用coalesce(1),上面将生成多个零件文件(但这将再次将数据移动到一个节点,这是不鼓励的,除非您绝对需要它)

另一种选择是使用toLocalIterator see here逐行打印,这也会将数据传输到节点...因此这不是个好主意

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55125909

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档