将大型HDFS文件读入Flink DataSet

时间:2018-10-28 00:05:09

标签: scala apache-flink

我正在尝试从HDFS中将具有自定义.fvecs格式的大文件读取到DataSet中。数据是公开可用的here,它也详细说明了格式。我将给出一个简短的摘要:

文件包含一组存储在原始Little Endian中的向量。每个向量占用4 + d * 4个字节,其中每个向量的前四个字节是表示向量维数的浮点数,已知为d = 128。以下d * 4个字节定义了d维点内的值。

数据可能包含多达十亿个点,这将永远无法容纳在内存中,因为即使没有额外的开销,这也将需要至少500 GB的内存。如果输入大小不太大,可以使用以下功能读取文件:

// The Point class is just a wrapper for Vector[Float]
def fi_vecs(path: String): Vector[Point] = {

  val data_in = new DataInputStream(
    new BufferedInputStream(
      new FileInputStream(
        new File(path))))

  // 516 is the number of bytes in a Point.
  // For floating points, we have 4 + 4 * 128
  val tmpArray = ByteBuffer.allocate(516).array
  val buffer = ByteBuffer.wrap(tmpArray)
  buffer.order(ByteOrder.LITTLE_ENDIAN)

  var tempVec = Vector[Point]()
  while (data_in.available > 0) {
    data_in.readFully(tmpArray)
    buffer.rewind()

    val dim = buffer.getInt
    if (dim != 128) throw new IOException("Error: Unexpected dimensionality d = " + dim + " of a feature vector.")

    var vec = Vector[Float]()
    while (vec.size < dim) {
        vec = vec :+ buffer.getFloat
    }
    tempVec = tempVec :+ Point(vec)
  }

  data_in.close()
  tempVec
}

我试图实现自定义FileInputFormat读取器,但是我不确定如何在不将完整读取的nextRecord直接保留在内存中的情况下驱动Vector[Point]函数调用。

任何建议都值得赞赏。

0 个答案:

没有答案