HDFS文件中的定位read或seek()会加载并忽略文件的全部内容吗?

ena*_*tor 3 java file hdfs

我想从某个偏移/位置读取大文件的子内容。例如,我有一个 1M 行的文件,我想从第 100 行开始读取 50 行。(行号:101 至 150 - 包括在内)

我想我应该使用 PositionalReadable。 https://issues.apache.org/jira/browse/HADOOP-519

我看到FSInputStream.readFully实际上使用了seek()的方法Seekable

当我检查底层实现时,seek()我发现它使用BlockReader.skip()

blockReader.skip() 不会读取整个数据直到跳过字节的位置吗?问题是 HDFS 是否也会加载前 100 行才能到达第 101 行。

如何使位置位于文件中任何所需的偏移量(例如文件的第 10000 行)而不加载其余内容?s3 在 header-offsets 中提供的东西。

这是我发现的类似问题:How to read files with a offset from Hadoop using Java,但它建议使用seek()并且在评论中争论这seek()是昂贵的操作,应该谨慎使用。我认为这是正确的,因为查找似乎读取所有数据以便跳到该位置。

Per*_*ERO 5

简短的回答可能会或可能不会读取尽可能多的数据skip(n)。正如你所说,seek()内部调用BlockReader.skip(). BlockReader是一种接口类型,通过创建BlockReaderFactory()BlockReader创建的实现是BlockReaderRemoteBlockReaderLocal。(没错,ExternalBlockReader也是可以的,但是因为是特殊情况所以排除了)

BlockReaderRemote当客户端通过 TCP 上的 RPC 从网络上的远程 DataNode 读取数据时使用。在这种情况下,如果分析skip()方法代码,您可以看到readNextPacket重复调用了 n 个字节以跳过。也就是说,它实际上读取的是要跳过的数据。

BlockReaderLocal当客户端与存储块的 DataNode 在同一台机器上时使用。在这种情况下,客户端可以直接读取块文件,并更改dataPos在下一次读取操作时实际执行基于偏移量的跳过。


+附加信息(2023.01.19)
上述内容适用于Hadoop 3.xx和2.xx,但由于项目结构的变化,实现的路径和名称从2.8.0版本开始发生了变化。

< 2.8.0
hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/BlockReaderLocal.java
hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache /hadoop/hdfs/RemoteBlockReader.java

>= 2.8.0
hadoop-hdfs-project/hadoop-hdfs-client/src/main/java/org/apache/hadoop/hdfs/client/impl/BlockReaderLocal.java
hadoop-hdfs-project/hadoop-hdfs-client/ src/main/java/org/apache/hadoop/hdfs/client/impl/BlockReaderRemote.java

相关 Jira 问题
https://issues.apache.org/jira/browse/HDFS-8057
https://issues.apache.org/jira/browse/HDFS-8925