This is an automated email from the ASF dual-hosted git repository. jackie pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/pinot.git
The following commit(s) were added to refs/heads/master by this push: new 4bafac8439 Add minor optimization for FIRST_VALUE / LAST_VALUE with IGNORE NULLS and unbounded ROWS window frame (#14324) 4bafac8439 is described below commit 4bafac8439e006750308ad8031c373791c594b1c Author: Yash Mayya <yash.ma...@gmail.com> AuthorDate: Wed Oct 30 00:16:13 2024 +0530 Add minor optimization for FIRST_VALUE / LAST_VALUE with IGNORE NULLS and unbounded ROWS window frame (#14324) --- .../window/value/FirstValueWindowFunction.java | 35 ++++++++++++++-------- .../window/value/LastValueWindowFunction.java | 29 +++++++++++------- .../operator/window/value/ValueWindowFunction.java | 7 ----- 3 files changed, 42 insertions(+), 29 deletions(-) diff --git a/pinot-query-runtime/src/main/java/org/apache/pinot/query/runtime/operator/window/value/FirstValueWindowFunction.java b/pinot-query-runtime/src/main/java/org/apache/pinot/query/runtime/operator/window/value/FirstValueWindowFunction.java index a1f84be32e..7baebe8b41 100644 --- a/pinot-query-runtime/src/main/java/org/apache/pinot/query/runtime/operator/window/value/FirstValueWindowFunction.java +++ b/pinot-query-runtime/src/main/java/org/apache/pinot/query/runtime/operator/window/value/FirstValueWindowFunction.java @@ -58,11 +58,12 @@ public class FirstValueWindowFunction extends ValueWindowFunction { } private List<Object> processRowsWindow(List<Object[]> rows) { + int numRows = rows.size(); + if (_windowFrame.isUnboundedPreceding() && _windowFrame.getUpperBound() >= 0) { - return fillAllWithValue(rows, extractValueFromRow(rows.get(0))); + return Collections.nCopies(numRows, extractValueFromRow(rows.get(0))); } - int numRows = rows.size(); List<Object> result = new ArrayList<>(numRows); // lowerBound is guaranteed to be less than or equal to upperBound here (but both can be -ve / +ve) @@ -92,6 +93,10 @@ public class FirstValueWindowFunction extends ValueWindowFunction { } private List<Object> processRowsWindowIgnoreNulls(List<Object[]> rows) { + if (_windowFrame.isUnboundedPreceding() && _windowFrame.isUnboundedFollowing()) { + return processUnboundedWindowIgnoreNulls(rows); + } + int numRows = rows.size(); int lowerBound = _windowFrame.getLowerBound(); int upperBound = Math.min(_windowFrame.getUpperBound(), numRows - 1); @@ -143,15 +148,16 @@ public class FirstValueWindowFunction extends ValueWindowFunction { } private List<Object> processRangeWindow(List<Object[]> rows) { + int numRows = rows.size(); + if (_windowFrame.isUnboundedPreceding()) { - return fillAllWithValue(rows, extractValueFromRow(rows.get(0))); + return Collections.nCopies(numRows, extractValueFromRow(rows.get(0))); } // The lower bound has to be CURRENT ROW since we don't support RANGE windows with offset value Preconditions.checkState(_windowFrame.isLowerBoundCurrentRow(), "RANGE window frame with offset PRECEDING / FOLLOWING is not supported"); - int numRows = rows.size(); List<Object> result = new ArrayList<>(numRows); // The window frame here is either RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING or RANGE BETWEEN CURRENT ROW @@ -178,14 +184,7 @@ public class FirstValueWindowFunction extends ValueWindowFunction { int numRows = rows.size(); if (_windowFrame.isUnboundedPreceding() && _windowFrame.isUnboundedFollowing()) { - // Find the first non-null value and fill it in all rows - int indexOfFirstNonNullValue = indexOfFirstNonNullValueInWindow(rows, 0, numRows - 1); - if (indexOfFirstNonNullValue == -1) { - // There's no non-null value - return Collections.nCopies(numRows, null); - } else { - return fillAllWithValue(rows, extractValueFromRow(rows.get(indexOfFirstNonNullValue))); - } + return processUnboundedWindowIgnoreNulls(rows); } if (_windowFrame.isUnboundedPreceding() && _windowFrame.isUpperBoundCurrentRow()) { @@ -270,6 +269,18 @@ public class FirstValueWindowFunction extends ValueWindowFunction { throw new IllegalStateException("RANGE window frame with offset PRECEDING / FOLLOWING is not supported"); } + private List<Object> processUnboundedWindowIgnoreNulls(List<Object[]> rows) { + int numRows = rows.size(); + // Find the first non-null value and fill it in all rows + int indexOfFirstNonNullValue = indexOfFirstNonNullValueInWindow(rows, 0, numRows - 1); + if (indexOfFirstNonNullValue == -1) { + // There's no non-null value + return Collections.nCopies(numRows, null); + } else { + return Collections.nCopies(numRows, extractValueFromRow(rows.get(indexOfFirstNonNullValue))); + } + } + /** * Both lowerBound and upperBound should be valid values for the given row set. The returned value is -1 if there is * no non-null value in the window. diff --git a/pinot-query-runtime/src/main/java/org/apache/pinot/query/runtime/operator/window/value/LastValueWindowFunction.java b/pinot-query-runtime/src/main/java/org/apache/pinot/query/runtime/operator/window/value/LastValueWindowFunction.java index 5383525d2d..8da5fa6fb1 100644 --- a/pinot-query-runtime/src/main/java/org/apache/pinot/query/runtime/operator/window/value/LastValueWindowFunction.java +++ b/pinot-query-runtime/src/main/java/org/apache/pinot/query/runtime/operator/window/value/LastValueWindowFunction.java @@ -60,7 +60,7 @@ public class LastValueWindowFunction extends ValueWindowFunction { private List<Object> processRowsWindow(List<Object[]> rows) { int numRows = rows.size(); if (_windowFrame.isUnboundedFollowing() && _windowFrame.getLowerBound() <= 0) { - return fillAllWithValue(rows, extractValueFromRow(rows.get(numRows - 1))); + return Collections.nCopies(numRows, extractValueFromRow(rows.get(numRows - 1))); } List<Object> result = new ArrayList<>(numRows); @@ -92,6 +92,10 @@ public class LastValueWindowFunction extends ValueWindowFunction { } private List<Object> processRowsWindowIgnoreNulls(List<Object[]> rows) { + if (_windowFrame.isUnboundedPreceding() && _windowFrame.isUnboundedFollowing()) { + return processUnboundedWindowIgnoreNulls(rows); + } + int numRows = rows.size(); int lowerBound = _windowFrame.getLowerBound(); int upperBound = Math.min(_windowFrame.getUpperBound(), numRows - 1); @@ -142,7 +146,7 @@ public class LastValueWindowFunction extends ValueWindowFunction { private List<Object> processRangeWindow(List<Object[]> rows) { int numRows = rows.size(); if (_windowFrame.isUnboundedFollowing()) { - return fillAllWithValue(rows, extractValueFromRow(rows.get(numRows - 1))); + return Collections.nCopies(numRows, extractValueFromRow(rows.get(numRows - 1))); } // The upper bound has to be CURRENT ROW here since we don't support RANGE windows with offset value @@ -177,14 +181,7 @@ public class LastValueWindowFunction extends ValueWindowFunction { int numRows = rows.size(); if (_windowFrame.isUnboundedPreceding() && _windowFrame.isUnboundedFollowing()) { - // Find the last non-null value and fill it in all rows - int indexOfLastNonNullValue = indexOfLastNonNullValueInWindow(rows, 0, numRows - 1); - if (indexOfLastNonNullValue == -1) { - // There's no non-null value - return Collections.nCopies(numRows, null); - } else { - return fillAllWithValue(rows, extractValueFromRow(rows.get(indexOfLastNonNullValue))); - } + return processUnboundedWindowIgnoreNulls(rows); } if (_windowFrame.isUnboundedPreceding() && _windowFrame.isUpperBoundCurrentRow()) { @@ -259,6 +256,18 @@ public class LastValueWindowFunction extends ValueWindowFunction { throw new IllegalStateException("RANGE window frame with offset PRECEDING / FOLLOWING is not supported"); } + private List<Object> processUnboundedWindowIgnoreNulls(List<Object[]> rows) { + int numRows = rows.size(); + // Find the last non-null value and fill it in all rows + int indexOfLastNonNullValue = indexOfLastNonNullValueInWindow(rows, 0, numRows - 1); + if (indexOfLastNonNullValue == -1) { + // There's no non-null value + return Collections.nCopies(numRows, null); + } else { + return Collections.nCopies(numRows, extractValueFromRow(rows.get(indexOfLastNonNullValue))); + } + } + /** * Both lowerBound and upperBound should be valid values for the given row set. The returned value is -1 if there is * no non-null value in the window. diff --git a/pinot-query-runtime/src/main/java/org/apache/pinot/query/runtime/operator/window/value/ValueWindowFunction.java b/pinot-query-runtime/src/main/java/org/apache/pinot/query/runtime/operator/window/value/ValueWindowFunction.java index ce8a00d432..154c846766 100644 --- a/pinot-query-runtime/src/main/java/org/apache/pinot/query/runtime/operator/window/value/ValueWindowFunction.java +++ b/pinot-query-runtime/src/main/java/org/apache/pinot/query/runtime/operator/window/value/ValueWindowFunction.java @@ -19,7 +19,6 @@ package org.apache.pinot.query.runtime.operator.window.value; import com.google.common.collect.ImmutableMap; -import java.util.Collections; import java.util.List; import java.util.Map; import org.apache.calcite.rel.RelFieldCollation; @@ -48,10 +47,4 @@ public abstract class ValueWindowFunction extends WindowFunction { super(aggCall, inputSchema, collations, windowFrame); _ignoreNulls = aggCall.isIgnoreNulls(); } - - protected List<Object> fillAllWithValue(List<Object[]> rows, Object value) { - int numRows = rows.size(); - assert numRows > 0; - return Collections.nCopies(numRows, value); - } } --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@pinot.apache.org For additional commands, e-mail: commits-h...@pinot.apache.org