Spark 数据集显示:无法多次捕获输出

问题描述

即使我已经找到了解决方法(请参阅答案),我还是要问这个问题,以免其他人遭受同样的痛苦。

我需要一种方法来向我的 log4j 记录器显示我的数据集。我这样做了: void org.apache.spark.sql.Dataset.show(int numRows,boolean truncate) 它只是记录到 stdOut。为了捕获 stdOut,我执行了以下操作(在 stackoverflow 上的其他地方找到了灵感):

void myMethod(Dataset<Row> data){
    // Save the old System.out
    PrintStream originalPrintStream = System.out;

    // Tell Java to use your special stream
    ByteArrayOutputStream logCollection = new ByteArrayOutputStream();
    PrintStream printStreamForCollectingLogs = new PrintStream(logCollection);
    System.setout(printStreamForCollectingLogs);

    // Print some output: goes to your special stream
    data.show(MAX_disPLAY_ROWS,false);

    // Put things back
    System.out.flush();
    System.setout(originalPrintStream);

    logger.info("\n"+logCollection.toString());
    logCollection.reset();
}

这仅适用一次,后续对同一数据集调用同一方法将无法捕获任何内容。 我正在使用:

      <groupId>org.apache.spark</groupId>
      <artifactId>spark-sql_2.11</artifactId>
      <version>2.4.5</version>

解决方法

这个问题似乎是由于数据集保留了它第一次遇到的字节流作为 stdOut 引起的,因为我能够通过将我的备用 stdOut 流提取为类变量来解决这个问题:

private static ByteArrayOutputStream logCollection = new ByteArrayOutputStream();
private static PrintStream printStreamForCollectingLogs = new PrintStream(logCollection);

这意味着我每次都在 logger.info("\n"+logCollection.toString()) 中使用相同的字节流。这使我可以随时调用 myMethod 并每次都捕获输出。