This is an automated email from the ASF dual-hosted git repository.
lzljs3620320 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-paimon.git
The following commit(s) were added to refs/heads/master by this push:
new 6acc43459 [core] Optimize BinaryTableStats to real binary (#2800)
6acc43459 is described below
commit 6acc43459da5b3050a60b40edde6f7a1c0508c3d
Author: Jingsong Lee <[email protected]>
AuthorDate: Mon Jan 29 10:44:39 2024 +0800
[core] Optimize BinaryTableStats to real binary (#2800)
---
.../java/org/apache/paimon/data/BinaryArray.java | 33 +++
.../main/java/org/apache/paimon/predicate/And.java | 11 +-
.../apache/paimon/predicate/CompoundPredicate.java | 13 +-
.../java/org/apache/paimon/predicate/Equal.java | 7 +-
.../apache/paimon/predicate/GreaterOrEqual.java | 6 +-
.../org/apache/paimon/predicate/GreaterThan.java | 6 +-
.../main/java/org/apache/paimon/predicate/In.java | 13 +-
.../org/apache/paimon/predicate/IsNotNull.java | 4 +-
.../java/org/apache/paimon/predicate/IsNull.java | 4 +-
.../org/apache/paimon/predicate/LeafFunction.java | 8 +-
.../org/apache/paimon/predicate/LeafPredicate.java | 19 +-
.../apache/paimon/predicate/LeafUnaryFunction.java | 13 +-
.../org/apache/paimon/predicate/LessOrEqual.java | 6 +-
.../java/org/apache/paimon/predicate/LessThan.java | 6 +-
.../java/org/apache/paimon/predicate/NotEqual.java | 7 +-
.../java/org/apache/paimon/predicate/NotIn.java | 13 +-
.../predicate/NullFalseLeafBinaryFunction.java | 13 +-
.../main/java/org/apache/paimon/predicate/Or.java | 11 +-
.../org/apache/paimon/predicate/Predicate.java | 5 +-
.../org/apache/paimon/predicate/StartsWith.java | 16 +-
.../apache/paimon/predicate/FieldStatsUtils.java} | 41 ++--
.../paimon/predicate/PredicateBuilderTest.java | 26 ++-
.../org/apache/paimon/predicate/PredicateTest.java | 224 ++++++++++++---------
.../java/org/apache/paimon/io/DataFileMeta.java | 3 +-
.../apache/paimon/io/DataFileMetaSerializer.java | 8 +-
.../apache/paimon/manifest/ManifestFileMeta.java | 6 +-
.../manifest/ManifestFileMetaSerializer.java | 4 +-
.../paimon/operation/AbstractFileStoreScan.java | 13 +-
.../paimon/operation/AppendOnlyFileStoreScan.java | 22 +-
.../paimon/operation/KeyValueFileStoreScan.java | 35 ++--
.../paimon/partition/PartitionPredicate.java | 30 ++-
.../apache/paimon/schema/SchemaEvolutionUtil.java | 13 +-
.../org/apache/paimon/stats/BinaryTableStats.java | 103 +++-------
.../paimon/stats/FieldStatsArraySerializer.java | 214 +++++++++++++++++++-
.../apache/paimon/stats/FieldStatsConverters.java | 15 +-
.../org/apache/paimon/table/system/FilesTable.java | 2 +-
.../org/apache/paimon/utils/BulkFormatMapping.java | 2 +-
.../apache/paimon/append/AppendOnlyWriterTest.java | 13 +-
.../apache/paimon/manifest/ManifestFileTest.java | 10 +-
.../paimon/partition/PartitionPredicateTest.java | 16 +-
.../apache/paimon/stats/BinaryTableStatsTest.java | 93 ---------
.../stats/FieldStatsArraySerializerTest.java | 18 +-
.../org/apache/paimon/stats/StatsTableTest.java | 16 +-
.../paimon/table/ColumnTypeFileMetaTestBase.java | 145 ++++++-------
.../paimon/table/FileMetaFilterTestBase.java | 88 ++++----
.../PrimaryKeyTableColumnTypeFileMetaTest.java | 63 +++---
.../paimon/flink/PredicateConverterTest.java | 7 +-
47 files changed, 857 insertions(+), 587 deletions(-)
diff --git
a/paimon-common/src/main/java/org/apache/paimon/data/BinaryArray.java
b/paimon-common/src/main/java/org/apache/paimon/data/BinaryArray.java
index 981c8ecd6..0c3437fb4 100644
--- a/paimon-common/src/main/java/org/apache/paimon/data/BinaryArray.java
+++ b/paimon-common/src/main/java/org/apache/paimon/data/BinaryArray.java
@@ -567,4 +567,37 @@ public final class BinaryArray extends BinarySection
implements InternalArray, D
result.pointTo(MemorySegment.wrap(data), 0, (int) totalSize);
return result;
}
+
+ public static BinaryArray fromLongArray(Long[] arr) {
+ BinaryArray array = new BinaryArray();
+ BinaryArrayWriter writer = new BinaryArrayWriter(array, arr.length, 8);
+ for (int i = 0; i < arr.length; i++) {
+ Long v = arr[i];
+ if (v == null) {
+ writer.setNullLong(i);
+ } else {
+ writer.writeLong(i, v);
+ }
+ }
+ writer.complete();
+ return array;
+ }
+
+ public static BinaryArray fromLongArray(InternalArray arr) {
+ if (arr instanceof BinaryArray) {
+ return (BinaryArray) arr;
+ }
+
+ BinaryArray array = new BinaryArray();
+ BinaryArrayWriter writer = new BinaryArrayWriter(array, arr.size(), 8);
+ for (int i = 0; i < arr.size(); i++) {
+ if (arr.isNullAt(i)) {
+ writer.setNullLong(i);
+ } else {
+ writer.writeLong(i, arr.getLong(i));
+ }
+ }
+ writer.complete();
+ return array;
+ }
}
diff --git a/paimon-common/src/main/java/org/apache/paimon/predicate/And.java
b/paimon-common/src/main/java/org/apache/paimon/predicate/And.java
index c4ec83525..372e2c501 100644
--- a/paimon-common/src/main/java/org/apache/paimon/predicate/And.java
+++ b/paimon-common/src/main/java/org/apache/paimon/predicate/And.java
@@ -18,8 +18,8 @@
package org.apache.paimon.predicate;
+import org.apache.paimon.data.InternalArray;
import org.apache.paimon.data.InternalRow;
-import org.apache.paimon.format.FieldStats;
import java.util.ArrayList;
import java.util.List;
@@ -45,9 +45,14 @@ public class And extends CompoundPredicate.Function {
}
@Override
- public boolean test(long rowCount, FieldStats[] fieldStats,
List<Predicate> children) {
+ public boolean test(
+ long rowCount,
+ InternalRow minValues,
+ InternalRow maxValues,
+ InternalArray nullCounts,
+ List<Predicate> children) {
for (Predicate child : children) {
- if (!child.test(rowCount, fieldStats)) {
+ if (!child.test(rowCount, minValues, maxValues, nullCounts)) {
return false;
}
}
diff --git
a/paimon-common/src/main/java/org/apache/paimon/predicate/CompoundPredicate.java
b/paimon-common/src/main/java/org/apache/paimon/predicate/CompoundPredicate.java
index b8540722f..7b880c8a9 100644
---
a/paimon-common/src/main/java/org/apache/paimon/predicate/CompoundPredicate.java
+++
b/paimon-common/src/main/java/org/apache/paimon/predicate/CompoundPredicate.java
@@ -18,8 +18,8 @@
package org.apache.paimon.predicate;
+import org.apache.paimon.data.InternalArray;
import org.apache.paimon.data.InternalRow;
-import org.apache.paimon.format.FieldStats;
import java.io.Serializable;
import java.util.List;
@@ -54,8 +54,9 @@ public class CompoundPredicate implements Predicate {
}
@Override
- public boolean test(long rowCount, FieldStats[] fieldStats) {
- return function.test(rowCount, fieldStats, children);
+ public boolean test(
+ long rowCount, InternalRow minValues, InternalRow maxValues,
InternalArray nullCounts) {
+ return function.test(rowCount, minValues, maxValues, nullCounts,
children);
}
@Override
@@ -93,7 +94,11 @@ public class CompoundPredicate implements Predicate {
public abstract boolean test(InternalRow row, List<Predicate>
children);
public abstract boolean test(
- long rowCount, FieldStats[] fieldStats, List<Predicate>
children);
+ long rowCount,
+ InternalRow minValues,
+ InternalRow maxValues,
+ InternalArray nullCounts,
+ List<Predicate> children);
public abstract Optional<Predicate> negate(List<Predicate> children);
diff --git a/paimon-common/src/main/java/org/apache/paimon/predicate/Equal.java
b/paimon-common/src/main/java/org/apache/paimon/predicate/Equal.java
index e375479a6..e826fb0f1 100644
--- a/paimon-common/src/main/java/org/apache/paimon/predicate/Equal.java
+++ b/paimon-common/src/main/java/org/apache/paimon/predicate/Equal.java
@@ -18,7 +18,6 @@
package org.apache.paimon.predicate;
-import org.apache.paimon.format.FieldStats;
import org.apache.paimon.types.DataType;
import java.util.List;
@@ -39,9 +38,9 @@ public class Equal extends NullFalseLeafBinaryFunction {
}
@Override
- public boolean test(DataType type, long rowCount, FieldStats fieldStats,
Object literal) {
- return compareLiteral(type, literal, fieldStats.minValue()) >= 0
- && compareLiteral(type, literal, fieldStats.maxValue()) <= 0;
+ public boolean test(
+ DataType type, long rowCount, Object min, Object max, Long
nullCount, Object literal) {
+ return compareLiteral(type, literal, min) >= 0 && compareLiteral(type,
literal, max) <= 0;
}
@Override
diff --git
a/paimon-common/src/main/java/org/apache/paimon/predicate/GreaterOrEqual.java
b/paimon-common/src/main/java/org/apache/paimon/predicate/GreaterOrEqual.java
index 85005c55b..d4ec8639b 100644
---
a/paimon-common/src/main/java/org/apache/paimon/predicate/GreaterOrEqual.java
+++
b/paimon-common/src/main/java/org/apache/paimon/predicate/GreaterOrEqual.java
@@ -18,7 +18,6 @@
package org.apache.paimon.predicate;
-import org.apache.paimon.format.FieldStats;
import org.apache.paimon.types.DataType;
import java.util.List;
@@ -39,8 +38,9 @@ public class GreaterOrEqual extends
NullFalseLeafBinaryFunction {
}
@Override
- public boolean test(DataType type, long rowCount, FieldStats fieldStats,
Object literal) {
- return compareLiteral(type, literal, fieldStats.maxValue()) <= 0;
+ public boolean test(
+ DataType type, long rowCount, Object min, Object max, Long
nullCount, Object literal) {
+ return compareLiteral(type, literal, max) <= 0;
}
@Override
diff --git
a/paimon-common/src/main/java/org/apache/paimon/predicate/GreaterThan.java
b/paimon-common/src/main/java/org/apache/paimon/predicate/GreaterThan.java
index 57300945c..0b498b3ab 100644
--- a/paimon-common/src/main/java/org/apache/paimon/predicate/GreaterThan.java
+++ b/paimon-common/src/main/java/org/apache/paimon/predicate/GreaterThan.java
@@ -18,7 +18,6 @@
package org.apache.paimon.predicate;
-import org.apache.paimon.format.FieldStats;
import org.apache.paimon.types.DataType;
import java.util.List;
@@ -39,8 +38,9 @@ public class GreaterThan extends NullFalseLeafBinaryFunction {
}
@Override
- public boolean test(DataType type, long rowCount, FieldStats fieldStats,
Object literal) {
- return compareLiteral(type, literal, fieldStats.maxValue()) < 0;
+ public boolean test(
+ DataType type, long rowCount, Object min, Object max, Long
nullCount, Object literal) {
+ return compareLiteral(type, literal, max) < 0;
}
@Override
diff --git a/paimon-common/src/main/java/org/apache/paimon/predicate/In.java
b/paimon-common/src/main/java/org/apache/paimon/predicate/In.java
index 2360b3f4f..ba96f6651 100644
--- a/paimon-common/src/main/java/org/apache/paimon/predicate/In.java
+++ b/paimon-common/src/main/java/org/apache/paimon/predicate/In.java
@@ -18,7 +18,6 @@
package org.apache.paimon.predicate;
-import org.apache.paimon.format.FieldStats;
import org.apache.paimon.types.DataType;
import java.util.List;
@@ -50,15 +49,19 @@ public class In extends LeafFunction {
@Override
public boolean test(
- DataType type, long rowCount, FieldStats fieldStats, List<Object>
literals) {
- Long nullCount = fieldStats.nullCount();
+ DataType type,
+ long rowCount,
+ Object min,
+ Object max,
+ Long nullCount,
+ List<Object> literals) {
if (nullCount != null && rowCount == nullCount) {
return false;
}
for (Object literal : literals) {
if (literal != null
- && compareLiteral(type, literal, fieldStats.minValue()) >= 0
- && compareLiteral(type, literal, fieldStats.maxValue()) <=
0) {
+ && compareLiteral(type, literal, min) >= 0
+ && compareLiteral(type, literal, max) <= 0) {
return true;
}
}
diff --git
a/paimon-common/src/main/java/org/apache/paimon/predicate/IsNotNull.java
b/paimon-common/src/main/java/org/apache/paimon/predicate/IsNotNull.java
index dcf5d1687..3d2f9584e 100644
--- a/paimon-common/src/main/java/org/apache/paimon/predicate/IsNotNull.java
+++ b/paimon-common/src/main/java/org/apache/paimon/predicate/IsNotNull.java
@@ -18,7 +18,6 @@
package org.apache.paimon.predicate;
-import org.apache.paimon.format.FieldStats;
import org.apache.paimon.types.DataType;
import java.util.List;
@@ -37,8 +36,7 @@ public class IsNotNull extends LeafUnaryFunction {
}
@Override
- public boolean test(DataType type, long rowCount, FieldStats fieldStats) {
- Long nullCount = fieldStats.nullCount();
+ public boolean test(DataType type, long rowCount, Object min, Object max,
Long nullCount) {
return nullCount == null || nullCount < rowCount;
}
diff --git
a/paimon-common/src/main/java/org/apache/paimon/predicate/IsNull.java
b/paimon-common/src/main/java/org/apache/paimon/predicate/IsNull.java
index 22300c718..f825b2e23 100644
--- a/paimon-common/src/main/java/org/apache/paimon/predicate/IsNull.java
+++ b/paimon-common/src/main/java/org/apache/paimon/predicate/IsNull.java
@@ -18,7 +18,6 @@
package org.apache.paimon.predicate;
-import org.apache.paimon.format.FieldStats;
import org.apache.paimon.types.DataType;
import java.util.List;
@@ -37,8 +36,7 @@ public class IsNull extends LeafUnaryFunction {
}
@Override
- public boolean test(DataType type, long rowCount, FieldStats fieldStats) {
- Long nullCount = fieldStats.nullCount();
+ public boolean test(DataType type, long rowCount, Object min, Object max,
Long nullCount) {
return nullCount == null || nullCount > 0;
}
diff --git
a/paimon-common/src/main/java/org/apache/paimon/predicate/LeafFunction.java
b/paimon-common/src/main/java/org/apache/paimon/predicate/LeafFunction.java
index 075be7112..7a1e3d0f5 100644
--- a/paimon-common/src/main/java/org/apache/paimon/predicate/LeafFunction.java
+++ b/paimon-common/src/main/java/org/apache/paimon/predicate/LeafFunction.java
@@ -18,7 +18,6 @@
package org.apache.paimon.predicate;
-import org.apache.paimon.format.FieldStats;
import org.apache.paimon.types.DataType;
import java.io.Serializable;
@@ -31,7 +30,12 @@ public abstract class LeafFunction implements Serializable {
public abstract boolean test(DataType type, Object field, List<Object>
literals);
public abstract boolean test(
- DataType type, long rowCount, FieldStats fieldStats, List<Object>
literals);
+ DataType type,
+ long rowCount,
+ Object min,
+ Object max,
+ Long nullCount,
+ List<Object> literals);
public abstract Optional<LeafFunction> negate();
diff --git
a/paimon-common/src/main/java/org/apache/paimon/predicate/LeafPredicate.java
b/paimon-common/src/main/java/org/apache/paimon/predicate/LeafPredicate.java
index d2a2461ee..5267f7069 100644
--- a/paimon-common/src/main/java/org/apache/paimon/predicate/LeafPredicate.java
+++ b/paimon-common/src/main/java/org/apache/paimon/predicate/LeafPredicate.java
@@ -18,15 +18,14 @@
package org.apache.paimon.predicate;
+import org.apache.paimon.data.InternalArray;
import org.apache.paimon.data.InternalRow;
import org.apache.paimon.data.serializer.InternalSerializers;
import org.apache.paimon.data.serializer.ListSerializer;
import org.apache.paimon.data.serializer.NullableSerializer;
-import org.apache.paimon.format.FieldStats;
import org.apache.paimon.io.DataInputViewStreamWrapper;
import org.apache.paimon.io.DataOutputViewStreamWrapper;
import org.apache.paimon.types.DataType;
-import org.apache.paimon.utils.InternalRowUtils;
import java.io.IOException;
import java.io.ObjectInputStream;
@@ -35,6 +34,8 @@ import java.util.List;
import java.util.Objects;
import java.util.Optional;
+import static org.apache.paimon.utils.InternalRowUtils.get;
+
/** Leaf node of a {@link Predicate} tree. Compares a field in the row with
literals. */
public class LeafPredicate implements Predicate {
@@ -90,22 +91,24 @@ public class LeafPredicate implements Predicate {
@Override
public boolean test(InternalRow row) {
- return function.test(type, InternalRowUtils.get(row, fieldIndex,
type), literals);
+ return function.test(type, get(row, fieldIndex, type), literals);
}
@Override
- public boolean test(long rowCount, FieldStats[] fieldStats) {
- FieldStats stats = fieldStats[fieldIndex];
- Long nullCount = stats.nullCount();
+ public boolean test(
+ long rowCount, InternalRow minValues, InternalRow maxValues,
InternalArray nullCounts) {
+ Object min = get(minValues, fieldIndex, type);
+ Object max = get(maxValues, fieldIndex, type);
+ Long nullCount = nullCounts.isNullAt(fieldIndex) ? null :
nullCounts.getLong(fieldIndex);
if (nullCount == null || rowCount != nullCount) {
// not all null
// min or max is null
// unknown stats
- if (stats.minValue() == null || stats.maxValue() == null) {
+ if (min == null || max == null) {
return true;
}
}
- return function.test(type, rowCount, stats, literals);
+ return function.test(type, rowCount, min, max, nullCount, literals);
}
@Override
diff --git
a/paimon-common/src/main/java/org/apache/paimon/predicate/LeafUnaryFunction.java
b/paimon-common/src/main/java/org/apache/paimon/predicate/LeafUnaryFunction.java
index 429411c24..575ef8371 100644
---
a/paimon-common/src/main/java/org/apache/paimon/predicate/LeafUnaryFunction.java
+++
b/paimon-common/src/main/java/org/apache/paimon/predicate/LeafUnaryFunction.java
@@ -18,7 +18,6 @@
package org.apache.paimon.predicate;
-import org.apache.paimon.format.FieldStats;
import org.apache.paimon.types.DataType;
import java.util.List;
@@ -30,7 +29,8 @@ public abstract class LeafUnaryFunction extends LeafFunction {
public abstract boolean test(DataType type, Object value);
- public abstract boolean test(DataType type, long rowCount, FieldStats
fieldStats);
+ public abstract boolean test(
+ DataType type, long rowCount, Object min, Object max, Long
nullCount);
@Override
public boolean test(DataType type, Object value, List<Object> literals) {
@@ -39,7 +39,12 @@ public abstract class LeafUnaryFunction extends LeafFunction
{
@Override
public boolean test(
- DataType type, long rowCount, FieldStats fieldStats, List<Object>
literals) {
- return test(type, rowCount, fieldStats);
+ DataType type,
+ long rowCount,
+ Object min,
+ Object max,
+ Long nullCount,
+ List<Object> literals) {
+ return test(type, rowCount, min, max, nullCount);
}
}
diff --git
a/paimon-common/src/main/java/org/apache/paimon/predicate/LessOrEqual.java
b/paimon-common/src/main/java/org/apache/paimon/predicate/LessOrEqual.java
index 42bfe1192..cc17decad 100644
--- a/paimon-common/src/main/java/org/apache/paimon/predicate/LessOrEqual.java
+++ b/paimon-common/src/main/java/org/apache/paimon/predicate/LessOrEqual.java
@@ -18,7 +18,6 @@
package org.apache.paimon.predicate;
-import org.apache.paimon.format.FieldStats;
import org.apache.paimon.types.DataType;
import java.util.List;
@@ -39,8 +38,9 @@ public class LessOrEqual extends NullFalseLeafBinaryFunction {
}
@Override
- public boolean test(DataType type, long rowCount, FieldStats fieldStats,
Object literal) {
- return compareLiteral(type, literal, fieldStats.minValue()) >= 0;
+ public boolean test(
+ DataType type, long rowCount, Object min, Object max, Long
nullCount, Object literal) {
+ return compareLiteral(type, literal, min) >= 0;
}
@Override
diff --git
a/paimon-common/src/main/java/org/apache/paimon/predicate/LessThan.java
b/paimon-common/src/main/java/org/apache/paimon/predicate/LessThan.java
index 8149f550c..e26c8d68c 100644
--- a/paimon-common/src/main/java/org/apache/paimon/predicate/LessThan.java
+++ b/paimon-common/src/main/java/org/apache/paimon/predicate/LessThan.java
@@ -18,7 +18,6 @@
package org.apache.paimon.predicate;
-import org.apache.paimon.format.FieldStats;
import org.apache.paimon.types.DataType;
import java.util.List;
@@ -39,8 +38,9 @@ public class LessThan extends NullFalseLeafBinaryFunction {
}
@Override
- public boolean test(DataType type, long rowCount, FieldStats fieldStats,
Object literal) {
- return compareLiteral(type, literal, fieldStats.minValue()) > 0;
+ public boolean test(
+ DataType type, long rowCount, Object min, Object max, Long
nullCount, Object literal) {
+ return compareLiteral(type, literal, min) > 0;
}
@Override
diff --git
a/paimon-common/src/main/java/org/apache/paimon/predicate/NotEqual.java
b/paimon-common/src/main/java/org/apache/paimon/predicate/NotEqual.java
index 0e2704ada..a3bdfbb99 100644
--- a/paimon-common/src/main/java/org/apache/paimon/predicate/NotEqual.java
+++ b/paimon-common/src/main/java/org/apache/paimon/predicate/NotEqual.java
@@ -18,7 +18,6 @@
package org.apache.paimon.predicate;
-import org.apache.paimon.format.FieldStats;
import org.apache.paimon.types.DataType;
import java.util.List;
@@ -39,9 +38,9 @@ public class NotEqual extends NullFalseLeafBinaryFunction {
}
@Override
- public boolean test(DataType type, long rowCount, FieldStats fieldStats,
Object literal) {
- return compareLiteral(type, literal, fieldStats.minValue()) != 0
- || compareLiteral(type, literal, fieldStats.maxValue()) != 0;
+ public boolean test(
+ DataType type, long rowCount, Object min, Object max, Long
nullCount, Object literal) {
+ return compareLiteral(type, literal, min) != 0 || compareLiteral(type,
literal, max) != 0;
}
@Override
diff --git a/paimon-common/src/main/java/org/apache/paimon/predicate/NotIn.java
b/paimon-common/src/main/java/org/apache/paimon/predicate/NotIn.java
index 0a0a014df..d3a9715bf 100644
--- a/paimon-common/src/main/java/org/apache/paimon/predicate/NotIn.java
+++ b/paimon-common/src/main/java/org/apache/paimon/predicate/NotIn.java
@@ -18,7 +18,6 @@
package org.apache.paimon.predicate;
-import org.apache.paimon.format.FieldStats;
import org.apache.paimon.types.DataType;
import java.util.List;
@@ -50,15 +49,19 @@ public class NotIn extends LeafFunction {
@Override
public boolean test(
- DataType type, long rowCount, FieldStats fieldStats, List<Object>
literals) {
- Long nullCount = fieldStats.nullCount();
+ DataType type,
+ long rowCount,
+ Object min,
+ Object max,
+ Long nullCount,
+ List<Object> literals) {
if (nullCount != null && rowCount == nullCount) {
return false;
}
for (Object literal : literals) {
if (literal == null
- || (compareLiteral(type, literal, fieldStats.minValue())
== 0
- && compareLiteral(type, literal,
fieldStats.maxValue()) == 0)) {
+ || (compareLiteral(type, literal, min) == 0
+ && compareLiteral(type, literal, max) == 0)) {
return false;
}
}
diff --git
a/paimon-common/src/main/java/org/apache/paimon/predicate/NullFalseLeafBinaryFunction.java
b/paimon-common/src/main/java/org/apache/paimon/predicate/NullFalseLeafBinaryFunction.java
index 244ed3d72..2c8b57d0d 100644
---
a/paimon-common/src/main/java/org/apache/paimon/predicate/NullFalseLeafBinaryFunction.java
+++
b/paimon-common/src/main/java/org/apache/paimon/predicate/NullFalseLeafBinaryFunction.java
@@ -18,7 +18,6 @@
package org.apache.paimon.predicate;
-import org.apache.paimon.format.FieldStats;
import org.apache.paimon.types.DataType;
import java.util.List;
@@ -31,7 +30,7 @@ public abstract class NullFalseLeafBinaryFunction extends
LeafFunction {
public abstract boolean test(DataType type, Object field, Object literal);
public abstract boolean test(
- DataType type, long rowCount, FieldStats fieldStats, Object
literal);
+ DataType type, long rowCount, Object min, Object max, Long
nullCount, Object literal);
@Override
public boolean test(DataType type, Object field, List<Object> literals) {
@@ -43,13 +42,17 @@ public abstract class NullFalseLeafBinaryFunction extends
LeafFunction {
@Override
public boolean test(
- DataType type, long rowCount, FieldStats fieldStats, List<Object>
literals) {
- Long nullCount = fieldStats.nullCount();
+ DataType type,
+ long rowCount,
+ Object min,
+ Object max,
+ Long nullCount,
+ List<Object> literals) {
if (nullCount != null) {
if (rowCount == nullCount || literals.get(0) == null) {
return false;
}
}
- return test(type, rowCount, fieldStats, literals.get(0));
+ return test(type, rowCount, min, max, nullCount, literals.get(0));
}
}
diff --git a/paimon-common/src/main/java/org/apache/paimon/predicate/Or.java
b/paimon-common/src/main/java/org/apache/paimon/predicate/Or.java
index c145878a2..3385677ab 100644
--- a/paimon-common/src/main/java/org/apache/paimon/predicate/Or.java
+++ b/paimon-common/src/main/java/org/apache/paimon/predicate/Or.java
@@ -18,8 +18,8 @@
package org.apache.paimon.predicate;
+import org.apache.paimon.data.InternalArray;
import org.apache.paimon.data.InternalRow;
-import org.apache.paimon.format.FieldStats;
import java.util.ArrayList;
import java.util.List;
@@ -45,9 +45,14 @@ public class Or extends CompoundPredicate.Function {
}
@Override
- public boolean test(long rowCount, FieldStats[] fieldStats,
List<Predicate> children) {
+ public boolean test(
+ long rowCount,
+ InternalRow minValues,
+ InternalRow maxValues,
+ InternalArray nullCounts,
+ List<Predicate> children) {
for (Predicate child : children) {
- if (child.test(rowCount, fieldStats)) {
+ if (child.test(rowCount, minValues, maxValues, nullCounts)) {
return true;
}
}
diff --git
a/paimon-common/src/main/java/org/apache/paimon/predicate/Predicate.java
b/paimon-common/src/main/java/org/apache/paimon/predicate/Predicate.java
index c3d0cd8eb..b04029ba7 100644
--- a/paimon-common/src/main/java/org/apache/paimon/predicate/Predicate.java
+++ b/paimon-common/src/main/java/org/apache/paimon/predicate/Predicate.java
@@ -19,8 +19,8 @@
package org.apache.paimon.predicate;
import org.apache.paimon.annotation.Public;
+import org.apache.paimon.data.InternalArray;
import org.apache.paimon.data.InternalRow;
-import org.apache.paimon.format.FieldStats;
import java.io.Serializable;
import java.util.Optional;
@@ -47,7 +47,8 @@ public interface Predicate extends Serializable {
* @return return true is likely to hit (there may also be false
positives), return false is
* absolutely not possible to hit.
*/
- boolean test(long rowCount, FieldStats[] fieldStats);
+ boolean test(
+ long rowCount, InternalRow minValues, InternalRow maxValues,
InternalArray nullCounts);
/** @return the negation predicate of this predicate if possible. */
Optional<Predicate> negate();
diff --git
a/paimon-common/src/main/java/org/apache/paimon/predicate/StartsWith.java
b/paimon-common/src/main/java/org/apache/paimon/predicate/StartsWith.java
index acbdd6de1..56e5e8ecf 100644
--- a/paimon-common/src/main/java/org/apache/paimon/predicate/StartsWith.java
+++ b/paimon-common/src/main/java/org/apache/paimon/predicate/StartsWith.java
@@ -19,7 +19,6 @@
package org.apache.paimon.predicate;
import org.apache.paimon.data.BinaryString;
-import org.apache.paimon.format.FieldStats;
import org.apache.paimon.types.DataType;
import java.util.List;
@@ -43,12 +42,17 @@ public class StartsWith extends NullFalseLeafBinaryFunction
{
@Override
public boolean test(
- DataType type, long rowCount, FieldStats fieldStats, Object
patternLiteral) {
- BinaryString min = (BinaryString) fieldStats.minValue();
- BinaryString max = (BinaryString) fieldStats.maxValue();
+ DataType type,
+ long rowCount,
+ Object min,
+ Object max,
+ Long nullCount,
+ Object patternLiteral) {
+ BinaryString minStr = (BinaryString) min;
+ BinaryString maxStr = (BinaryString) max;
BinaryString pattern = (BinaryString) patternLiteral;
- return (min.startsWith(pattern) || min.compareTo(pattern) <= 0)
- && (max.startsWith(pattern) || max.compareTo(pattern) >= 0);
+ return (minStr.startsWith(pattern) || minStr.compareTo(pattern) <= 0)
+ && (maxStr.startsWith(pattern) || maxStr.compareTo(pattern) >=
0);
}
@Override
diff --git
a/paimon-common/src/main/java/org/apache/paimon/predicate/LeafUnaryFunction.java
b/paimon-common/src/test/java/org/apache/paimon/predicate/FieldStatsUtils.java
similarity index 52%
copy from
paimon-common/src/main/java/org/apache/paimon/predicate/LeafUnaryFunction.java
copy to
paimon-common/src/test/java/org/apache/paimon/predicate/FieldStatsUtils.java
index 429411c24..b829cf34d 100644
---
a/paimon-common/src/main/java/org/apache/paimon/predicate/LeafUnaryFunction.java
+++
b/paimon-common/src/test/java/org/apache/paimon/predicate/FieldStatsUtils.java
@@ -18,28 +18,27 @@
package org.apache.paimon.predicate;
+import org.apache.paimon.data.BinaryArray;
+import org.apache.paimon.data.GenericRow;
import org.apache.paimon.format.FieldStats;
-import org.apache.paimon.types.DataType;
-import java.util.List;
-
-/** Function to test a field. */
-public abstract class LeafUnaryFunction extends LeafFunction {
-
- private static final long serialVersionUID = 1L;
-
- public abstract boolean test(DataType type, Object value);
-
- public abstract boolean test(DataType type, long rowCount, FieldStats
fieldStats);
-
- @Override
- public boolean test(DataType type, Object value, List<Object> literals) {
- return test(type, value);
- }
-
- @Override
- public boolean test(
- DataType type, long rowCount, FieldStats fieldStats, List<Object>
literals) {
- return test(type, rowCount, fieldStats);
+/** Utils for testing with {@link FieldStats}. */
+public class FieldStatsUtils {
+
+ public static boolean test(Predicate predicate, long rowCount,
FieldStats[] fieldStats) {
+ Object[] min = new Object[fieldStats.length];
+ Object[] max = new Object[fieldStats.length];
+ Long[] nullCounts = new Long[fieldStats.length];
+ for (int i = 0; i < fieldStats.length; i++) {
+ min[i] = fieldStats[i].minValue();
+ max[i] = fieldStats[i].maxValue();
+ nullCounts[i] = fieldStats[i].nullCount();
+ }
+
+ return predicate.test(
+ rowCount,
+ GenericRow.of(min),
+ GenericRow.of(max),
+ BinaryArray.fromLongArray(nullCounts));
}
}
diff --git
a/paimon-common/src/test/java/org/apache/paimon/predicate/PredicateBuilderTest.java
b/paimon-common/src/test/java/org/apache/paimon/predicate/PredicateBuilderTest.java
index b88240333..8990c2427 100644
---
a/paimon-common/src/test/java/org/apache/paimon/predicate/PredicateBuilderTest.java
+++
b/paimon-common/src/test/java/org/apache/paimon/predicate/PredicateBuilderTest.java
@@ -27,6 +27,7 @@ import org.junit.jupiter.api.Test;
import java.util.Arrays;
+import static org.apache.paimon.predicate.FieldStatsUtils.test;
import static org.assertj.core.api.Assertions.assertThat;
/** Tests for {@link PredicateBuilder}. */
@@ -43,11 +44,12 @@ public class PredicateBuilderTest {
assertThat(predicate.test(GenericRow.of(4))).isEqualTo(false);
assertThat(predicate.test(GenericRow.of((Object)
null))).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(0, 5,
0L)})).isEqualTo(true);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(2, 5,
0L)})).isEqualTo(true);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(0, 2,
0L)})).isEqualTo(true);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(6, 7,
0L)})).isEqualTo(false);
- assertThat(predicate.test(1, new FieldStats[] {new FieldStats(null,
null, 1L)}))
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(0, 5,
0L)})).isEqualTo(true);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(2, 5,
0L)})).isEqualTo(true);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(0, 2,
0L)})).isEqualTo(true);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(6, 7,
0L)}))
+ .isEqualTo(false);
+ assertThat(test(predicate, 1, new FieldStats[] {new FieldStats(null,
null, 1L)}))
.isEqualTo(false);
}
@@ -62,11 +64,15 @@ public class PredicateBuilderTest {
assertThat(predicate.test(GenericRow.of(4))).isEqualTo(false);
assertThat(predicate.test(GenericRow.of((Object)
null))).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(0, 5,
0L)})).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(2, 5,
0L)})).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(0, 2,
0L)})).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(6, 7,
0L)})).isEqualTo(false);
- assertThat(predicate.test(1, new FieldStats[] {new FieldStats(null,
null, 1L)}))
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(0, 5,
0L)}))
+ .isEqualTo(false);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(2, 5,
0L)}))
+ .isEqualTo(false);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(0, 2,
0L)}))
+ .isEqualTo(false);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(6, 7,
0L)}))
+ .isEqualTo(false);
+ assertThat(test(predicate, 1, new FieldStats[] {new FieldStats(null,
null, 1L)}))
.isEqualTo(false);
}
diff --git
a/paimon-common/src/test/java/org/apache/paimon/predicate/PredicateTest.java
b/paimon-common/src/test/java/org/apache/paimon/predicate/PredicateTest.java
index ceac81b38..d449f55e4 100644
--- a/paimon-common/src/test/java/org/apache/paimon/predicate/PredicateTest.java
+++ b/paimon-common/src/test/java/org/apache/paimon/predicate/PredicateTest.java
@@ -29,6 +29,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import static org.apache.paimon.predicate.FieldStatsUtils.test;
import static org.assertj.core.api.Assertions.assertThat;
/** Test for {@link Predicate}s. */
@@ -43,10 +44,11 @@ public class PredicateTest {
assertThat(predicate.test(GenericRow.of(5))).isEqualTo(true);
assertThat(predicate.test(GenericRow.of((Object)
null))).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(0, 5,
0L)})).isEqualTo(true);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(0, 6,
0L)})).isEqualTo(true);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(6, 7,
0L)})).isEqualTo(false);
- assertThat(predicate.test(1, new FieldStats[] {new FieldStats(null,
null, 1L)}))
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(0, 5,
0L)})).isEqualTo(true);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(0, 6,
0L)})).isEqualTo(true);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(6, 7,
0L)}))
+ .isEqualTo(false);
+ assertThat(test(predicate, 1, new FieldStats[] {new FieldStats(null,
null, 1L)}))
.isEqualTo(false);
assertThat(predicate.negate().orElse(null)).isEqualTo(builder.notEqual(0, 5));
@@ -60,8 +62,9 @@ public class PredicateTest {
assertThat(predicate.test(GenericRow.of(4))).isEqualTo(false);
assertThat(predicate.test(GenericRow.of((Object)
null))).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(0, 5,
0L)})).isEqualTo(false);
- assertThat(predicate.test(1, new FieldStats[] {new FieldStats(null,
null, 1L)}))
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(0, 5,
0L)}))
+ .isEqualTo(false);
+ assertThat(test(predicate, 1, new FieldStats[] {new FieldStats(null,
null, 1L)}))
.isEqualTo(false);
}
@@ -74,11 +77,12 @@ public class PredicateTest {
assertThat(predicate.test(GenericRow.of(5))).isEqualTo(false);
assertThat(predicate.test(GenericRow.of((Object)
null))).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(0, 5,
0L)})).isEqualTo(true);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(0, 6,
0L)})).isEqualTo(true);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(6, 7,
0L)})).isEqualTo(true);
- assertThat(predicate.test(1, new FieldStats[] {new FieldStats(5, 5,
0L)})).isEqualTo(false);
- assertThat(predicate.test(1, new FieldStats[] {new FieldStats(null,
null, 1L)}))
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(0, 5,
0L)})).isEqualTo(true);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(0, 6,
0L)})).isEqualTo(true);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(6, 7,
0L)})).isEqualTo(true);
+ assertThat(test(predicate, 1, new FieldStats[] {new FieldStats(5, 5,
0L)}))
+ .isEqualTo(false);
+ assertThat(test(predicate, 1, new FieldStats[] {new FieldStats(null,
null, 1L)}))
.isEqualTo(false);
assertThat(predicate.negate().orElse(null)).isEqualTo(builder.equal(0,
5));
@@ -92,8 +96,9 @@ public class PredicateTest {
assertThat(predicate.test(GenericRow.of(4))).isEqualTo(false);
assertThat(predicate.test(GenericRow.of((Object)
null))).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(0, 5,
0L)})).isEqualTo(false);
- assertThat(predicate.test(1, new FieldStats[] {new FieldStats(null,
null, 1L)}))
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(0, 5,
0L)}))
+ .isEqualTo(false);
+ assertThat(test(predicate, 1, new FieldStats[] {new FieldStats(null,
null, 1L)}))
.isEqualTo(false);
}
@@ -107,11 +112,13 @@ public class PredicateTest {
assertThat(predicate.test(GenericRow.of(6))).isEqualTo(true);
assertThat(predicate.test(GenericRow.of((Object)
null))).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(0, 4,
0L)})).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(0, 5,
0L)})).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(0, 6,
0L)})).isEqualTo(true);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(6, 7,
0L)})).isEqualTo(true);
- assertThat(predicate.test(1, new FieldStats[] {new FieldStats(null,
null, 1L)}))
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(0, 4,
0L)}))
+ .isEqualTo(false);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(0, 5,
0L)}))
+ .isEqualTo(false);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(0, 6,
0L)})).isEqualTo(true);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(6, 7,
0L)})).isEqualTo(true);
+ assertThat(test(predicate, 1, new FieldStats[] {new FieldStats(null,
null, 1L)}))
.isEqualTo(false);
assertThat(predicate.negate().orElse(null)).isEqualTo(builder.lessOrEqual(0,
5));
@@ -125,8 +132,9 @@ public class PredicateTest {
assertThat(predicate.test(GenericRow.of(4))).isEqualTo(false);
assertThat(predicate.test(GenericRow.of((Object)
null))).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(0, 4,
0L)})).isEqualTo(false);
- assertThat(predicate.test(1, new FieldStats[] {new FieldStats(null,
null, 1L)}))
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(0, 4,
0L)}))
+ .isEqualTo(false);
+ assertThat(test(predicate, 1, new FieldStats[] {new FieldStats(null,
null, 1L)}))
.isEqualTo(false);
}
@@ -140,11 +148,12 @@ public class PredicateTest {
assertThat(predicate.test(GenericRow.of(6))).isEqualTo(true);
assertThat(predicate.test(GenericRow.of((Object)
null))).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(0, 4,
0L)})).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(0, 5,
0L)})).isEqualTo(true);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(0, 6,
0L)})).isEqualTo(true);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(6, 7,
0L)})).isEqualTo(true);
- assertThat(predicate.test(1, new FieldStats[] {new FieldStats(null,
null, 1L)}))
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(0, 4,
0L)}))
+ .isEqualTo(false);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(0, 5,
0L)})).isEqualTo(true);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(0, 6,
0L)})).isEqualTo(true);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(6, 7,
0L)})).isEqualTo(true);
+ assertThat(test(predicate, 1, new FieldStats[] {new FieldStats(null,
null, 1L)}))
.isEqualTo(false);
assertThat(predicate.negate().orElse(null)).isEqualTo(builder.lessThan(0, 5));
@@ -158,8 +167,9 @@ public class PredicateTest {
assertThat(predicate.test(GenericRow.of(4))).isEqualTo(false);
assertThat(predicate.test(GenericRow.of((Object)
null))).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(0, 4,
0L)})).isEqualTo(false);
- assertThat(predicate.test(1, new FieldStats[] {new FieldStats(null,
null, 1L)}))
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(0, 4,
0L)}))
+ .isEqualTo(false);
+ assertThat(test(predicate, 1, new FieldStats[] {new FieldStats(null,
null, 1L)}))
.isEqualTo(false);
}
@@ -173,10 +183,12 @@ public class PredicateTest {
assertThat(predicate.test(GenericRow.of(6))).isEqualTo(false);
assertThat(predicate.test(GenericRow.of((Object)
null))).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(6, 7,
0L)})).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(5, 7,
0L)})).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(4, 7,
0L)})).isEqualTo(true);
- assertThat(predicate.test(1, new FieldStats[] {new FieldStats(null,
null, 1L)}))
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(6, 7,
0L)}))
+ .isEqualTo(false);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(5, 7,
0L)}))
+ .isEqualTo(false);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(4, 7,
0L)})).isEqualTo(true);
+ assertThat(test(predicate, 1, new FieldStats[] {new FieldStats(null,
null, 1L)}))
.isEqualTo(false);
assertThat(predicate.negate().orElse(null)).isEqualTo(builder.greaterOrEqual(0,
5));
@@ -190,8 +202,9 @@ public class PredicateTest {
assertThat(predicate.test(GenericRow.of(4))).isEqualTo(false);
assertThat(predicate.test(GenericRow.of((Object)
null))).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(6, 7,
0L)})).isEqualTo(false);
- assertThat(predicate.test(1, new FieldStats[] {new FieldStats(null,
null, 1L)}))
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(6, 7,
0L)}))
+ .isEqualTo(false);
+ assertThat(test(predicate, 1, new FieldStats[] {new FieldStats(null,
null, 1L)}))
.isEqualTo(false);
}
@@ -205,10 +218,11 @@ public class PredicateTest {
assertThat(predicate.test(GenericRow.of(6))).isEqualTo(false);
assertThat(predicate.test(GenericRow.of((Object)
null))).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(6, 7,
0L)})).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(5, 7,
0L)})).isEqualTo(true);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(4, 7,
0L)})).isEqualTo(true);
- assertThat(predicate.test(1, new FieldStats[] {new FieldStats(null,
null, 1L)}))
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(6, 7,
0L)}))
+ .isEqualTo(false);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(5, 7,
0L)})).isEqualTo(true);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(4, 7,
0L)})).isEqualTo(true);
+ assertThat(test(predicate, 1, new FieldStats[] {new FieldStats(null,
null, 1L)}))
.isEqualTo(false);
assertThat(predicate.negate().orElse(null)).isEqualTo(builder.greaterThan(0,
5));
@@ -222,8 +236,9 @@ public class PredicateTest {
assertThat(predicate.test(GenericRow.of(4))).isEqualTo(false);
assertThat(predicate.test(GenericRow.of((Object)
null))).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(6, 7,
0L)})).isEqualTo(false);
- assertThat(predicate.test(1, new FieldStats[] {new FieldStats(null,
null, 1L)}))
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(6, 7,
0L)}))
+ .isEqualTo(false);
+ assertThat(test(predicate, 1, new FieldStats[] {new FieldStats(null,
null, 1L)}))
.isEqualTo(false);
}
@@ -235,8 +250,9 @@ public class PredicateTest {
assertThat(predicate.test(GenericRow.of(4))).isEqualTo(false);
assertThat(predicate.test(GenericRow.of((Object)
null))).isEqualTo(true);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(6, 7,
0L)})).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(5, 7,
1L)})).isEqualTo(true);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(6, 7,
0L)}))
+ .isEqualTo(false);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(5, 7,
1L)})).isEqualTo(true);
assertThat(predicate.negate().orElse(null)).isEqualTo(builder.isNotNull(0));
}
@@ -249,9 +265,9 @@ public class PredicateTest {
assertThat(predicate.test(GenericRow.of(4))).isEqualTo(true);
assertThat(predicate.test(GenericRow.of((Object)
null))).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(6, 7,
0L)})).isEqualTo(true);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(5, 7,
1L)})).isEqualTo(true);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(null,
null, 3L)}))
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(6, 7,
0L)})).isEqualTo(true);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(5, 7,
1L)})).isEqualTo(true);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(null,
null, 3L)}))
.isEqualTo(false);
assertThat(predicate.negate().orElse(null)).isEqualTo(builder.isNull(0));
@@ -268,9 +284,10 @@ public class PredicateTest {
assertThat(predicate.test(GenericRow.of(3))).isEqualTo(true);
assertThat(predicate.test(GenericRow.of((Object)
null))).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(0, 5,
0L)})).isEqualTo(true);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(6, 7,
0L)})).isEqualTo(false);
- assertThat(predicate.test(1, new FieldStats[] {new FieldStats(null,
null, 1L)}))
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(0, 5,
0L)})).isEqualTo(true);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(6, 7,
0L)}))
+ .isEqualTo(false);
+ assertThat(test(predicate, 1, new FieldStats[] {new FieldStats(null,
null, 1L)}))
.isEqualTo(false);
}
@@ -285,9 +302,10 @@ public class PredicateTest {
assertThat(predicate.test(GenericRow.of(3))).isEqualTo(true);
assertThat(predicate.test(GenericRow.of((Object)
null))).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(0, 5,
0L)})).isEqualTo(true);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(6, 7,
0L)})).isEqualTo(false);
- assertThat(predicate.test(1, new FieldStats[] {new FieldStats(null,
null, 1L)}))
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(0, 5,
0L)})).isEqualTo(true);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(6, 7,
0L)}))
+ .isEqualTo(false);
+ assertThat(test(predicate, 1, new FieldStats[] {new FieldStats(null,
null, 1L)}))
.isEqualTo(false);
}
@@ -302,12 +320,14 @@ public class PredicateTest {
assertThat(predicate.test(GenericRow.of(3))).isEqualTo(false);
assertThat(predicate.test(GenericRow.of((Object)
null))).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(1, 1,
0L)})).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(3, 3,
0L)})).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(1, 3,
0L)})).isEqualTo(true);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(0, 5,
0L)})).isEqualTo(true);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(6, 7,
0L)})).isEqualTo(true);
- assertThat(predicate.test(1, new FieldStats[] {new FieldStats(null,
null, 1L)}))
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(1, 1,
0L)}))
+ .isEqualTo(false);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(3, 3,
0L)}))
+ .isEqualTo(false);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(1, 3,
0L)})).isEqualTo(true);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(0, 5,
0L)})).isEqualTo(true);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(6, 7,
0L)})).isEqualTo(true);
+ assertThat(test(predicate, 1, new FieldStats[] {new FieldStats(null,
null, 1L)}))
.isEqualTo(false);
}
@@ -322,12 +342,17 @@ public class PredicateTest {
assertThat(predicate.test(GenericRow.of(3))).isEqualTo(false);
assertThat(predicate.test(GenericRow.of((Object)
null))).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(1, 1,
0L)})).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(3, 3,
0L)})).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(1, 3,
0L)})).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(0, 5,
0L)})).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(6, 7,
0L)})).isEqualTo(false);
- assertThat(predicate.test(1, new FieldStats[] {new FieldStats(null,
null, 1L)}))
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(1, 1,
0L)}))
+ .isEqualTo(false);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(3, 3,
0L)}))
+ .isEqualTo(false);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(1, 3,
0L)}))
+ .isEqualTo(false);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(0, 5,
0L)}))
+ .isEqualTo(false);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(6, 7,
0L)}))
+ .isEqualTo(false);
+ assertThat(test(predicate, 1, new FieldStats[] {new FieldStats(null,
null, 1L)}))
.isEqualTo(false);
}
@@ -348,11 +373,12 @@ public class PredicateTest {
assertThat(predicate.test(GenericRow.of(3))).isEqualTo(true);
assertThat(predicate.test(GenericRow.of((Object)
null))).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(0, 5,
0L)})).isEqualTo(true);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(6, 7,
0L)})).isEqualTo(false);
- assertThat(predicate.test(1, new FieldStats[] {new FieldStats(null,
null, 1L)}))
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(0, 5,
0L)})).isEqualTo(true);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(6, 7,
0L)}))
+ .isEqualTo(false);
+ assertThat(test(predicate, 1, new FieldStats[] {new FieldStats(null,
null, 1L)}))
.isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(29, 32,
0L)}))
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(29, 32,
0L)}))
.isEqualTo(true);
}
@@ -374,11 +400,12 @@ public class PredicateTest {
assertThat(predicate.test(GenericRow.of(3))).isEqualTo(true);
assertThat(predicate.test(GenericRow.of((Object)
null))).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(0, 5,
0L)})).isEqualTo(true);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(6, 7,
0L)})).isEqualTo(false);
- assertThat(predicate.test(1, new FieldStats[] {new FieldStats(null,
null, 1L)}))
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(0, 5,
0L)})).isEqualTo(true);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(6, 7,
0L)}))
.isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(29, 32,
0L)}))
+ assertThat(test(predicate, 1, new FieldStats[] {new FieldStats(null,
null, 1L)}))
+ .isEqualTo(false);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(29, 32,
0L)}))
.isEqualTo(true);
}
@@ -399,14 +426,16 @@ public class PredicateTest {
assertThat(predicate.test(GenericRow.of(3))).isEqualTo(false);
assertThat(predicate.test(GenericRow.of((Object)
null))).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(1, 1,
0L)})).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(3, 3,
0L)})).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(1, 3,
0L)})).isEqualTo(true);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(0, 5,
0L)})).isEqualTo(true);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(6, 7,
0L)})).isEqualTo(true);
- assertThat(predicate.test(1, new FieldStats[] {new FieldStats(null,
null, 1L)}))
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(1, 1,
0L)}))
+ .isEqualTo(false);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(3, 3,
0L)}))
.isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(29, 32,
0L)}))
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(1, 3,
0L)})).isEqualTo(true);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(0, 5,
0L)})).isEqualTo(true);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(6, 7,
0L)})).isEqualTo(true);
+ assertThat(test(predicate, 1, new FieldStats[] {new FieldStats(null,
null, 1L)}))
+ .isEqualTo(false);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(29, 32,
0L)}))
.isEqualTo(true);
}
@@ -428,14 +457,19 @@ public class PredicateTest {
assertThat(predicate.test(GenericRow.of(3))).isEqualTo(false);
assertThat(predicate.test(GenericRow.of((Object)
null))).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(1, 1,
0L)})).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(3, 3,
0L)})).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(1, 3,
0L)})).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(0, 5,
0L)})).isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(6, 7,
0L)})).isEqualTo(false);
- assertThat(predicate.test(1, new FieldStats[] {new FieldStats(null,
null, 1L)}))
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(1, 1,
0L)}))
+ .isEqualTo(false);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(3, 3,
0L)}))
+ .isEqualTo(false);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(1, 3,
0L)}))
+ .isEqualTo(false);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(0, 5,
0L)}))
+ .isEqualTo(false);
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(6, 7,
0L)}))
+ .isEqualTo(false);
+ assertThat(test(predicate, 1, new FieldStats[] {new FieldStats(null,
null, 1L)}))
.isEqualTo(false);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(29, 32,
0L)}))
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(29, 32,
0L)}))
.isEqualTo(false);
}
@@ -450,21 +484,24 @@ public class PredicateTest {
assertThat(predicate.test(GenericRow.of(null, 5))).isEqualTo(false);
assertThat(
- predicate.test(
+ test(
+ predicate,
3,
new FieldStats[] {
new FieldStats(3, 6, 0L), new
FieldStats(4, 6, 0L)
}))
.isEqualTo(true);
assertThat(
- predicate.test(
+ test(
+ predicate,
3,
new FieldStats[] {
new FieldStats(3, 6, 0L), new
FieldStats(6, 8, 0L)
}))
.isEqualTo(false);
assertThat(
- predicate.test(
+ test(
+ predicate,
3,
new FieldStats[] {
new FieldStats(6, 7, 0L), new
FieldStats(4, 6, 0L)
@@ -486,21 +523,24 @@ public class PredicateTest {
assertThat(predicate.test(GenericRow.of(null, 5))).isEqualTo(true);
assertThat(
- predicate.test(
+ test(
+ predicate,
3,
new FieldStats[] {
new FieldStats(3, 6, 0L), new
FieldStats(4, 6, 0L)
}))
.isEqualTo(true);
assertThat(
- predicate.test(
+ test(
+ predicate,
3,
new FieldStats[] {
new FieldStats(3, 6, 0L), new
FieldStats(6, 8, 0L)
}))
.isEqualTo(true);
assertThat(
- predicate.test(
+ test(
+ predicate,
3,
new FieldStats[] {
new FieldStats(6, 7, 0L), new
FieldStats(8, 10, 0L)
@@ -516,11 +556,11 @@ public class PredicateTest {
PredicateBuilder builder = new PredicateBuilder(RowType.of(new
IntType()));
Predicate predicate = builder.equal(0, 5);
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(null,
null, 3L)}))
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(null,
null, 3L)}))
.isEqualTo(false);
// unknown stats, we don't know, likely to hit
- assertThat(predicate.test(3, new FieldStats[] {new FieldStats(null,
null, 4L)}))
+ assertThat(test(predicate, 3, new FieldStats[] {new FieldStats(null,
null, 4L)}))
.isEqualTo(true);
}
diff --git a/paimon-core/src/main/java/org/apache/paimon/io/DataFileMeta.java
b/paimon-core/src/main/java/org/apache/paimon/io/DataFileMeta.java
index 41bceea49..0b1c5c50d 100644
--- a/paimon-core/src/main/java/org/apache/paimon/io/DataFileMeta.java
+++ b/paimon-core/src/main/java/org/apache/paimon/io/DataFileMeta.java
@@ -19,6 +19,7 @@
package org.apache.paimon.io;
import org.apache.paimon.CoreOptions;
+import org.apache.paimon.data.BinaryArray;
import org.apache.paimon.data.BinaryRow;
import org.apache.paimon.data.Timestamp;
import org.apache.paimon.fs.Path;
@@ -50,7 +51,7 @@ public class DataFileMeta {
// Append only data files don't have any key columns and meaningful level
value. it will use
// the following dummy values.
public static final BinaryTableStats EMPTY_KEY_STATS =
- new BinaryTableStats(EMPTY_ROW, EMPTY_ROW, new Long[0]);
+ new BinaryTableStats(EMPTY_ROW, EMPTY_ROW,
BinaryArray.fromLongArray(new Long[0]));
public static final BinaryRow EMPTY_MIN_KEY = EMPTY_ROW;
public static final BinaryRow EMPTY_MAX_KEY = EMPTY_ROW;
public static final int DUMMY_LEVEL = 0;
diff --git
a/paimon-core/src/main/java/org/apache/paimon/io/DataFileMetaSerializer.java
b/paimon-core/src/main/java/org/apache/paimon/io/DataFileMetaSerializer.java
index dad2bc973..a823b5791 100644
--- a/paimon-core/src/main/java/org/apache/paimon/io/DataFileMetaSerializer.java
+++ b/paimon-core/src/main/java/org/apache/paimon/io/DataFileMetaSerializer.java
@@ -46,8 +46,8 @@ public class DataFileMetaSerializer extends
ObjectSerializer<DataFileMeta> {
meta.rowCount(),
serializeBinaryRow(meta.minKey()),
serializeBinaryRow(meta.maxKey()),
- meta.keyStats().toRowData(),
- meta.valueStats().toRowData(),
+ meta.keyStats().toRow(),
+ meta.valueStats().toRow(),
meta.minSequenceNumber(),
meta.maxSequenceNumber(),
meta.schemaId(),
@@ -64,8 +64,8 @@ public class DataFileMetaSerializer extends
ObjectSerializer<DataFileMeta> {
row.getLong(2),
deserializeBinaryRow(row.getBinary(3)),
deserializeBinaryRow(row.getBinary(4)),
- BinaryTableStats.fromRowData(row.getRow(5, 3)),
- BinaryTableStats.fromRowData(row.getRow(6, 3)),
+ BinaryTableStats.fromRow(row.getRow(5, 3)),
+ BinaryTableStats.fromRow(row.getRow(6, 3)),
row.getLong(7),
row.getLong(8),
row.getLong(9),
diff --git
a/paimon-core/src/main/java/org/apache/paimon/manifest/ManifestFileMeta.java
b/paimon-core/src/main/java/org/apache/paimon/manifest/ManifestFileMeta.java
index b917e27fb..5910ad75f 100644
--- a/paimon-core/src/main/java/org/apache/paimon/manifest/ManifestFileMeta.java
+++ b/paimon-core/src/main/java/org/apache/paimon/manifest/ManifestFileMeta.java
@@ -281,14 +281,14 @@ public class ManifestFileMeta {
if (predicateOpt.isPresent()) {
Predicate predicate = predicateOpt.get();
- FieldStatsArraySerializer fieldStatsArraySerializer =
- new FieldStatsArraySerializer(partitionType);
for (; j < base.size(); j++) {
// TODO: optimize this to binary search.
ManifestFileMeta file = base.get(j);
if (predicate.test(
file.numAddedFiles + file.numDeletedFiles,
-
file.partitionStats.fields(fieldStatsArraySerializer))) {
+ file.partitionStats.minValues(),
+ file.partitionStats.maxValues(),
+ file.partitionStats.nullCounts())) {
break;
} else {
result.add(file);
diff --git
a/paimon-core/src/main/java/org/apache/paimon/manifest/ManifestFileMetaSerializer.java
b/paimon-core/src/main/java/org/apache/paimon/manifest/ManifestFileMetaSerializer.java
index bba5803a1..632644f85 100644
---
a/paimon-core/src/main/java/org/apache/paimon/manifest/ManifestFileMetaSerializer.java
+++
b/paimon-core/src/main/java/org/apache/paimon/manifest/ManifestFileMetaSerializer.java
@@ -45,7 +45,7 @@ public class ManifestFileMetaSerializer extends
VersionedObjectSerializer<Manife
meta.fileSize(),
meta.numAddedFiles(),
meta.numDeletedFiles(),
- meta.partitionStats().toRowData(),
+ meta.partitionStats().toRow(),
meta.schemaId());
}
@@ -65,7 +65,7 @@ public class ManifestFileMetaSerializer extends
VersionedObjectSerializer<Manife
row.getLong(1),
row.getLong(2),
row.getLong(3),
- BinaryTableStats.fromRowData(row.getRow(4, 3)),
+ BinaryTableStats.fromRow(row.getRow(4, 3)),
row.getLong(5));
}
}
diff --git
a/paimon-core/src/main/java/org/apache/paimon/operation/AbstractFileStoreScan.java
b/paimon-core/src/main/java/org/apache/paimon/operation/AbstractFileStoreScan.java
index 94a383f95..65857daed 100644
---
a/paimon-core/src/main/java/org/apache/paimon/operation/AbstractFileStoreScan.java
+++
b/paimon-core/src/main/java/org/apache/paimon/operation/AbstractFileStoreScan.java
@@ -33,7 +33,7 @@ import org.apache.paimon.partition.PartitionPredicate;
import org.apache.paimon.predicate.Predicate;
import org.apache.paimon.schema.SchemaManager;
import org.apache.paimon.schema.TableSchema;
-import org.apache.paimon.stats.FieldStatsArraySerializer;
+import org.apache.paimon.stats.BinaryTableStats;
import org.apache.paimon.table.source.ScanMode;
import org.apache.paimon.types.RowType;
import org.apache.paimon.utils.FileStorePathFactory;
@@ -61,7 +61,6 @@ import static
org.apache.paimon.utils.Preconditions.checkState;
/** Default implementation of {@link FileStoreScan}. */
public abstract class AbstractFileStoreScan implements FileStoreScan {
- private final FieldStatsArraySerializer partitionStatsConverter;
private final RowType partitionType;
private final SnapshotManager snapshotManager;
private final ManifestFile.Factory manifestFileFactory;
@@ -96,7 +95,6 @@ public abstract class AbstractFileStoreScan implements
FileStoreScan {
int numOfBuckets,
boolean checkNumOfBuckets,
Integer scanManifestParallelism) {
- this.partitionStatsConverter = new
FieldStatsArraySerializer(partitionType);
this.partitionType = partitionType;
this.bucketKeyFilter = bucketKeyFilter;
this.snapshotManager = snapshotManager;
@@ -379,10 +377,17 @@ public abstract class AbstractFileStoreScan implements
FileStoreScan {
/** Note: Keep this thread-safe. */
private boolean filterManifestFileMeta(ManifestFileMeta manifest) {
+ if (partitionFilter == null) {
+ return true;
+ }
+
+ BinaryTableStats stats = manifest.partitionStats();
return partitionFilter == null
|| partitionFilter.test(
manifest.numAddedFiles() + manifest.numDeletedFiles(),
-
manifest.partitionStats().fields(partitionStatsConverter));
+ stats.minValues(),
+ stats.maxValues(),
+ stats.nullCounts());
}
/** Note: Keep this thread-safe. */
diff --git
a/paimon-core/src/main/java/org/apache/paimon/operation/AppendOnlyFileStoreScan.java
b/paimon-core/src/main/java/org/apache/paimon/operation/AppendOnlyFileStoreScan.java
index c53966f0f..1cd7db0d2 100644
---
a/paimon-core/src/main/java/org/apache/paimon/operation/AppendOnlyFileStoreScan.java
+++
b/paimon-core/src/main/java/org/apache/paimon/operation/AppendOnlyFileStoreScan.java
@@ -24,6 +24,8 @@ import org.apache.paimon.manifest.ManifestFile;
import org.apache.paimon.manifest.ManifestList;
import org.apache.paimon.predicate.Predicate;
import org.apache.paimon.schema.SchemaManager;
+import org.apache.paimon.stats.BinaryTableStats;
+import org.apache.paimon.stats.FieldStatsArraySerializer;
import org.apache.paimon.stats.FieldStatsConverters;
import org.apache.paimon.types.RowType;
import org.apache.paimon.utils.SnapshotManager;
@@ -71,14 +73,18 @@ public class AppendOnlyFileStoreScan extends
AbstractFileStoreScan {
/** Note: Keep this thread-safe. */
@Override
protected boolean filterByStats(ManifestEntry entry) {
- return filter == null
- || filter.test(
- entry.file().rowCount(),
- entry.file()
- .valueStats()
- .fields(
-
fieldStatsConverters.getOrCreate(entry.file().schemaId()),
- entry.file().rowCount()));
+ if (filter == null) {
+ return true;
+ }
+
+ FieldStatsArraySerializer serializer =
+ fieldStatsConverters.getOrCreate(entry.file().schemaId());
+ BinaryTableStats stats = entry.file().valueStats();
+ return filter.test(
+ entry.file().rowCount(),
+ serializer.evolution(stats.minValues()),
+ serializer.evolution(stats.maxValues()),
+ serializer.evolution(stats.nullCounts(),
entry.file().rowCount()));
}
@Override
diff --git
a/paimon-core/src/main/java/org/apache/paimon/operation/KeyValueFileStoreScan.java
b/paimon-core/src/main/java/org/apache/paimon/operation/KeyValueFileStoreScan.java
index 0c9d4a872..d528e5e79 100644
---
a/paimon-core/src/main/java/org/apache/paimon/operation/KeyValueFileStoreScan.java
+++
b/paimon-core/src/main/java/org/apache/paimon/operation/KeyValueFileStoreScan.java
@@ -25,6 +25,8 @@ import org.apache.paimon.manifest.ManifestList;
import org.apache.paimon.predicate.Predicate;
import org.apache.paimon.schema.KeyValueFieldsExtractor;
import org.apache.paimon.schema.SchemaManager;
+import org.apache.paimon.stats.BinaryTableStats;
+import org.apache.paimon.stats.FieldStatsArraySerializer;
import org.apache.paimon.stats.FieldStatsConverters;
import org.apache.paimon.types.RowType;
import org.apache.paimon.utils.SnapshotManager;
@@ -84,15 +86,18 @@ public class KeyValueFileStoreScan extends
AbstractFileStoreScan {
/** Note: Keep this thread-safe. */
@Override
protected boolean filterByStats(ManifestEntry entry) {
- return keyFilter == null
- || keyFilter.test(
- entry.file().rowCount(),
- entry.file()
- .keyStats()
- .fields(
- fieldKeyStatsConverters.getOrCreate(
- entry.file().schemaId()),
- entry.file().rowCount()));
+ if (keyFilter == null) {
+ return true;
+ }
+
+ FieldStatsArraySerializer serializer =
+ fieldKeyStatsConverters.getOrCreate(entry.file().schemaId());
+ BinaryTableStats stats = entry.file().keyStats();
+ return keyFilter.test(
+ entry.file().rowCount(),
+ serializer.evolution(stats.minValues()),
+ serializer.evolution(stats.maxValues()),
+ serializer.evolution(stats.nullCounts(),
entry.file().rowCount()));
}
/** Note: Keep this thread-safe. */
@@ -102,14 +107,14 @@ public class KeyValueFileStoreScan extends
AbstractFileStoreScan {
// the bucket.
if (valueFilter != null) {
for (ManifestEntry entry : entries) {
+ FieldStatsArraySerializer serializer =
+
fieldValueStatsConverters.getOrCreate(entry.file().schemaId());
+ BinaryTableStats stats = entry.file().valueStats();
if (valueFilter.test(
entry.file().rowCount(),
- entry.file()
- .valueStats()
- .fields(
- fieldValueStatsConverters.getOrCreate(
- entry.file().schemaId()),
- entry.file().rowCount()))) {
+ serializer.evolution(stats.minValues()),
+ serializer.evolution(stats.maxValues()),
+ serializer.evolution(stats.nullCounts(),
entry.file().rowCount()))) {
return true;
}
}
diff --git
a/paimon-core/src/main/java/org/apache/paimon/partition/PartitionPredicate.java
b/paimon-core/src/main/java/org/apache/paimon/partition/PartitionPredicate.java
index 2748ef40b..b0a89e29e 100644
---
a/paimon-core/src/main/java/org/apache/paimon/partition/PartitionPredicate.java
+++
b/paimon-core/src/main/java/org/apache/paimon/partition/PartitionPredicate.java
@@ -19,6 +19,8 @@
package org.apache.paimon.partition;
import org.apache.paimon.data.BinaryRow;
+import org.apache.paimon.data.InternalArray;
+import org.apache.paimon.data.InternalRow;
import org.apache.paimon.data.serializer.InternalSerializers;
import org.apache.paimon.data.serializer.Serializer;
import org.apache.paimon.format.FieldStats;
@@ -37,7 +39,8 @@ public interface PartitionPredicate {
boolean test(BinaryRow part);
- boolean test(long rowCount, FieldStats[] fieldStats);
+ boolean test(
+ long rowCount, InternalRow minValues, InternalRow maxValues,
InternalArray nullCounts);
static PartitionPredicate fromPredicate(Predicate predicate) {
return new DefaultPartitionPredicate(predicate);
@@ -63,8 +66,12 @@ public interface PartitionPredicate {
}
@Override
- public boolean test(long rowCount, FieldStats[] fieldStats) {
- return predicate.test(rowCount, fieldStats);
+ public boolean test(
+ long rowCount,
+ InternalRow minValues,
+ InternalRow maxValues,
+ InternalArray nullCounts) {
+ return predicate.test(rowCount, minValues, maxValues, nullCounts);
}
}
@@ -75,7 +82,7 @@ public interface PartitionPredicate {
class MultiplePartitionPredicate implements PartitionPredicate {
private final Set<BinaryRow> partitions;
-
+ private final int fieldNum;
private final Predicate[] min;
private final Predicate[] max;
@@ -83,7 +90,7 @@ public interface PartitionPredicate {
RowDataToObjectArrayConverter converter, Set<BinaryRow>
partitions) {
this.partitions = partitions;
RowType partitionType = converter.rowType();
- int fieldNum = partitionType.getFieldCount();
+ this.fieldNum = partitionType.getFieldCount();
@SuppressWarnings("unchecked")
Serializer<Object>[] serializers = new Serializer[fieldNum];
FullFieldStatsCollector[] collectors = new
FullFieldStatsCollector[fieldNum];
@@ -113,13 +120,18 @@ public interface PartitionPredicate {
}
@Override
- public boolean test(long rowCount, FieldStats[] fieldStats) {
- if (fieldStats.length == 0) {
+ public boolean test(
+ long rowCount,
+ InternalRow minValues,
+ InternalRow maxValues,
+ InternalArray nullCounts) {
+ if (fieldNum == 0) {
return true;
}
- for (int i = 0; i < fieldStats.length; i++) {
- if (!min[i].test(rowCount, fieldStats) ||
!max[i].test(rowCount, fieldStats)) {
+ for (int i = 0; i < fieldNum; i++) {
+ if (!min[i].test(rowCount, minValues, maxValues, nullCounts)
+ || !max[i].test(rowCount, minValues, maxValues,
nullCounts)) {
return false;
}
}
diff --git
a/paimon-core/src/main/java/org/apache/paimon/schema/SchemaEvolutionUtil.java
b/paimon-core/src/main/java/org/apache/paimon/schema/SchemaEvolutionUtil.java
index ad119f772..8fa41bebf 100644
---
a/paimon-core/src/main/java/org/apache/paimon/schema/SchemaEvolutionUtil.java
+++
b/paimon-core/src/main/java/org/apache/paimon/schema/SchemaEvolutionUtil.java
@@ -139,12 +139,17 @@ public class SchemaEvolutionUtil {
List<DataField> tableFields,
int[] dataProjection,
List<DataField> dataFields) {
- List<DataField> tableProjectFields =
projectDataFields(tableProjection, tableFields);
- List<DataField> dataProjectFields = projectDataFields(dataProjection,
dataFields);
+ return createIndexCastMapping(
+ projectDataFields(tableProjection, tableFields),
+ projectDataFields(dataProjection, dataFields));
+ }
- int[] indexMapping = createIndexMapping(tableProjectFields,
dataProjectFields);
+ /** Create index mapping from table fields to underlying data fields. */
+ public static IndexCastMapping createIndexCastMapping(
+ List<DataField> tableFields, List<DataField> dataFields) {
+ int[] indexMapping = createIndexMapping(tableFields, dataFields);
CastFieldGetter[] castMapping =
- createCastFieldGetterMapping(tableProjectFields,
dataProjectFields, indexMapping);
+ createCastFieldGetterMapping(tableFields, dataFields,
indexMapping);
return new IndexCastMapping() {
@Nullable
@Override
diff --git
a/paimon-core/src/main/java/org/apache/paimon/stats/BinaryTableStats.java
b/paimon-core/src/main/java/org/apache/paimon/stats/BinaryTableStats.java
index 7923b0a4b..89bf9704b 100644
--- a/paimon-core/src/main/java/org/apache/paimon/stats/BinaryTableStats.java
+++ b/paimon-core/src/main/java/org/apache/paimon/stats/BinaryTableStats.java
@@ -18,101 +18,52 @@
package org.apache.paimon.stats;
+import org.apache.paimon.data.BinaryArray;
import org.apache.paimon.data.BinaryRow;
-import org.apache.paimon.data.GenericArray;
import org.apache.paimon.data.GenericRow;
-import org.apache.paimon.data.InternalArray;
import org.apache.paimon.data.InternalRow;
import org.apache.paimon.format.FieldStats;
-import javax.annotation.Nullable;
-
-import java.util.Arrays;
import java.util.Objects;
-import static org.apache.paimon.utils.Preconditions.checkNotNull;
import static org.apache.paimon.utils.SerializationUtils.deserializeBinaryRow;
import static org.apache.paimon.utils.SerializationUtils.serializeBinaryRow;
/** A serialized row bytes to cache {@link FieldStats}. */
public class BinaryTableStats {
- @Nullable private InternalRow row;
- @Nullable private FieldStats[] cacheArray;
- @Nullable private BinaryRow cacheMin;
- @Nullable private BinaryRow cacheMax;
- @Nullable private Long[] cacheNullCounts;
-
- public BinaryTableStats(InternalRow row) {
- this.row = row;
- }
+ private final BinaryRow minValues;
+ private final BinaryRow maxValues;
+ private final BinaryArray nullCounts;
- public BinaryTableStats(BinaryRow cacheMin, BinaryRow cacheMax, Long[]
cacheNullCounts) {
- this(cacheMin, cacheMax, cacheNullCounts, null);
+ public BinaryTableStats(BinaryRow minValues, BinaryRow maxValues,
BinaryArray nullCounts) {
+ this.minValues = minValues;
+ this.maxValues = maxValues;
+ this.nullCounts = nullCounts;
}
- public BinaryTableStats(
- BinaryRow cacheMin,
- BinaryRow cacheMax,
- Long[] cacheNullCounts,
- @Nullable FieldStats[] cacheArray) {
- this.cacheMin = cacheMin;
- this.cacheMax = cacheMax;
- this.cacheNullCounts = cacheNullCounts;
- this.cacheArray = cacheArray;
+ public BinaryRow minValues() {
+ return minValues;
}
- public FieldStats[] fields(FieldStatsArraySerializer converter) {
- return fields(converter, null);
+ public BinaryRow maxValues() {
+ return maxValues;
}
- public FieldStats[] fields(FieldStatsArraySerializer converter, @Nullable
Long rowCount) {
- if (cacheArray == null) {
- cacheArray = converter.fromBinary(this, rowCount);
- }
- return cacheArray;
- }
-
- public BinaryRow min() {
- if (cacheMin == null) {
- checkNotNull(row);
- cacheMin = deserializeBinaryRow(this.row.getBinary(0));
- }
- return cacheMin;
- }
-
- public BinaryRow max() {
- if (cacheMax == null) {
- checkNotNull(row);
- cacheMax = deserializeBinaryRow(this.row.getBinary(1));
- }
- return cacheMax;
- }
-
- public Long[] nullCounts() {
- if (cacheNullCounts == null) {
- checkNotNull(row);
- InternalArray internalArray = row.getArray(2);
- Long[] array = new Long[internalArray.size()];
- for (int i = 0; i < array.length; i++) {
- array[i] = internalArray.isNullAt(i) ? null :
internalArray.getLong(i);
- }
- return array;
- }
- return cacheNullCounts;
+ public BinaryArray nullCounts() {
+ return nullCounts;
}
- public InternalRow toRowData() {
- return row == null
- ? GenericRow.of(
- serializeBinaryRow(min()),
- serializeBinaryRow(max()),
- new GenericArray(nullCounts()))
- : row;
+ public InternalRow toRow() {
+ return GenericRow.of(
+ serializeBinaryRow(minValues), serializeBinaryRow(maxValues),
nullCounts);
}
- public static BinaryTableStats fromRowData(InternalRow row) {
- return new BinaryTableStats(row);
+ public static BinaryTableStats fromRow(InternalRow row) {
+ return new BinaryTableStats(
+ deserializeBinaryRow(row.getBinary(0)),
+ deserializeBinaryRow(row.getBinary(1)),
+ BinaryArray.fromLongArray(row.getArray(2)));
}
@Override
@@ -124,15 +75,13 @@ public class BinaryTableStats {
return false;
}
BinaryTableStats that = (BinaryTableStats) o;
- return Objects.equals(min(), that.min())
- && Objects.equals(max(), that.max())
- && Arrays.equals(nullCounts(), that.nullCounts());
+ return Objects.equals(minValues, that.minValues)
+ && Objects.equals(maxValues, that.maxValues)
+ && Objects.equals(nullCounts, that.nullCounts);
}
@Override
public int hashCode() {
- int result = Objects.hash(min(), max());
- result = 31 * result + Arrays.hashCode(nullCounts());
- return result;
+ return Objects.hash(minValues, maxValues, nullCounts);
}
}
diff --git
a/paimon-core/src/main/java/org/apache/paimon/stats/FieldStatsArraySerializer.java
b/paimon-core/src/main/java/org/apache/paimon/stats/FieldStatsArraySerializer.java
index 17db3a53e..0d830f551 100644
---
a/paimon-core/src/main/java/org/apache/paimon/stats/FieldStatsArraySerializer.java
+++
b/paimon-core/src/main/java/org/apache/paimon/stats/FieldStatsArraySerializer.java
@@ -19,8 +19,17 @@
package org.apache.paimon.stats;
import org.apache.paimon.casting.CastExecutor;
+import org.apache.paimon.casting.CastFieldGetter;
+import org.apache.paimon.casting.CastedRow;
+import org.apache.paimon.data.BinaryArray;
+import org.apache.paimon.data.BinaryRow;
+import org.apache.paimon.data.BinaryString;
+import org.apache.paimon.data.Decimal;
import org.apache.paimon.data.GenericRow;
+import org.apache.paimon.data.InternalArray;
+import org.apache.paimon.data.InternalMap;
import org.apache.paimon.data.InternalRow;
+import org.apache.paimon.data.Timestamp;
import org.apache.paimon.data.serializer.InternalRowSerializer;
import org.apache.paimon.format.FieldStats;
import org.apache.paimon.types.ArrayType;
@@ -29,6 +38,7 @@ import org.apache.paimon.types.DataField;
import org.apache.paimon.types.DataType;
import org.apache.paimon.types.RowType;
import org.apache.paimon.utils.InternalRowUtils;
+import org.apache.paimon.utils.ProjectedRow;
import javax.annotation.Nullable;
@@ -47,13 +57,17 @@ public class FieldStatsArraySerializer {
@Nullable private final int[] indexMapping;
@Nullable private final CastExecutor<Object, Object>[] converterMapping;
+ @Nullable private final CastFieldGetter[] castFieldGetters;
public FieldStatsArraySerializer(RowType type) {
- this(type, null, null);
+ this(type, null, null, null);
}
public FieldStatsArraySerializer(
- RowType type, int[] indexMapping, CastExecutor<Object, Object>[]
converterMapping) {
+ RowType type,
+ @Nullable int[] indexMapping,
+ @Nullable CastExecutor<Object, Object>[] converterMapping,
+ @Nullable CastFieldGetter[] castFieldGetters) {
RowType safeType = toAllFieldsNullableRowType(type);
this.serializer = new InternalRowSerializer(safeType);
this.fieldGetters =
@@ -65,6 +79,7 @@ public class FieldStatsArraySerializer {
.toArray(InternalRow.FieldGetter[]::new);
this.indexMapping = indexMapping;
this.converterMapping = converterMapping;
+ this.castFieldGetters = castFieldGetters;
}
public BinaryTableStats toBinary(FieldStats[] stats) {
@@ -80,8 +95,7 @@ public class FieldStatsArraySerializer {
return new BinaryTableStats(
serializer.toBinaryRow(minValues).copy(),
serializer.toBinaryRow(maxValues).copy(),
- nullCounts,
- stats);
+ BinaryArray.fromLongArray(nullCounts));
}
public FieldStats[] fromBinary(BinaryTableStats array) {
@@ -91,10 +105,10 @@ public class FieldStatsArraySerializer {
public FieldStats[] fromBinary(BinaryTableStats array, @Nullable Long
rowCount) {
int fieldCount = indexMapping == null ? fieldGetters.length :
indexMapping.length;
FieldStats[] stats = new FieldStats[fieldCount];
- Long[] nullCounts = array.nullCounts();
+ BinaryArray nullCounts = array.nullCounts();
for (int i = 0; i < fieldCount; i++) {
int fieldIndex = indexMapping == null ? i : indexMapping[i];
- if (fieldIndex < 0 || fieldIndex >= array.min().getFieldCount()) {
+ if (fieldIndex < 0 || fieldIndex >=
array.minValues().getFieldCount()) {
// simple evolution for add column
if (rowCount == null) {
throw new RuntimeException("Schema Evolution for stats
needs row count.");
@@ -103,18 +117,49 @@ public class FieldStatsArraySerializer {
} else {
CastExecutor<Object, Object> converter =
converterMapping == null ? null : converterMapping[i];
- Object min =
fieldGetters[fieldIndex].getFieldOrNull(array.min());
+ Object min =
fieldGetters[fieldIndex].getFieldOrNull(array.minValues());
min = converter == null || min == null ? min :
converter.cast(min);
- Object max =
fieldGetters[fieldIndex].getFieldOrNull(array.max());
+ Object max =
fieldGetters[fieldIndex].getFieldOrNull(array.maxValues());
max = converter == null || max == null ? max :
converter.cast(max);
- stats[i] = new FieldStats(min, max, nullCounts[fieldIndex]);
+ stats[i] =
+ new FieldStats(
+ min,
+ max,
+ nullCounts.isNullAt(fieldIndex)
+ ? null
+ : nullCounts.getLong(fieldIndex));
}
}
return stats;
}
+ public InternalRow evolution(BinaryRow values) {
+ InternalRow row = values;
+ if (indexMapping != null) {
+ row = ProjectedRow.from(indexMapping).replaceRow(row);
+ }
+
+ if (castFieldGetters != null) {
+ row = CastedRow.from(castFieldGetters).replaceRow(values);
+ }
+
+ return row;
+ }
+
+ public InternalArray evolution(BinaryArray nullCounts, @Nullable Long
rowCount) {
+ if (indexMapping == null) {
+ return nullCounts;
+ }
+
+ if (rowCount == null) {
+ throw new RuntimeException("Schema Evolution for stats needs row
count.");
+ }
+
+ return new NullCountsEvoArray(indexMapping, nullCounts, rowCount);
+ }
+
public static RowType schema() {
List<DataField> fields = new ArrayList<>();
fields.add(new DataField(0, "_MIN_VALUES", newBytesType(false)));
@@ -134,4 +179,155 @@ public class FieldStatsArraySerializer {
rowType.getFieldNames().toArray(new String[0]))
.build();
}
+
+ private static class NullCountsEvoArray implements InternalArray {
+
+ private final int[] indexMapping;
+ private final InternalArray array;
+ private final long notFoundValue;
+
+ protected NullCountsEvoArray(int[] indexMapping, InternalArray array,
long notFoundValue) {
+ this.indexMapping = indexMapping;
+ this.array = array;
+ this.notFoundValue = notFoundValue;
+ }
+
+ @Override
+ public int size() {
+ return indexMapping.length;
+ }
+
+ @Override
+ public boolean isNullAt(int pos) {
+ if (indexMapping[pos] < 0) {
+ return false;
+ }
+ return array.isNullAt(indexMapping[pos]);
+ }
+
+ @Override
+ public long getLong(int pos) {
+ if (indexMapping[pos] < 0) {
+ return notFoundValue;
+ }
+ return array.getLong(indexMapping[pos]);
+ }
+
+ // ============================= Unsupported Methods
================================
+
+ @Override
+ public boolean getBoolean(int pos) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public byte getByte(int pos) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public short getShort(int pos) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getInt(int pos) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public float getFloat(int pos) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public double getDouble(int pos) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public BinaryString getString(int pos) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Decimal getDecimal(int pos, int precision, int scale) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Timestamp getTimestamp(int pos, int precision) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public byte[] getBinary(int pos) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public InternalArray getArray(int pos) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public InternalMap getMap(int pos) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public InternalRow getRow(int pos, int numFields) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int hashCode() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String toString() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean[] toBooleanArray() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public byte[] toByteArray() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public short[] toShortArray() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int[] toIntArray() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long[] toLongArray() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public float[] toFloatArray() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public double[] toDoubleArray() {
+ throw new UnsupportedOperationException();
+ }
+ }
}
diff --git
a/paimon-core/src/main/java/org/apache/paimon/stats/FieldStatsConverters.java
b/paimon-core/src/main/java/org/apache/paimon/stats/FieldStatsConverters.java
index b02772763..9c5f421ac 100644
---
a/paimon-core/src/main/java/org/apache/paimon/stats/FieldStatsConverters.java
+++
b/paimon-core/src/main/java/org/apache/paimon/stats/FieldStatsConverters.java
@@ -19,16 +19,21 @@
package org.apache.paimon.stats;
import org.apache.paimon.casting.CastExecutor;
+import org.apache.paimon.schema.IndexCastMapping;
import org.apache.paimon.schema.SchemaEvolutionUtil;
import org.apache.paimon.types.DataField;
import org.apache.paimon.types.RowType;
+import javax.annotation.Nullable;
+
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
+import static
org.apache.paimon.schema.SchemaEvolutionUtil.createIndexCastMapping;
+
/** Converters to create field stats array serializer. */
public class FieldStatsConverters {
private final Function<Long, List<DataField>> schemaFields;
@@ -57,15 +62,19 @@ public class FieldStatsConverters {
List<DataField> schemaTableFields =
tableFields.updateAndGet(v -> v == null ?
tableDataFields : v);
List<DataField> dataFields = schemaFields.apply(id);
- int[] indexMapping =
-
SchemaEvolutionUtil.createIndexMapping(schemaTableFields, dataFields);
+ IndexCastMapping indexCastMapping =
+ createIndexCastMapping(schemaTableFields,
dataFields);
+ @Nullable int[] indexMapping =
indexCastMapping.getIndexMapping();
CastExecutor<Object, Object>[] castExecutors =
(CastExecutor<Object, Object>[])
SchemaEvolutionUtil.createConvertMapping(
schemaTableFields, dataFields,
indexMapping);
// Create field stats array serializer with schema
evolution
return new FieldStatsArraySerializer(
- new RowType(dataFields), indexMapping,
castExecutors);
+ new RowType(dataFields),
+ indexMapping,
+ castExecutors,
+ indexCastMapping.getCastMapping());
});
}
diff --git
a/paimon-core/src/main/java/org/apache/paimon/table/system/FilesTable.java
b/paimon-core/src/main/java/org/apache/paimon/table/system/FilesTable.java
index f0508bda8..0949de2df 100644
--- a/paimon-core/src/main/java/org/apache/paimon/table/system/FilesTable.java
+++ b/paimon-core/src/main/java/org/apache/paimon/table/system/FilesTable.java
@@ -372,7 +372,7 @@ public class FilesTable implements ReadonlyTable {
fieldStatsConverters.getOrCreate(file.schemaId());
// Create value stats
FieldStats[] fieldStatsArray =
- tableStats.fields(fieldStatsArraySerializer,
file.rowCount());
+ fieldStatsArraySerializer.fromBinary(tableStats,
file.rowCount());
lazyNullValueCounts = new TreeMap<>();
lazyLowerValueBounds = new TreeMap<>();
lazyUpperValueBounds = new TreeMap<>();
diff --git
a/paimon-core/src/main/java/org/apache/paimon/utils/BulkFormatMapping.java
b/paimon-core/src/main/java/org/apache/paimon/utils/BulkFormatMapping.java
index 04a47c65b..36aeb6d6f 100644
--- a/paimon-core/src/main/java/org/apache/paimon/utils/BulkFormatMapping.java
+++ b/paimon-core/src/main/java/org/apache/paimon/utils/BulkFormatMapping.java
@@ -44,7 +44,7 @@ public class BulkFormatMapping {
private final FormatReaderFactory bulkFormat;
public BulkFormatMapping(
- int[] indexMapping,
+ @Nullable int[] indexMapping,
@Nullable CastFieldGetter[] castMapping,
@Nullable Pair<int[], RowType> partitionPair,
FormatReaderFactory bulkFormat) {
diff --git
a/paimon-core/src/test/java/org/apache/paimon/append/AppendOnlyWriterTest.java
b/paimon-core/src/test/java/org/apache/paimon/append/AppendOnlyWriterTest.java
index e18eaf066..163ba3bec 100644
---
a/paimon-core/src/test/java/org/apache/paimon/append/AppendOnlyWriterTest.java
+++
b/paimon-core/src/test/java/org/apache/paimon/append/AppendOnlyWriterTest.java
@@ -567,15 +567,20 @@ public class AppendOnlyWriterTest {
STATS_SERIALIZER.toBinary(
new FieldStats[] {
initStats(
-
toCompact.get(0).valueStats().min().getInt(0),
- toCompact.get(size -
1).valueStats().max().getInt(0),
+
toCompact.get(0).valueStats().minValues().getInt(0),
+ toCompact.get(size -
1).valueStats().maxValues().getInt(0),
0),
initStats(
-
toCompact.get(0).valueStats().min().getString(1).toString(),
+ toCompact
+ .get(0)
+ .valueStats()
+ .minValues()
+ .getString(1)
+ .toString(),
toCompact
.get(size - 1)
.valueStats()
- .max()
+ .maxValues()
.getString(1)
.toString(),
0),
diff --git
a/paimon-core/src/test/java/org/apache/paimon/manifest/ManifestFileTest.java
b/paimon-core/src/test/java/org/apache/paimon/manifest/ManifestFileTest.java
index 5be026b7c..cdd16a377 100644
--- a/paimon-core/src/test/java/org/apache/paimon/manifest/ManifestFileTest.java
+++ b/paimon-core/src/test/java/org/apache/paimon/manifest/ManifestFileTest.java
@@ -19,6 +19,7 @@
package org.apache.paimon.manifest;
import org.apache.paimon.CoreOptions;
+import org.apache.paimon.format.FieldStats;
import org.apache.paimon.format.FileFormat;
import org.apache.paimon.fs.FileIO;
import org.apache.paimon.fs.FileIOFinder;
@@ -26,6 +27,7 @@ import org.apache.paimon.fs.Path;
import org.apache.paimon.fs.local.LocalFileIO;
import org.apache.paimon.options.Options;
import org.apache.paimon.schema.SchemaManager;
+import org.apache.paimon.stats.FieldStatsArraySerializer;
import org.apache.paimon.stats.StatsTestUtils;
import org.apache.paimon.utils.FailingFileIO;
import org.apache.paimon.utils.FileStorePathFactory;
@@ -128,12 +130,14 @@ public class ManifestFileTest {
.isEqualTo(expected.numDeletedFiles());
// check stats
- for (int i = 0; i < expected.partitionStats().fields(null).length;
i++) {
+ FieldStatsArraySerializer statsConverter = new
FieldStatsArraySerializer(DEFAULT_PART_TYPE);
+ FieldStats[] fieldStats =
statsConverter.fromBinary(expected.partitionStats());
+ for (int i = 0; i < fieldStats.length; i++) {
int idx = i;
StatsTestUtils.checkRollingFileStats(
- expected.partitionStats().fields(null)[i],
+ fieldStats[i],
actual,
- meta -> meta.partitionStats().fields(null)[idx]);
+ meta ->
statsConverter.fromBinary(meta.partitionStats())[idx]);
}
}
}
diff --git
a/paimon-core/src/test/java/org/apache/paimon/partition/PartitionPredicateTest.java
b/paimon-core/src/test/java/org/apache/paimon/partition/PartitionPredicateTest.java
index 68a1a0265..f43610f71 100644
---
a/paimon-core/src/test/java/org/apache/paimon/partition/PartitionPredicateTest.java
+++
b/paimon-core/src/test/java/org/apache/paimon/partition/PartitionPredicateTest.java
@@ -18,8 +18,10 @@
package org.apache.paimon.partition;
+import org.apache.paimon.data.BinaryArray;
import org.apache.paimon.data.BinaryRow;
import org.apache.paimon.data.BinaryRowWriter;
+import org.apache.paimon.data.GenericRow;
import org.apache.paimon.format.FieldStats;
import org.apache.paimon.predicate.Predicate;
import org.apache.paimon.predicate.PredicateBuilder;
@@ -45,7 +47,8 @@ public class PartitionPredicateTest {
PartitionPredicate.fromMultiple(RowType.of(),
Collections.singletonList(EMPTY_ROW));
assertThat(predicate.test(EMPTY_ROW)).isTrue();
- assertThat(predicate.test(1, new FieldStats[] {})).isTrue();
+ assertThat(predicate.test(1, EMPTY_ROW, EMPTY_ROW,
BinaryArray.fromLongArray(new Long[0])))
+ .isTrue();
}
@Test
@@ -150,7 +153,16 @@ public class PartitionPredicateTest {
}
private boolean validate(PartitionPredicate predicate, FieldStats[]
fieldStats) {
- return predicate.test(3, fieldStats);
+ Object[] min = new Object[fieldStats.length];
+ Object[] max = new Object[fieldStats.length];
+ Long[] nullCounts = new Long[fieldStats.length];
+ for (int i = 0; i < fieldStats.length; i++) {
+ min[i] = fieldStats[i].minValue();
+ max[i] = fieldStats[i].maxValue();
+ nullCounts[i] = fieldStats[i].nullCount();
+ }
+ return predicate.test(
+ 3, GenericRow.of(min), GenericRow.of(max),
BinaryArray.fromLongArray(nullCounts));
}
private static BinaryRow createPart(int i, int j) {
diff --git
a/paimon-core/src/test/java/org/apache/paimon/stats/BinaryTableStatsTest.java
b/paimon-core/src/test/java/org/apache/paimon/stats/BinaryTableStatsTest.java
deleted file mode 100644
index f4e0826e7..000000000
---
a/paimon-core/src/test/java/org/apache/paimon/stats/BinaryTableStatsTest.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.paimon.stats;
-
-import org.apache.paimon.data.BinaryRow;
-import org.apache.paimon.data.BinaryRowWriter;
-import org.apache.paimon.data.InternalRow;
-import org.apache.paimon.format.FieldStats;
-import org.apache.paimon.types.IntType;
-import org.apache.paimon.types.RowType;
-
-import org.junit.jupiter.api.Test;
-
-import java.util.Arrays;
-import java.util.List;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-/** Tests for {@link BinaryTableStats}. */
-public class BinaryTableStatsTest {
- @Test
- public void testBinaryTableStats() {
- List<Integer> minList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
- List<Integer> maxList = Arrays.asList(11, 12, 13, 14, 15, 16, 17, 18,
19);
- Long[] nullCounts = new Long[] {0L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L};
-
- BinaryRow minRowData = binaryRow(minList);
- BinaryRow maxRowData = binaryRow(maxList);
- BinaryTableStats tableStats1 = new BinaryTableStats(minRowData,
maxRowData, nullCounts);
-
- InternalRow rowData = tableStats1.toRowData();
- BinaryTableStats tableStats2 = new BinaryTableStats(rowData);
- assertThat(tableStats1.min()).isEqualTo(tableStats2.min());
- assertThat(tableStats1.max()).isEqualTo(tableStats2.max());
-
assertThat(tableStats1.nullCounts()).isEqualTo(tableStats2.nullCounts());
- assertThat(tableStats1).isEqualTo(tableStats2);
-
- FieldStatsArraySerializer serializer =
- new FieldStatsArraySerializer(
- RowType.of(
- new IntType(),
- new IntType(),
- new IntType(),
- new IntType(),
- new IntType(),
- new IntType(),
- new IntType(),
- new IntType(),
- new IntType()));
-
- FieldStats[] fieldStatsArray1 = tableStats1.fields(serializer, 100L);
- FieldStats[] fieldStatsArray2 = tableStats2.fields(serializer, 100L);
-
assertThat(fieldStatsArray1.length).isEqualTo(fieldStatsArray2.length).isEqualTo(9);
- assertThat(fieldStatsArray1).isEqualTo(fieldStatsArray2);
- for (int i = 0; i < fieldStatsArray1.length; i++) {
- FieldStats fieldStats = fieldStatsArray1[i];
- assertThat(fieldStats.minValue()).isEqualTo(1 + i);
- assertThat(fieldStats.maxValue()).isEqualTo(11 + i);
- assertThat(fieldStats.nullCount()).isEqualTo(i);
- }
-
- BinaryTableStats tableStats3 =
- new BinaryTableStats(minRowData, maxRowData, nullCounts,
fieldStatsArray1);
- assertThat(tableStats3).isEqualTo(tableStats1).isEqualTo(tableStats2);
- assertThat(tableStats3.fields(serializer)).isEqualTo(fieldStatsArray2);
- }
-
- private BinaryRow binaryRow(List<Integer> valueList) {
- BinaryRow b = new BinaryRow(valueList.size());
- BinaryRowWriter writer = new BinaryRowWriter(b);
- for (int i = 0; i < valueList.size(); i++) {
- writer.writeInt(i, valueList.get(i));
- }
- writer.complete();
- return b;
- }
-}
diff --git
a/paimon-core/src/test/java/org/apache/paimon/stats/FieldStatsArraySerializerTest.java
b/paimon-core/src/test/java/org/apache/paimon/stats/FieldStatsArraySerializerTest.java
index 0eeaec583..2da96070f 100644
---
a/paimon-core/src/test/java/org/apache/paimon/stats/FieldStatsArraySerializerTest.java
+++
b/paimon-core/src/test/java/org/apache/paimon/stats/FieldStatsArraySerializerTest.java
@@ -19,8 +19,10 @@
package org.apache.paimon.stats;
import org.apache.paimon.casting.CastExecutor;
+import org.apache.paimon.data.BinaryArray;
import org.apache.paimon.data.BinaryRow;
import org.apache.paimon.format.FieldStats;
+import org.apache.paimon.schema.IndexCastMapping;
import org.apache.paimon.schema.SchemaEvolutionUtil;
import org.apache.paimon.schema.TableSchema;
import org.apache.paimon.types.DataField;
@@ -66,21 +68,27 @@ public class FieldStatsArraySerializerTest {
Collections.EMPTY_MAP,
"");
- int[] indexMapping =
- SchemaEvolutionUtil.createIndexMapping(tableSchema.fields(),
dataSchema.fields());
+ IndexCastMapping indexCastMapping =
+ SchemaEvolutionUtil.createIndexCastMapping(
+ tableSchema.fields(), dataSchema.fields());
+ int[] indexMapping = indexCastMapping.getIndexMapping();
CastExecutor<Object, Object>[] converterMapping =
(CastExecutor<Object, Object>[])
SchemaEvolutionUtil.createConvertMapping(
tableSchema.fields(), dataSchema.fields(),
indexMapping);
FieldStatsArraySerializer fieldStatsArraySerializer =
new FieldStatsArraySerializer(
- tableSchema.logicalRowType(), indexMapping,
converterMapping);
+ tableSchema.logicalRowType(),
+ indexMapping,
+ converterMapping,
+ indexCastMapping.getCastMapping());
BinaryRow minRowData = row(1, 2, 3, 4);
BinaryRow maxRowData = row(100, 99, 98, 97);
Long[] nullCounts = new Long[] {1L, 0L, 10L, 100L};
- BinaryTableStats dataTableStats = new BinaryTableStats(minRowData,
maxRowData, nullCounts);
+ BinaryTableStats dataTableStats =
+ new BinaryTableStats(minRowData, maxRowData,
BinaryArray.fromLongArray(nullCounts));
- FieldStats[] fieldStatsArray =
dataTableStats.fields(fieldStatsArraySerializer, 1000L);
+ FieldStats[] fieldStatsArray =
fieldStatsArraySerializer.fromBinary(dataTableStats, 1000L);
assertThat(fieldStatsArray.length).isEqualTo(tableSchema.fields().size()).isEqualTo(5);
checkFieldStats(fieldStatsArray[0], 2, 99, 0L);
checkFieldStats(fieldStatsArray[1], 4, 97, 100L);
diff --git
a/paimon-core/src/test/java/org/apache/paimon/stats/StatsTableTest.java
b/paimon-core/src/test/java/org/apache/paimon/stats/StatsTableTest.java
index ce98052e5..e63d481d9 100644
--- a/paimon-core/src/test/java/org/apache/paimon/stats/StatsTableTest.java
+++ b/paimon-core/src/test/java/org/apache/paimon/stats/StatsTableTest.java
@@ -73,18 +73,18 @@ public class StatsTableTest extends TableTestBase {
// should have partition stats
BinaryTableStats partitionStats = manifest.partitionStats();
- assertThat(partitionStats.min().getInt(0)).isEqualTo(1);
- assertThat(partitionStats.max().getInt(0)).isEqualTo(2);
+ assertThat(partitionStats.minValues().getInt(0)).isEqualTo(1);
+ assertThat(partitionStats.maxValues().getInt(0)).isEqualTo(2);
// should not have record stats because of NONE mode
ManifestFile manifestFile = store.manifestFileFactory().create();
DataFileMeta file =
manifestFile.read(manifest.fileName()).get(0).file();
BinaryTableStats recordStats = file.valueStats();
- assertThat(recordStats.min().isNullAt(0)).isTrue();
- assertThat(recordStats.min().isNullAt(1)).isTrue();
- assertThat(recordStats.min().isNullAt(2)).isTrue();
- assertThat(recordStats.max().isNullAt(0)).isTrue();
- assertThat(recordStats.max().isNullAt(1)).isTrue();
- assertThat(recordStats.max().isNullAt(2)).isTrue();
+ assertThat(recordStats.minValues().isNullAt(0)).isTrue();
+ assertThat(recordStats.minValues().isNullAt(1)).isTrue();
+ assertThat(recordStats.minValues().isNullAt(2)).isTrue();
+ assertThat(recordStats.maxValues().isNullAt(0)).isTrue();
+ assertThat(recordStats.maxValues().isNullAt(1)).isTrue();
+ assertThat(recordStats.maxValues().isNullAt(2)).isTrue();
}
}
diff --git
a/paimon-core/src/test/java/org/apache/paimon/table/ColumnTypeFileMetaTestBase.java
b/paimon-core/src/test/java/org/apache/paimon/table/ColumnTypeFileMetaTestBase.java
index a95bd63b6..f1fc1f958 100644
---
a/paimon-core/src/test/java/org/apache/paimon/table/ColumnTypeFileMetaTestBase.java
+++
b/paimon-core/src/test/java/org/apache/paimon/table/ColumnTypeFileMetaTestBase.java
@@ -20,18 +20,23 @@ package org.apache.paimon.table;
import org.apache.paimon.CoreOptions;
import org.apache.paimon.data.BinaryString;
-import org.apache.paimon.data.Decimal;
-import org.apache.paimon.format.FieldStats;
+import org.apache.paimon.data.InternalRow;
import org.apache.paimon.io.DataFileMeta;
import org.apache.paimon.predicate.Predicate;
import org.apache.paimon.predicate.PredicateBuilder;
+import org.apache.paimon.schema.TableSchema;
import org.apache.paimon.stats.BinaryTableStats;
+import org.apache.paimon.stats.FieldStatsArraySerializer;
+import org.apache.paimon.stats.FieldStatsConverters;
import org.apache.paimon.table.source.DataSplit;
+import org.apache.paimon.types.DataField;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
import java.util.stream.Collectors;
import static org.assertj.core.api.Assertions.assertThat;
@@ -91,15 +96,15 @@ public abstract class ColumnTypeFileMetaTestBase extends
SchemaEvolutionTableTes
protected void validateStatsField(List<DataFileMeta> fileMetaList) {
for (DataFileMeta fileMeta : fileMetaList) {
- FieldStats[] statsArray =
getTableValueStats(fileMeta).fields(null);
- assertThat(statsArray.length).isEqualTo(12);
+ BinaryTableStats stats = getTableValueStats(fileMeta);
+ assertThat(stats.minValues().getFieldCount()).isEqualTo(12);
for (int i = 0; i < 11; i++) {
- assertThat(statsArray[i].minValue()).isNotNull();
- assertThat(statsArray[i].maxValue()).isNotNull();
+ assertThat(stats.minValues().isNullAt(i)).isFalse();
+ assertThat(stats.maxValues().isNullAt(i)).isFalse();
}
// Min and max value of binary type is null
- assertThat(statsArray[11].minValue()).isNull();
- assertThat(statsArray[11].maxValue()).isNull();
+ assertThat(stats.minValues().isNullAt(11)).isTrue();
+ assertThat(stats.maxValues().isNullAt(11)).isTrue();
}
}
@@ -165,7 +170,8 @@ public abstract class ColumnTypeFileMetaTestBase extends
SchemaEvolutionTableTes
.collect(Collectors.toList()))
.containsAll(filesName);
- validateValuesWithNewSchema(filesName, fileMetaList);
+ validateValuesWithNewSchema(
+ schemas, table.schema().id(), filesName,
fileMetaList);
},
getPrimaryKeyNames(),
tableConfig,
@@ -216,7 +222,8 @@ public abstract class ColumnTypeFileMetaTestBase extends
SchemaEvolutionTableTes
.containsAll(filesName);
// Compare all columns with table column type
- validateValuesWithNewSchema(filesName, fileMetaList);
+ validateValuesWithNewSchema(
+ schemas, table.schema().id(), filesName,
fileMetaList);
},
getPrimaryKeyNames(),
tableConfig,
@@ -224,14 +231,22 @@ public abstract class ColumnTypeFileMetaTestBase extends
SchemaEvolutionTableTes
}
protected void validateValuesWithNewSchema(
- List<String> filesName, List<DataFileMeta> fileMetaList) {
+ Map<Long, TableSchema> tableSchemas,
+ long schemaId,
+ List<String> filesName,
+ List<DataFileMeta> fileMetaList) {
+ Function<Long, List<DataField>> schemaFields = id ->
tableSchemas.get(id).fields();
+ FieldStatsConverters converters = new
FieldStatsConverters(schemaFields, schemaId);
for (DataFileMeta fileMeta : fileMetaList) {
- FieldStats[] statsArray =
getTableValueStats(fileMeta).fields(null);
- assertThat(statsArray.length).isEqualTo(12);
+ BinaryTableStats stats = getTableValueStats(fileMeta);
+ FieldStatsArraySerializer serializer =
converters.getOrCreate(fileMeta.schemaId());
+ InternalRow min = serializer.evolution(stats.minValues());
+ InternalRow max = serializer.evolution(stats.maxValues());
+ assertThat(stats.minValues().getFieldCount()).isEqualTo(12);
if (filesName.contains(fileMeta.fileName())) {
- checkTwoValues(statsArray);
+ checkTwoValues(min, max);
} else {
- checkOneValue(statsArray);
+ checkOneValue(min, max);
}
}
}
@@ -245,41 +260,28 @@ public abstract class ColumnTypeFileMetaTestBase extends
SchemaEvolutionTableTes
* <li>types: a->int, b->varchar[10], c->varchar[10], d->double, e->int,
f->decimal,g->float,
* h->double, i->decimal, j->date, k->date, l->varbinary
* </ul>
- *
- * @param statsArray the field stats
*/
- private void checkOneValue(FieldStats[] statsArray) {
-
assertThat(statsArray[0].minValue()).isEqualTo((statsArray[0].maxValue())).isEqualTo(2);
- assertThat(statsArray[1].minValue())
- .isEqualTo(statsArray[1].maxValue())
+ private void checkOneValue(InternalRow min, InternalRow max) {
+ assertThat(min.getInt(0)).isEqualTo(max.getInt(0)).isEqualTo(2);
+ assertThat(min.getString(1))
+ .isEqualTo(max.getString(1))
.isEqualTo(BinaryString.fromString("400"));
- assertThat(statsArray[2].minValue())
- .isEqualTo(statsArray[2].maxValue())
+ assertThat(min.getString(2))
+ .isEqualTo(max.getString(2))
.isEqualTo(BinaryString.fromString("401"));
- assertThat((Double) statsArray[3].minValue())
- .isEqualTo((Double) statsArray[3].maxValue())
- .isEqualTo(402D);
- assertThat((Integer) statsArray[4].minValue())
- .isEqualTo(statsArray[4].maxValue())
- .isEqualTo(403);
- assertThat(((Decimal)
statsArray[5].minValue()).toBigDecimal().intValue())
- .isEqualTo(((Decimal)
statsArray[5].maxValue()).toBigDecimal().intValue())
+
assertThat(min.getDouble(3)).isEqualTo(max.getDouble(3)).isEqualTo(402D);
+ assertThat(min.getInt(4)).isEqualTo(max.getInt(4)).isEqualTo(403);
+ assertThat(min.getDecimal(5, 10, 2).toBigDecimal().intValue())
+ .isEqualTo(max.getDecimal(5, 10, 2).toBigDecimal().intValue())
.isEqualTo(404);
- assertThat((Float) statsArray[6].minValue())
- .isEqualTo(statsArray[6].maxValue())
- .isEqualTo(405F);
- assertThat((Double) statsArray[7].minValue())
- .isEqualTo(statsArray[7].maxValue())
- .isEqualTo(406D);
- assertThat(((Decimal)
statsArray[8].minValue()).toBigDecimal().doubleValue())
- .isEqualTo(((Decimal)
statsArray[8].maxValue()).toBigDecimal().doubleValue())
+ assertThat(min.getFloat(6)).isEqualTo(max.getFloat(6)).isEqualTo(405F);
+
assertThat(min.getDouble(7)).isEqualTo(max.getDouble(7)).isEqualTo(406D);
+ assertThat(min.getDecimal(8, 10, 2).toBigDecimal().doubleValue())
+ .isEqualTo(max.getDecimal(8, 10,
2).toBigDecimal().doubleValue())
.isEqualTo(407D);
-
assertThat(statsArray[9].minValue()).isEqualTo(statsArray[9].maxValue()).isEqualTo(408);
-
assertThat(statsArray[10].minValue()).isEqualTo(statsArray[10].maxValue()).isEqualTo(409);
-
- // Min and max value of binary type is null
- assertThat(statsArray[11].minValue()).isNull();
- assertThat(statsArray[11].maxValue()).isNull();
+ assertThat(min.getInt(9)).isEqualTo(max.getInt(9)).isEqualTo(408);
+ assertThat(min.getInt(10)).isEqualTo(max.getInt(10)).isEqualTo(409);
+ assertThat(min.isNullAt(11)).isEqualTo(max.isNullAt(11)).isTrue();
}
/**
@@ -296,44 +298,43 @@ public abstract class ColumnTypeFileMetaTestBase extends
SchemaEvolutionTableTes
* f->decimal,g->float, h->double, i->decimal, j->date, k->date,
l->varbinary
* </ul>
*/
- private void checkTwoValues(FieldStats[] statsArray) {
- assertThat(statsArray[0].minValue()).isEqualTo(2);
- assertThat(statsArray[0].maxValue()).isEqualTo(2);
+ private void checkTwoValues(InternalRow min, InternalRow max) {
+ assertThat(min.getInt(0)).isEqualTo(2);
+ assertThat(max.getInt(0)).isEqualTo(2);
+
+ assertThat(min.getString(1)).isEqualTo(BinaryString.fromString("200
"));
+ assertThat(max.getString(1)).isEqualTo(BinaryString.fromString("300
"));
-
assertThat(statsArray[1].minValue()).isEqualTo(BinaryString.fromString("200
"));
-
assertThat(statsArray[1].maxValue()).isEqualTo(BinaryString.fromString("300
"));
+ assertThat(min.getString(2)).isEqualTo(BinaryString.fromString("201"));
+ assertThat(max.getString(2)).isEqualTo(BinaryString.fromString("301"));
-
assertThat(statsArray[2].minValue()).isEqualTo(BinaryString.fromString("201"));
-
assertThat(statsArray[2].maxValue()).isEqualTo(BinaryString.fromString("301"));
+ assertThat(min.getDouble(3)).isEqualTo(202D);
+ assertThat(max.getDouble(3)).isEqualTo(302D);
- assertThat((Double) statsArray[3].minValue()).isEqualTo(202D);
- assertThat((Double) statsArray[3].maxValue()).isEqualTo(302D);
+ assertThat(min.getInt(4)).isEqualTo(203);
+ assertThat(max.getInt(4)).isEqualTo(303);
- assertThat((Integer) statsArray[4].minValue()).isEqualTo(203);
- assertThat((Integer) statsArray[4].maxValue()).isEqualTo(303);
+ assertThat(min.getDecimal(5, 10,
2).toBigDecimal().intValue()).isEqualTo(204);
+ assertThat(max.getDecimal(5, 10,
2).toBigDecimal().intValue()).isEqualTo(304);
- assertThat(((Decimal)
statsArray[5].minValue()).toBigDecimal().intValue()).isEqualTo(204);
- assertThat(((Decimal)
statsArray[5].maxValue()).toBigDecimal().intValue()).isEqualTo(304);
+ assertThat(min.getFloat(6)).isEqualTo(205F);
+ assertThat(max.getFloat(6)).isEqualTo(305F);
- assertThat((Float) statsArray[6].minValue()).isEqualTo(205F);
- assertThat((Float) statsArray[6].maxValue()).isEqualTo(305F);
+ assertThat(min.getDouble(7)).isEqualTo(206D);
+ assertThat(max.getDouble(7)).isEqualTo(306D);
- assertThat((Double) statsArray[7].minValue()).isEqualTo(206D);
- assertThat((Double) statsArray[7].maxValue()).isEqualTo(306D);
+ assertThat(min.getDecimal(8, 10,
2).toBigDecimal().doubleValue()).isEqualTo(207D);
+ assertThat(max.getDecimal(8, 10,
2).toBigDecimal().doubleValue()).isEqualTo(307D);
- assertThat(((Decimal)
statsArray[8].minValue()).toBigDecimal().doubleValue())
- .isEqualTo(207D);
- assertThat(((Decimal)
statsArray[8].maxValue()).toBigDecimal().doubleValue())
- .isEqualTo(307D);
+ assertThat(min.getInt(9)).isEqualTo(208);
+ assertThat(max.getInt(9)).isEqualTo(308);
- assertThat(statsArray[9].minValue()).isEqualTo(208);
- assertThat(statsArray[9].maxValue()).isEqualTo(308);
- assertThat(statsArray[10].minValue()).isEqualTo(209);
- assertThat(statsArray[10].maxValue()).isEqualTo(309);
+ assertThat(min.getInt(10)).isEqualTo(209);
+ assertThat(max.getInt(10)).isEqualTo(309);
// Min and max value of binary type is null
- assertThat(statsArray[11].minValue()).isNull();
- assertThat(statsArray[11].maxValue()).isNull();
+ assertThat(min.isNullAt(11)).isTrue();
+ assertThat(max.isNullAt(11)).isTrue();
}
@Override
diff --git
a/paimon-core/src/test/java/org/apache/paimon/table/FileMetaFilterTestBase.java
b/paimon-core/src/test/java/org/apache/paimon/table/FileMetaFilterTestBase.java
index f2ab5b9a9..d460e854a 100644
---
a/paimon-core/src/test/java/org/apache/paimon/table/FileMetaFilterTestBase.java
+++
b/paimon-core/src/test/java/org/apache/paimon/table/FileMetaFilterTestBase.java
@@ -18,18 +18,22 @@
package org.apache.paimon.table;
-import org.apache.paimon.format.FieldStats;
+import org.apache.paimon.data.InternalRow;
import org.apache.paimon.io.DataFileMeta;
import org.apache.paimon.predicate.Predicate;
import org.apache.paimon.predicate.PredicateBuilder;
import org.apache.paimon.stats.BinaryTableStats;
+import org.apache.paimon.stats.FieldStatsArraySerializer;
+import org.apache.paimon.stats.FieldStatsConverters;
import org.apache.paimon.table.source.DataSplit;
+import org.apache.paimon.types.DataField;
import org.junit.jupiter.api.Test;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import java.util.function.Function;
import java.util.stream.Collectors;
import static org.assertj.core.api.Assertions.assertThat;
@@ -73,36 +77,38 @@ public abstract class FileMetaFilterTestBase extends
SchemaEvolutionTableTestBas
.collect(Collectors.toList()))
.containsAll(filesName);
+ Function<Long, List<DataField>> schemaFields = id ->
schemas.get(id).fields();
+ FieldStatsConverters converters =
+ new FieldStatsConverters(schemaFields,
table.schema().id());
for (DataFileMeta fileMeta : fileMetaList) {
- FieldStats[] statsArray =
getTableValueStats(fileMeta).fields(null);
- assertThat(statsArray.length).isEqualTo(6);
- if (filesName.contains(fileMeta.fileName())) {
- assertThat(statsArray[0].minValue()).isNotNull();
- assertThat(statsArray[0].maxValue()).isNotNull();
- assertThat(statsArray[1].minValue()).isNotNull();
- assertThat(statsArray[1].maxValue()).isNotNull();
- assertThat(statsArray[2].minValue()).isNotNull();
- assertThat(statsArray[2].maxValue()).isNotNull();
+ BinaryTableStats stats = getTableValueStats(fileMeta);
+ FieldStatsArraySerializer serializer =
+ converters.getOrCreate(fileMeta.schemaId());
+ InternalRow min =
serializer.evolution(stats.minValues());
+ InternalRow max =
serializer.evolution(stats.maxValues());
+
+ assertThat(min.getFieldCount()).isEqualTo(6);
- assertThat(statsArray[3].minValue()).isNull();
- assertThat(statsArray[3].maxValue()).isNull();
- assertThat(statsArray[4].minValue()).isNull();
- assertThat(statsArray[4].maxValue()).isNull();
- assertThat(statsArray[5].minValue()).isNull();
- assertThat(statsArray[5].maxValue()).isNull();
+ assertThat(min.isNullAt(0)).isFalse();
+ assertThat(max.isNullAt(0)).isFalse();
+ assertThat(min.isNullAt(1)).isFalse();
+ assertThat(max.isNullAt(1)).isFalse();
+ assertThat(min.isNullAt(2)).isFalse();
+ assertThat(max.isNullAt(2)).isFalse();
+ if (filesName.contains(fileMeta.fileName())) {
+ assertThat(min.isNullAt(3)).isTrue();
+ assertThat(max.isNullAt(3)).isTrue();
+ assertThat(min.isNullAt(4)).isTrue();
+ assertThat(max.isNullAt(4)).isTrue();
+ assertThat(min.isNullAt(5)).isTrue();
+ assertThat(max.isNullAt(5)).isTrue();
} else {
- assertThat(statsArray[0].minValue()).isNotNull();
- assertThat(statsArray[0].maxValue()).isNotNull();
- assertThat(statsArray[1].minValue()).isNotNull();
- assertThat(statsArray[1].maxValue()).isNotNull();
- assertThat(statsArray[2].minValue()).isNotNull();
- assertThat(statsArray[2].maxValue()).isNotNull();
- assertThat(statsArray[3].minValue()).isNotNull();
- assertThat(statsArray[3].maxValue()).isNotNull();
- assertThat(statsArray[4].minValue()).isNotNull();
- assertThat(statsArray[4].maxValue()).isNotNull();
- assertThat(statsArray[5].minValue()).isNotNull();
- assertThat(statsArray[5].maxValue()).isNotNull();
+ assertThat(min.isNullAt(3)).isFalse();
+ assertThat(max.isNullAt(3)).isFalse();
+ assertThat(min.isNullAt(4)).isFalse();
+ assertThat(max.isNullAt(4)).isFalse();
+ assertThat(min.isNullAt(5)).isFalse();
+ assertThat(max.isNullAt(5)).isFalse();
}
}
},
@@ -177,12 +183,19 @@ public abstract class FileMetaFilterTestBase extends
SchemaEvolutionTableTestBas
List<DataSplit> allSplits =
table.newSnapshotReader().read().dataSplits();
assertThat(filterAllSplits).isEqualTo(allSplits);
+ Function<Long, List<DataField>> schemaFields = id ->
schemas.get(id).fields();
+ FieldStatsConverters converters =
+ new FieldStatsConverters(schemaFields,
table.schema().id());
Set<String> filterFileNames = new HashSet<>();
for (DataSplit dataSplit : filterAllSplits) {
for (DataFileMeta dataFileMeta :
dataSplit.dataFiles()) {
- FieldStats[] fieldStats =
getTableValueStats(dataFileMeta).fields(null);
- int minValue = (Integer) fieldStats[1].minValue();
- int maxValue = (Integer) fieldStats[1].maxValue();
+ BinaryTableStats stats =
getTableValueStats(dataFileMeta);
+ FieldStatsArraySerializer serializer =
+
converters.getOrCreate(dataFileMeta.schemaId());
+ InternalRow min =
serializer.evolution(stats.minValues());
+ InternalRow max =
serializer.evolution(stats.maxValues());
+ int minValue = min.getInt(1);
+ int maxValue = max.getInt(1);
if (minValue >= 14
&& minValue <= 19
&& maxValue >= 14
@@ -249,11 +262,18 @@ public abstract class FileMetaFilterTestBase extends
SchemaEvolutionTableTestBas
checkFilterRowCount(toDataFileMetas(allSplits), 12L);
Set<String> filterFileNames = new HashSet<>();
+ Function<Long, List<DataField>> schemaFields = id ->
schemas.get(id).fields();
+ FieldStatsConverters converters =
+ new FieldStatsConverters(schemaFields,
table.schema().id());
for (DataSplit dataSplit : allSplits) {
for (DataFileMeta dataFileMeta :
dataSplit.dataFiles()) {
- FieldStats[] fieldStats =
getTableValueStats(dataFileMeta).fields(null);
- Integer minValue = (Integer)
fieldStats[3].minValue();
- Integer maxValue = (Integer)
fieldStats[3].maxValue();
+ BinaryTableStats stats =
getTableValueStats(dataFileMeta);
+ FieldStatsArraySerializer serializer =
+
converters.getOrCreate(dataFileMeta.schemaId());
+ InternalRow min =
serializer.evolution(stats.minValues());
+ InternalRow max =
serializer.evolution(stats.maxValues());
+ Integer minValue = min.isNullAt(3) ? null :
min.getInt(3);
+ Integer maxValue = max.isNullAt(3) ? null :
max.getInt(3);
if (minValue != null
&& maxValue != null
&& minValue > 1120
diff --git
a/paimon-core/src/test/java/org/apache/paimon/table/PrimaryKeyTableColumnTypeFileMetaTest.java
b/paimon-core/src/test/java/org/apache/paimon/table/PrimaryKeyTableColumnTypeFileMetaTest.java
index 8b3e3726f..4edbd35a2 100644
---
a/paimon-core/src/test/java/org/apache/paimon/table/PrimaryKeyTableColumnTypeFileMetaTest.java
+++
b/paimon-core/src/test/java/org/apache/paimon/table/PrimaryKeyTableColumnTypeFileMetaTest.java
@@ -19,20 +19,24 @@
package org.apache.paimon.table;
import org.apache.paimon.data.BinaryString;
-import org.apache.paimon.format.FieldStats;
+import org.apache.paimon.data.InternalRow;
import org.apache.paimon.io.DataFileMeta;
import org.apache.paimon.predicate.Predicate;
import org.apache.paimon.predicate.PredicateBuilder;
import org.apache.paimon.schema.SchemaManager;
import org.apache.paimon.schema.TableSchema;
import org.apache.paimon.stats.BinaryTableStats;
+import org.apache.paimon.stats.FieldStatsArraySerializer;
+import org.apache.paimon.stats.FieldStatsConverters;
import org.apache.paimon.table.source.DataSplit;
+import org.apache.paimon.types.DataField;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.List;
import java.util.Map;
+import java.util.function.Function;
import java.util.stream.Collectors;
import static org.assertj.core.api.Assertions.assertThat;
@@ -65,11 +69,11 @@ public class PrimaryKeyTableColumnTypeFileMetaTest extends
ColumnTypeFileMetaTes
@Override
protected void validateStatsField(List<DataFileMeta> fileMetaList) {
for (DataFileMeta fileMeta : fileMetaList) {
- FieldStats[] statsArray =
getTableValueStats(fileMeta).fields(null);
- assertThat(statsArray.length).isEqualTo(4);
+ BinaryTableStats stats = getTableValueStats(fileMeta);
+ assertThat(stats.maxValues().getFieldCount()).isEqualTo(4);
for (int i = 0; i < 4; i++) {
- assertThat(statsArray[i].minValue()).isNotNull();
- assertThat(statsArray[i].maxValue()).isNotNull();
+ assertThat(stats.minValues().isNullAt(i)).isFalse();
+ assertThat(stats.maxValues().isNullAt(i)).isFalse();
}
}
}
@@ -112,37 +116,40 @@ public class PrimaryKeyTableColumnTypeFileMetaTest
extends ColumnTypeFileMetaTes
/** We can only validate the values in primary keys for changelog with key
table. */
@Override
protected void validateValuesWithNewSchema(
- List<String> filesName, List<DataFileMeta> fileMetaList) {
+ Map<Long, TableSchema> tableSchemas,
+ long schemaId,
+ List<String> filesName,
+ List<DataFileMeta> fileMetaList) {
+ Function<Long, List<DataField>> schemaFields =
+ id ->
tableSchemas.get(id).logicalTrimmedPrimaryKeysType().getFields();
+ FieldStatsConverters converters = new
FieldStatsConverters(schemaFields, schemaId);
for (DataFileMeta fileMeta : fileMetaList) {
- FieldStats[] statsArray =
getTableValueStats(fileMeta).fields(null);
- assertThat(statsArray.length).isEqualTo(4);
+ BinaryTableStats stats = getTableValueStats(fileMeta);
+ FieldStatsArraySerializer serializer =
converters.getOrCreate(fileMeta.schemaId());
+ InternalRow min = serializer.evolution(stats.minValues());
+ InternalRow max = serializer.evolution(stats.maxValues());
+ assertThat(min.getFieldCount()).isEqualTo(4);
if (filesName.contains(fileMeta.fileName())) {
- assertThat(statsArray[0].minValue())
- .isEqualTo(BinaryString.fromString("200 "));
- assertThat(statsArray[0].maxValue())
- .isEqualTo(BinaryString.fromString("300 "));
+
assertThat(min.getString(0)).isEqualTo(BinaryString.fromString("200 "));
+
assertThat(max.getString(0)).isEqualTo(BinaryString.fromString("300 "));
-
assertThat(statsArray[1].minValue()).isEqualTo(BinaryString.fromString("201"));
-
assertThat(statsArray[1].maxValue()).isEqualTo(BinaryString.fromString("301"));
+
assertThat(min.getString(1)).isEqualTo(BinaryString.fromString("201"));
+
assertThat(max.getString(1)).isEqualTo(BinaryString.fromString("301"));
- assertThat((Double) statsArray[2].minValue()).isEqualTo(202D);
- assertThat((Double) statsArray[2].maxValue()).isEqualTo(302D);
+ assertThat(min.getDouble(2)).isEqualTo(202D);
+ assertThat(max.getDouble(2)).isEqualTo(302D);
- assertThat((Integer) statsArray[3].minValue()).isEqualTo(203);
- assertThat((Integer) statsArray[3].maxValue()).isEqualTo(303);
+ assertThat(min.getInt(3)).isEqualTo(203);
+ assertThat(max.getInt(3)).isEqualTo(303);
} else {
- assertThat(statsArray[0].minValue())
- .isEqualTo(statsArray[0].maxValue())
+ assertThat(min.getString(0))
+ .isEqualTo(max.getString(0))
.isEqualTo(BinaryString.fromString("400"));
- assertThat(statsArray[1].minValue())
- .isEqualTo(statsArray[1].maxValue())
+ assertThat(min.getString(1))
+ .isEqualTo(max.getString(1))
.isEqualTo(BinaryString.fromString("401"));
- assertThat((Double) statsArray[2].minValue())
- .isEqualTo((Double) statsArray[2].maxValue())
- .isEqualTo(402D);
- assertThat((Integer) statsArray[3].minValue())
- .isEqualTo(statsArray[3].maxValue())
- .isEqualTo(403);
+
assertThat(min.getDouble(2)).isEqualTo(max.getDouble(2)).isEqualTo(402D);
+
assertThat(min.getInt(3)).isEqualTo(max.getInt(3)).isEqualTo(403);
}
}
}
diff --git
a/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/PredicateConverterTest.java
b/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/PredicateConverterTest.java
index e5df44849..e4f70ab13 100644
---
a/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/PredicateConverterTest.java
+++
b/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/PredicateConverterTest.java
@@ -21,6 +21,7 @@ package org.apache.paimon.flink;
import org.apache.paimon.data.BinaryString;
import org.apache.paimon.data.GenericRow;
import org.apache.paimon.format.FieldStats;
+import org.apache.paimon.predicate.FieldStatsUtils;
import org.apache.paimon.predicate.Predicate;
import org.apache.paimon.predicate.PredicateBuilder;
@@ -265,7 +266,11 @@ public class PredicateConverterTest {
IntStream.range(0, rowCountList.size())
.forEach(
i ->
- assertThat(predicate.test(rowCountList.get(i),
statsList.get(i)))
+ assertThat(
+ FieldStatsUtils.test(
+ predicate,
+ rowCountList.get(i),
+ statsList.get(i)))
.isEqualTo(expectedForStats.get(i)));
}