Repository navigation
Conversation
| return false; | ||
| } | ||
|
|
||
| protected Set<FileFormat> supportedFormats() { |
There was a problem hiding this comment.
I don't really like this one.
Could we just re-define FILE_FORMATS, and FORMAT_AND_GENERATOR in TestSparkVectorizedFormatModel?
private static final FileFormat[] FILE_FORMATS = {FileFormat.ORC, FileFormat.PARQUET};
private static final List<Arguments> FORMAT_AND_GENERATOR
This relies on the fact, how junit works internally, but no change is required in all of the tests.
I'm open for other ideas as well, this is just the first one occured to me
There was a problem hiding this comment.
Thank you for the suggestion @pvary I tried it out and here's what I found:
Redefining FILE_FORMATS in the subclass works as you described, those tests drop AVRO with no base class changes.
Redefining FORMAT_AND_GENERATOR doesn't work as is, because it references DataGenerators, which is package-private in org.apache.iceberg.data while TestSparkVectorizedFormatModel is in org.apache.iceberg.spark.data.
I tried making DataGenerators, DataGenerators.ALL and the DataGenerator interface public, and with that both fields can be redefined in the subclass. All AVRO cases are gone and I could remove supportedFormats() and the per test assumptions entirely. TestSparkFormatModel and TestFlinkFormatModel still pass.
Would you like me to go with that, or would you rather avoid widening the visibility of those test classes?
There was a problem hiding this comment.
I'm fine with making the DataGenerator and related stuff public in the test packages
There was a problem hiding this comment.
Thank you @pvary.
- Made
DataGenerator,DataGeneratorsandDataGenerators.ALLpublic in the test package. TestSparkVectorizedFormatModelredefines bothFILE_FORMATSandFORMAT_AND_GENERATOR.- Dropped
supportedFormats()and all the per testassumeSupportedFormat()calls from the base class.
There was a problem hiding this comment.
One thing I hit while doing this. When the subclass redefines FORMAT_AND_GENERATOR, it also has to repeat every filter the base applies. #17617 added supportsGenerator yesterday, my subclass didn't have it, and ORC + Variant came back and failed CI.
To fix it I'd have to either make supportsGenerator public, or copy the check into the subclass. Neither seems clean, and any new filter will have the same problem IIUC.
| return false; | ||
| } | ||
|
|
||
| protected boolean readOnly() { |
There was a problem hiding this comment.
Shall we split the base test class to read-tests, and read+write-tests?
Using this method in all test seem awkward a bit.
If we decide so, we might want to do it in a different PR
There was a problem hiding this comment.
I agree with you, would love your advice.
Two ways we could do it:
- Keep the read tests and shared helpers in
BaseFormatModelTests, move the write tests into aBaseReadWriteFormatModelTeststhat extends it. Existing tests move to the new class. - Insert a
BaseReadFormatModelTestsabove the currentBaseFormatModelTestsand put the read tests there. No existing subclass changes its extends.
And TestSparkVectorizedFormatModel would only extend the read-only class.
Would you like to do it in a follow-up PR or this PR?
There was a problem hiding this comment.
Please separate out the test to:
- ReadFormatModelTests as a base, and move the read tests there
- BaseFormatModelTests inheriting from ReadFormatModelTests
I would do this way
There was a problem hiding this comment.
This should be in a PR before this change
159b391 to
6b66972
Compare
| import org.apache.spark.sql.vectorized.ColumnarBatch; | ||
| import org.junit.jupiter.params.provider.Arguments; | ||
|
|
||
| public class TestSparkVectorizedFormatModel extends BaseFormatModelTests<ColumnarBatch> { |
6b66972 to
50d5209
Compare
50d5209 to
625fe88
Compare
| @ParameterizedTest | ||
| @FieldSource("FILE_FORMATS") | ||
| void testNestedDefaultValue(FileFormat fileFormat) throws IOException { | ||
| assumeFalse(supportsBatchReads(), "Vectorized reads do not support nested types"); |
There was a problem hiding this comment.
could we handle this with unsupportedTypeIds?
There was a problem hiding this comment.
I added assumeSupportedTypes() to skip tests when the schema contains a type listed in unsupportedTypeIds().
| @FieldSource("FILE_FORMATS") | ||
| void testReaderBuilderSplit(FileFormat fileFormat) throws IOException { | ||
|
|
||
| assumeFalse(supportsBatchReads(), "Batch reads return batches, not rows"); |
There was a problem hiding this comment.
Do we need to override this test, or can we test differently?
There was a problem hiding this comment.
I added a countRows() hook that sums the row counts across ColumnarBatch instances and uses .size() for row readers. This allows the shared tests to work for both.
| @FieldSource("FILE_FORMATS") | ||
| void testReaderBuilderReuseContainers(FileFormat fileFormat) throws IOException { | ||
|
|
||
| assumeFalse(supportsBatchReads(), "Batch reads reuse differently"); |
There was a problem hiding this comment.
Neither vectorized reader returns the same object twice. ColumnarBatchReader.read always builds a new ColumnarBatch and uses reuse only to decide whether to close the previous vectors IIUC:
if (reuse == null) {
closeVectors();
}
return new ColumnBatchLoader(numRowsToRead).loadDataToColumnBatch();VectorizedSparkOrcReaders.read doesn't take a reuse argument at all.
I checked with and without reuseContainers() on both formats and each call returns a new object either way. Is that expected for batch reads? Please correct me if I am wrong.
There was a problem hiding this comment.
What about the underlying data structures? I expect that the Arrow Vlvectors should be reused.
There was a problem hiding this comment.
The reuse logic is in VectorizedArrowReader.java.
In ColumnarBatchReader.java, the previous VectorHolder is passed back to the reader, allowing the underlying Arrow vector to be reused.
I am getting each vector in a batch like this,
private ValueVector arrowVector(ColumnarBatch batch, int col) {
IcebergArrowColumnVector vector = (IcebergArrowColumnVector) batch.column(col);
return vector.vectorAccessor().getVector();
}I have updated the shared test to compare the underlying Arrow vectors for every column, both with and without reuseContainers().
| @FieldSource("FILE_FORMATS") | ||
| void testReadMetadataColumnIsDeleted(FileFormat fileFormat) throws IOException { | ||
|
|
||
| assumeFalse(supportsBatchReads(), "DeletedColumnVector requires a delete filter"); |
There was a problem hiding this comment.
Please provide a better message. DeletedColumnVector is Spark specific.
What is the exact issue here? The batch readers doesn't read the DVs either, so checking false seems ok.
There was a problem hiding this comment.
It doesn't return false, it throws:
TestSparkVectorizedFormatModel > testReadMetadataColumnIsDeleted(FileFormat) > [2] PARQUET FAILED
java.lang.NullPointerException: Cannot load from byte/boolean array because "this.isDeleted" is null
at org.apache.iceberg.spark.data.vectorized.DeletedColumnVector.getBoolean(DeletedColumnVector.java:61)
at org.apache.spark.sql.vectorized.ColumnarBatchRow.getBoolean(ColumnarBatchRow.java:108)
at org.apache.spark.sql.vectorized.ColumnarBatchRow.get(ColumnarBatchRow.java:181)
at org.apache.iceberg.spark.data.TestHelpers.assertEquals(TestHelpers.java:772)
at org.apache.iceberg.spark.data.TestHelpers.assertEquals(TestHelpers.java:734)
at org.apache.iceberg.spark.data.TestHelpers.assertEquals(TestHelpers.java:719)
at org.apache.iceberg.spark.data.TestSparkVectorizedFormatModel.assertRecordsEqual(TestSparkVectorizedFormatModel.java:102)
The array is only filled when a delete filter is set IIUC. ORC passes, so this is Parquet only if I am not wrong. I will fix the message. Should I file an issue for this, or send a fix PR? Please correct me if I am wrong.
There was a problem hiding this comment.
Yeah, the array is only created by the delete filter.
Let me think what could we do here.
There was a problem hiding this comment.
Taking a look at supportsBatchReads - it always return false.
I think we should override this method.
Also we should update testReaderBuilderRecordsPerBatchNotSupported to have a batch and a non-bach version. Maybe with override and rename to testReaderBuilderRecordsPerBatch
There was a problem hiding this comment.
I updated the skip message to explain the issue and limited the skip to vectorized Parquet. ORC still runs the test.
There was a problem hiding this comment.
I updated testReaderBuilderRecordsPerBatch to test both row and batch readers. Row readers check that recordsPerBatch() throws an exception, while batch readers check the batch size and total row count.
| @FieldSource("FILE_FORMATS") | ||
| void testReadMetadataColumnRowLineage(FileFormat fileFormat) throws IOException { | ||
|
|
||
| // TODO: ORC's vectorized reader treats _row_id as a plain constant |
There was a problem hiding this comment.
Shorten and leave an issue id in the text
| @ParameterizedTest | ||
| @FieldSource("FILE_FORMATS") | ||
| void testSchemaEvolutionEmptyProjection(FileFormat fileFormat) throws IOException { | ||
| assumeFalse(supportsBatchReads(), "Row count assertion does not apply to batches"); |
There was a problem hiding this comment.
I added a countRows() hook that sums the row counts across ColumnarBatch instances and uses .size() for row readers. This allows the shared tests to work for both.
|
This pull request has been marked as stale due to 30 days of inactivity. It will be closed in 1 week if no further activity occurs. If you think that’s incorrect or this pull request requires a review, please simply write any comment. If closed, you can revive the PR at any time and @mention a reviewer or discuss it on the dev@iceberg.apache.org list. Thank you for your contributions. |
|
@joyhaldar: Are you planning to work on this? Shall we take over? Maybe @Guosmilesmile could help, if you want. |
Sorry for the delay, I was still planning to work on this, but I've been consumed by other priorities. I would still require some time to get back to this. I would not mind if you'd like to take it over, but I am planning to make time in the coming weeks. |
Hi @joyhaldar, if you're still short on time I'd be happy to pick this up. I'd keep your commits and address @pvary's comments (splitting testReaderBuilderRecordsPerBatchNotSupported into batch and non-batch versions, and checking reuse of the underlying Arrow vectors). If you'd rather finish it yourself, no problem at all, I'll leave it with you. |
Co-authored-by: Joy Haldar <joy.haldar@target.com>
Hello, sorry for the delay, I am working this over the weekend. |
…o 4.2 Co-authored-by: Joy Haldar <joy.haldar@target.com>
… for batch readers Co-authored-by: Joy Haldar <joy.haldar@target.com>
Co-authored-by: Joy Haldar <joy.haldar@target.com>
Co-authored-by: Joy Haldar <joy.haldar@target.com>
Co-authored-by: Joy Haldar <joy.haldar@target.com>
625fe88 to
556ce35
Compare
Co-authored-by: Joy Haldar <joy.haldar@target.com>
Co-authored-by: Joy Haldar <joy.haldar@target.com>
Co-authored-by: Joy Haldar <joy.haldar@target.com>
| readRecords = ImmutableList.copyOf(reader); | ||
| } | ||
|
|
||
| assertThat(readRecords).hasSizeGreaterThan(0).hasSizeLessThan(genericRecords.size()); |
There was a problem hiding this comment.
Please check this size checks. Are they still valid for the batches?
| } | ||
|
|
||
| private ValueVector arrowVector(ColumnarBatch batch, int col) { | ||
| IcebergArrowColumnVector vector = (IcebergArrowColumnVector) batch.column(col); |
There was a problem hiding this comment.
Are we sure about this? At least an instanceof please
| } | ||
|
|
||
| protected void assumeSupportedTypes(Schema schema) { | ||
| Collection<Type.TypeID> unsupportedTypeIds = unsupportedTypeIds(); |
There was a problem hiding this comment.
MAybe update the javadoc for unsupportedTypeIds?
Adds a TCK subclass for Spark's vectorized
ColumnarBatchread path.TestSparkVectorizedFormatModelextendsReadFormatModelTestsand redefinesFILE_FORMATSandFORMAT_AND_GENERATORto skip Avro, which has noColumnarBatchmodel registered. This required makingDataGenerator,DataGeneratorsandDataGenerators.ALLpublic in the test package.Two base class changes were needed:
assertRecordsEqual()- read tests built expectations viaconvertToEngineRecords, which can't work for a batch type