Presto 之Hive数据源Batch Read功能代码走读

本文详细介绍了Presto在通过HiveConnector读取Parquet和ORC文件时的BatchRead机制。对于Parquet,BatchSize的计算基于文件内容和RowGroup,以Page对齐方式读取数据;而对于ORC,初始BatchSize是blockSize与1024的较小值,读取时不需Page对齐,直接按字节流读取。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一. 前言

       在Presto中通过数据源的Connector读取数据的时候,返回来的是Page,一个Page中包含每列数据Block,Block中会包含多行数据。本文主要是通过Presto源码走读了解在Presto的Hive Connector中是如何通过Batch Read实现到Hive数据源取Page的时候进行多行数据读取功能的实现过程。

二. Parquet文件的Batch Read    

       Parquet文件的读取时候每次通过Parquet接口读取的数据量在Presto中是通过ParquetReader::batchSize参数控制的。BatchSize的计算遵循如下几个规则:

  1. Parquet文件读取时,初始batchSize为1。

  2. 读取Parquet数据量一般情况下,每次通过Parquet接口读取的batchSize是上一次的2倍。

  3. 如果一个rowkey内,剩下的数据小于batchSize,则只读取剩下的数据量大小。

  4. 如果读数据的position已经越过一个GroupRow,则重新清零,重复2-3,BatchSize还是上一次的两倍,不会从1开始初始化。

  5. 从parquet中真正读数据的时候,也是按照page对齐的方式读取的,每次读取pageSize大小的数据,读到BatchSize大小为止。

     Parquet文件读取时候BatchSize的控制主要通过如下几个代码段控制的:

// 计算BatchSize 大小
public int nextBatch()
{
    // nextRowInGroup: 在此RowGroup中,下一行读取的位置
	// currentGroupRowCount :此RowGroup的大小
	// currentPosition : 所有RowGroup中累计的位置
	
	// 如果下一行已经超过当前GroupRow的大小,则跳到下一个RowGroup
    if (nextRowInGroup >= currentGroupRowCount && !advanceToNextRowGroup()) {
        return -1;
    }


    // batchSize: 本次读取的批大小
	// nextBatchSize : 下一次读取的批大小
	// maxBatchSize : 固定为1024
	
	// 计算本次读取的批大小为上一次读取的大小的2倍
    batchSize = toIntExact(min(nextBatchSize, maxBatchSize));
    nextBatchSize = min(batchSize * BATCH_SIZE_GROWTH_FACTOR, MAX_VECTOR_LENGTH);
	
	// 如果当前RowGroup剩下的数据小于batchSize,以剩下的数据大小为准
    batchSize = toIntExact(min(batchSize, currentGroupRowCount - nextRowInGroup));

    nextRowInGroup += batchSize;
    currentPosition += batchSize;
    Arrays.stream(columnReaders)
            .forEach(reader -> reader.prepareNextRead(batchSize));
    return batchSize;
}



// 越过RowGroup BatchSize不会重新初始化,还是上次的2倍
private boolean advanceToNextRowGroup()
{
    currentRowGroupMemoryContext.close();
    currentRowGroupMemoryContext = systemMemoryContext.newAggregatedMemoryContext();

    // currentBlock: 当前的block的位置
	
	// 所有的block数据都已经读取完成
    if (currentBlock == blocks.size()) {
        return false;
    }
    currentBlockMetadata = blocks.get(currentBlock);
    currentBlock = currentBlock + 1;

    // 从下一个block的0开始的地方读取
    nextRowInGroup = 0L;
    currentGroupRowCount = currentBlockMetadata.getRowCount();
    initializeColumnReaders();
    return true;
}


// 读数据时候Page对齐进行读取
private void processValues(int valuesToRead, Consumer<Void> valueConsumer)
{
    if (definitionLevel == EMPTY_LEVEL_VALUE && repetitionLevel == EMPTY_LEVEL_VALUE) {
        definitionLevel = definitionReader.readLevel();
        repetitionLevel = repetitionReader.readLevel();
    }
    int valueCount = 0;
    for (int i = 0; i < valuesToRead; i++) {
        do {
            valueConsumer.accept(null);
            valueCount++;
            if (valueCount == remainingValueCountInPage) {
			
			    // 一个page一个page读取数据,直到读满batchSize
                updateValueCounts(valueCount);
                if (!readNextPage()) {
                    return;
                }
                valueCount = 0;
            }
            repetitionLevel = repetitionReader.readLevel();
            definitionLevel = definitionReader.readLevel();
        }
        while (repetitionLevel != 0);
    }
    updateValueCounts(valueCount);
}	       
	       

三. ORC文件的Batch Read

    ORC文件的Batch Size计算规则与Parquet文件有些不一样,主要表现为:

        1. ORC文件的初始initSize为 blockSize(一般为16M)与1024的较小值

         2. 当访问到下一个RowGroup的时候,BatchSize会按照上述第一步规则重新初始化

         3. ORC不需要Page对齐,因为ORC读取是如流式那样每个字节进行读取读取,然后不断地next直接到BatchSize数量为止,下边是ORC数据的主要读取流程。

OrcRecordReader::nextPage
    prepareNextBatch   // 计算batchSize大小
       columnsReader[columnIndex].readBlock
           BooleanColumnReader.readBlock   // 根据列的类型迪调用对应的ColumnReader
               readNonNullBlock
                  dataStream.getSetBits
                     getSetBits
                        byteStream.next()  // 一个个字节进行直接读取

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值