为啥 Apache Orc RecordReader.searchArgument() 没有正确过滤?

Posted

技术标签:

【中文标题】为啥 Apache Orc RecordReader.searchArgument() 没有正确过滤?【英文标题】:Why is Apache Orc RecordReader.searchArgument() not filtering correctly?为什么 Apache Orc RecordReader.searchArgument() 没有正确过滤? 【发布时间】:2017-11-25 06:17:09 【问题描述】:

这是一个简单的程序:

    将记录写入 Orc 文件 然后尝试使用谓词下推 (searchArgument) 读取文件

问题:

    这是在 Orc 中使用谓词下推的正确方法吗? read(..) 方法似乎返回了所有记录,完全忽略了searchArguments。这是为什么呢?

注意事项:

我找不到任何有用的单元测试来演示谓词下推在 Orc 中的工作原理 (Orc on GitHub)。我也找不到有关此功能的任何明确文档。尝试查看Spark 和Presto 代码,但我找不到任何有用的东西。

下面的代码是https://github.com/melanio/codecheese-blog-examples/tree/master/orc-examples/src/main/java/codecheese/blog/examples/orc的修改版

public class TestRoundTrip 
public static void main(String[] args) throws IOException 
    final String file = "tmp/test-round-trip.orc";
    new File(file).delete();

    final long highestX = 10000L;
    final Configuration conf = new Configuration();

    write(file, highestX, conf);
    read(file, highestX, conf);


private static void read(String file, long highestX, Configuration conf) throws IOException 
    Reader reader = OrcFile.createReader(
            new Path(file),
            OrcFile.readerOptions(conf)
    );

    //Retrieve x that is "highestX - 1000". So, only 1 value should've been retrieved.
    Options readerOptions = new Options(conf)
            .searchArgument(
                    SearchArgumentFactory
                            .newBuilder()
                            .equals("x", Type.LONG, highestX - 1000)
                            .build(),
                    new String[]"x"
            );
    RecordReader rows = reader.rows(readerOptions);
    VectorizedRowBatch batch = reader.getSchema().createRowBatch();

    while (rows.nextBatch(batch)) 
        LongColumnVector x = (LongColumnVector) batch.cols[0];
        LongColumnVector y = (LongColumnVector) batch.cols[1];

        for (int r = 0; r < batch.size; r++) 
            long xValue = x.vector[r];
            long yValue = y.vector[r];

            System.out.println(xValue + ", " + yValue);
        
    
    rows.close();


private static void write(String file, long highestX, Configuration conf) throws IOException 
    TypeDescription schema = TypeDescription.fromString("struct<x:int,y:int>");
    Writer writer = OrcFile.createWriter(
            new Path(file),
            OrcFile.writerOptions(conf).setSchema(schema)
    );

    VectorizedRowBatch batch = schema.createRowBatch();
    LongColumnVector x = (LongColumnVector) batch.cols[0];
    LongColumnVector y = (LongColumnVector) batch.cols[1];
    for (int r = 0; r < highestX; ++r) 
        int row = batch.size++;
        x.vector[row] = r;
        y.vector[row] = r * 3;
        // If the batch is full, write it out and start over.
        if (batch.size == batch.getMaxSize()) 
            writer.addRowBatch(batch);
            batch.reset();
        
    
    if (batch.size != 0) 
        writer.addRowBatch(batch);
        batch.reset();
    
    writer.close();

【问题讨论】:

【参考方案1】:

我遇到了同样的问题,我认为通过更改来纠正它

.equals("x", Type.LONG,

.equals("x",PredicateLeaf.Type.LONG

在使用它时,阅读器似乎只返回批次以及相关行,而不仅仅是我们要求的一次。

【讨论】:

将highestX更改为1M(而不是10000L)以使其工作。为什么 ?因为 sarg 只会过滤/​​跳过文件/条带/行组。它不过滤行。或者将搜索参数更改为搜索 -100,您会看到差异。【参考方案2】:

我知道这个问题很老,但也许答案对某人有用。 (而且我刚刚看到mac写了一个评论说和我几个小时前基本一样,但我觉得单独的答案更好看)

Orc 在内部将数据分成所谓的“行组”(每个默认有​​ 10000 行),其中每个行组都有自己的索引。搜索参数仅用于过滤掉没有行可以匹配搜索参数的行组。但是,它不会过滤掉单个行。甚至可能是索引表明行组与搜索参数匹配,而其中没有一行实际上与搜索匹配。这是因为行组索引主要由行组中每一列的最小值和最大值组成。

因此,您将不得不遍历返回的行并跳过与您的搜索条件不匹配的行。

【讨论】:

以上是关于为啥 Apache Orc RecordReader.searchArgument() 没有正确过滤?的主要内容,如果未能解决你的问题,请参考以下文章

Java读取HDFS上的ORC格式文件

在 macOS 10.15.6 上编译 Apache ORC 时出错

org.apache.hadoop.hive.ql.io.orc.OrcStruct无法转换为org.apache.hadoop.io.BinaryComparable

原创问题定位分享(17)spark查orc格式数据偶尔报错NullPointerException

大数据基础之ORC简介

Hive ORC和Parquet