|
58 | 58 | import java.util.Iterator; |
59 | 59 | import java.util.List; |
60 | 60 | import java.util.Map; |
| 61 | +import java.util.Optional; |
61 | 62 | import java.util.Random; |
62 | 63 | import java.util.Set; |
63 | 64 | import java.util.function.Predicate; |
|
69 | 70 | import org.apache.parquet.bytes.TrackingByteBufferAllocator; |
70 | 71 | import org.apache.parquet.column.ParquetProperties; |
71 | 72 | import org.apache.parquet.column.ParquetProperties.WriterVersion; |
| 73 | +import org.apache.parquet.column.statistics.BinaryStatistics; |
72 | 74 | import org.apache.parquet.crypto.ColumnEncryptionProperties; |
73 | 75 | import org.apache.parquet.crypto.DecryptionKeyRetrieverMock; |
74 | 76 | import org.apache.parquet.crypto.FileDecryptionProperties; |
|
86 | 88 | import org.apache.parquet.hadoop.example.ExampleParquetWriter; |
87 | 89 | import org.apache.parquet.hadoop.example.GroupReadSupport; |
88 | 90 | import org.apache.parquet.hadoop.metadata.ColumnPath; |
| 91 | +import org.apache.parquet.internal.column.columnindex.ColumnIndex; |
| 92 | +import org.apache.parquet.internal.column.columnindex.ColumnIndexBuilder; |
| 93 | +import org.apache.parquet.internal.column.columnindex.OffsetIndex; |
| 94 | +import org.apache.parquet.internal.column.columnindex.OffsetIndexBuilder; |
| 95 | +import org.apache.parquet.internal.filter2.columnindex.ColumnIndexFilter; |
| 96 | +import org.apache.parquet.internal.filter2.columnindex.ColumnIndexStore; |
| 97 | +import org.apache.parquet.internal.filter2.columnindex.RowRanges; |
89 | 98 | import org.apache.parquet.io.api.Binary; |
90 | 99 | import org.apache.parquet.schema.MessageType; |
| 100 | +import org.apache.parquet.schema.PrimitiveType; |
91 | 101 | import org.apache.parquet.schema.Types; |
92 | 102 | import org.junit.After; |
93 | 103 | import org.junit.AfterClass; |
@@ -650,4 +660,75 @@ public void testFilteringWithProjection() throws IOException { |
650 | 660 | false, |
651 | 661 | true)); |
652 | 662 | } |
| 663 | + |
| 664 | + @Test |
| 665 | + public void testValidMetadata() throws Exception { |
| 666 | + String testColumnName = "test_column"; |
| 667 | + long testRowCount = 100L; |
| 668 | + Binary testMinValue = Binary.fromString("a"); |
| 669 | + Binary testMaxValue = Binary.fromString("z"); |
| 670 | + Binary filterValue = Binary.fromString(""); |
| 671 | + |
| 672 | + OffsetIndex offsetIndex = createValidOffsetIndex(); |
| 673 | + ColumnIndex columnIndex = createValidColumnIndex(testColumnName, testMinValue, testMaxValue); |
| 674 | + |
| 675 | + MockColumnIndexStore store = new MockColumnIndexStore(columnIndex, offsetIndex); |
| 676 | + RowRanges result = ColumnIndexFilter.calculateRowRanges( |
| 677 | + FilterCompat.get(gtEq(binaryColumn(testColumnName), filterValue)), |
| 678 | + store, |
| 679 | + Collections.singleton(ColumnPath.fromDotString(testColumnName)), |
| 680 | + testRowCount); |
| 681 | + |
| 682 | + assertEquals("Should return all rows for this filter", testRowCount, result.rowCount()); |
| 683 | + assertEquals("Should have single range", 1, result.getRanges().size()); |
| 684 | + assertEquals("Range should start at 0", 0L, result.getRanges().get(0).from); |
| 685 | + assertEquals( |
| 686 | + "Range should end at last row", |
| 687 | + testRowCount - 1, |
| 688 | + result.getRanges().get(0).to); |
| 689 | + } |
| 690 | + |
| 691 | + private OffsetIndex createValidOffsetIndex() { |
| 692 | + OffsetIndexBuilder builder = OffsetIndexBuilder.getBuilder(); |
| 693 | + builder.add(1000L, 100, 0L, Optional.empty()); |
| 694 | + builder.add(1100L, 100, 50L, Optional.empty()); |
| 695 | + return builder.build(); |
| 696 | + } |
| 697 | + |
| 698 | + private ColumnIndex createValidColumnIndex(String columnName, Binary minValue, Binary maxValue) { |
| 699 | + MessageType schema = Types.buildMessage() |
| 700 | + .required(PrimitiveType.PrimitiveTypeName.BINARY) |
| 701 | + .named(columnName) |
| 702 | + .named("test_schema"); |
| 703 | + PrimitiveType primitiveType = schema.getColumns().get(0).getPrimitiveType(); |
| 704 | + ColumnIndexBuilder builder = ColumnIndexBuilder.getBuilder(primitiveType, Integer.MAX_VALUE); |
| 705 | + |
| 706 | + for (int i = 0; i < 2; i++) { |
| 707 | + BinaryStatistics stats = new BinaryStatistics(); |
| 708 | + stats.updateStats(minValue); |
| 709 | + stats.updateStats(maxValue); |
| 710 | + builder.add(stats); |
| 711 | + } |
| 712 | + return builder.build(); |
| 713 | + } |
| 714 | + |
| 715 | + private static class MockColumnIndexStore implements ColumnIndexStore { |
| 716 | + private final ColumnIndex columnIndex; |
| 717 | + private final OffsetIndex offsetIndex; |
| 718 | + |
| 719 | + public MockColumnIndexStore(ColumnIndex columnIndex, OffsetIndex offsetIndex) { |
| 720 | + this.columnIndex = columnIndex; |
| 721 | + this.offsetIndex = offsetIndex; |
| 722 | + } |
| 723 | + |
| 724 | + @Override |
| 725 | + public ColumnIndex getColumnIndex(ColumnPath column) { |
| 726 | + return columnIndex; |
| 727 | + } |
| 728 | + |
| 729 | + @Override |
| 730 | + public OffsetIndex getOffsetIndex(ColumnPath column) { |
| 731 | + return offsetIndex; |
| 732 | + } |
| 733 | + } |
653 | 734 | } |
0 commit comments