aboutsummaryrefslogtreecommitdiff
path: root/sql/hive
diff options
context:
space:
mode:
authorHerman van Hovell <hvanhovell@questtec.nl>2015-12-17 15:16:35 -0800
committerYin Huai <yhuai@databricks.com>2015-12-17 15:16:35 -0800
commit658f66e6208a52367e3b43a6fee9c90f33fb6226 (patch)
tree15616196d5ffe59fcf94fe6b49bf4cf545429b0f /sql/hive
parented6ebda5c898bad76194fe3a090bef5a14f861c2 (diff)
downloadspark-658f66e6208a52367e3b43a6fee9c90f33fb6226.tar.gz
spark-658f66e6208a52367e3b43a6fee9c90f33fb6226.tar.bz2
spark-658f66e6208a52367e3b43a6fee9c90f33fb6226.zip
[SPARK-8641][SQL] Native Spark Window functions
This PR removes Hive windows functions from Spark and replaces them with (native) Spark ones. The PR is on par with Hive in terms of features. This has the following advantages: * Better memory management. * The ability to use spark UDAFs in Window functions. cc rxin / yhuai Author: Herman van Hovell <hvanhovell@questtec.nl> Closes #9819 from hvanhovell/SPARK-8641-2.
Diffstat (limited to 'sql/hive')
-rw-r--r--sql/hive/compatibility/src/test/scala/org/apache/spark/sql/hive/execution/HiveWindowFunctionQuerySuite.scala10
-rw-r--r--sql/hive/src/main/scala/org/apache/spark/sql/hive/HiveContext.scala1
-rw-r--r--sql/hive/src/main/scala/org/apache/spark/sql/hive/HiveQl.scala22
-rw-r--r--sql/hive/src/main/scala/org/apache/spark/sql/hive/hiveUDFs.scala224
-rw-r--r--sql/hive/src/test/scala/org/apache/spark/sql/hive/HiveDataFrameWindowSuite.scala259
-rw-r--r--sql/hive/src/test/scala/org/apache/spark/sql/hive/execution/WindowQuerySuite.scala230
6 files changed, 249 insertions, 497 deletions
diff --git a/sql/hive/compatibility/src/test/scala/org/apache/spark/sql/hive/execution/HiveWindowFunctionQuerySuite.scala b/sql/hive/compatibility/src/test/scala/org/apache/spark/sql/hive/execution/HiveWindowFunctionQuerySuite.scala
index 92bb9e6d73..98bbdf0653 100644
--- a/sql/hive/compatibility/src/test/scala/org/apache/spark/sql/hive/execution/HiveWindowFunctionQuerySuite.scala
+++ b/sql/hive/compatibility/src/test/scala/org/apache/spark/sql/hive/execution/HiveWindowFunctionQuerySuite.scala
@@ -454,6 +454,9 @@ class HiveWindowFunctionQuerySuite extends HiveComparisonTest with BeforeAndAfte
|window w1 as (distribute by p_mfgr sort by p_name rows between 2 preceding and 2 following)
""".stripMargin, reset = false)
+ /* Disabled because:
+ - Spark uses a different default stddev.
+ - Tiny numerical differences in stddev results.
createQueryTest("windowing.q -- 15. testExpressions",
s"""
|select p_mfgr,p_name, p_size,
@@ -472,7 +475,7 @@ class HiveWindowFunctionQuerySuite extends HiveComparisonTest with BeforeAndAfte
|window w1 as (distribute by p_mfgr sort by p_mfgr, p_name
| rows between 2 preceding and 2 following)
""".stripMargin, reset = false)
-
+ */
createQueryTest("windowing.q -- 16. testMultipleWindows",
s"""
|select p_mfgr,p_name, p_size,
@@ -530,6 +533,9 @@ class HiveWindowFunctionQuerySuite extends HiveComparisonTest with BeforeAndAfte
// when running this test suite under Java 7 and 8.
// We change the original sql query a little bit for making the test suite passed
// under different JDK
+ /* Disabled because:
+ - Spark uses a different default stddev.
+ - Tiny numerical differences in stddev results.
createQueryTest("windowing.q -- 20. testSTATs",
"""
|select p_mfgr,p_name, p_size, sdev, sdev_pop, uniq_data, var, cor, covarp
@@ -547,7 +553,7 @@ class HiveWindowFunctionQuerySuite extends HiveComparisonTest with BeforeAndAfte
|) t lateral view explode(uniq_size) d as uniq_data
|order by p_mfgr,p_name, p_size, sdev, sdev_pop, uniq_data, var, cor, covarp
""".stripMargin, reset = false)
-
+ */
createQueryTest("windowing.q -- 21. testDISTs",
"""
|select p_mfgr,p_name, p_size,
diff --git a/sql/hive/src/main/scala/org/apache/spark/sql/hive/HiveContext.scala b/sql/hive/src/main/scala/org/apache/spark/sql/hive/HiveContext.scala
index 5958777b0d..0eeb62ca2c 100644
--- a/sql/hive/src/main/scala/org/apache/spark/sql/hive/HiveContext.scala
+++ b/sql/hive/src/main/scala/org/apache/spark/sql/hive/HiveContext.scala
@@ -476,7 +476,6 @@ class HiveContext private[hive](
catalog.CreateTables ::
catalog.PreInsertionCasts ::
ExtractPythonUDFs ::
- ResolveHiveWindowFunction ::
PreInsertCastAndRename ::
(if (conf.runSQLOnFile) new ResolveDataSource(self) :: Nil else Nil)
diff --git a/sql/hive/src/main/scala/org/apache/spark/sql/hive/HiveQl.scala b/sql/hive/src/main/scala/org/apache/spark/sql/hive/HiveQl.scala
index 091caab921..da41b659e3 100644
--- a/sql/hive/src/main/scala/org/apache/spark/sql/hive/HiveQl.scala
+++ b/sql/hive/src/main/scala/org/apache/spark/sql/hive/HiveQl.scala
@@ -353,6 +353,14 @@ private[hive] object HiveQl extends Logging {
}
/** Extractor for matching Hive's AST Tokens. */
+ private[hive] case class Token(name: String, children: Seq[ASTNode]) extends Node {
+ def getName(): String = name
+ def getChildren(): java.util.List[Node] = {
+ val col = new java.util.ArrayList[Node](children.size)
+ children.foreach(col.add(_))
+ col
+ }
+ }
object Token {
/** @return matches of the form (tokenName, children). */
def unapply(t: Any): Option[(String, Seq[ASTNode])] = t match {
@@ -360,6 +368,7 @@ private[hive] object HiveQl extends Logging {
CurrentOrigin.setPosition(t.getLine, t.getCharPositionInLine)
Some((t.getText,
Option(t.getChildren).map(_.asScala.toList).getOrElse(Nil).asInstanceOf[Seq[ASTNode]]))
+ case t: Token => Some((t.name, t.children))
case _ => None
}
}
@@ -1617,17 +1626,8 @@ https://cwiki.apache.org/confluence/display/Hive/Enhanced+Aggregation%2C+Cube%2C
UnresolvedExtractValue(nodeToExpr(child), nodeToExpr(ordinal))
/* Window Functions */
- case Token("TOK_FUNCTION", Token(name, Nil) +: args :+ Token("TOK_WINDOWSPEC", spec)) =>
- val function = UnresolvedWindowFunction(name, args.map(nodeToExpr))
- nodesToWindowSpecification(spec) match {
- case reference: WindowSpecReference =>
- UnresolvedWindowExpression(function, reference)
- case definition: WindowSpecDefinition =>
- WindowExpression(function, definition)
- }
- case Token("TOK_FUNCTIONSTAR", Token(name, Nil) :: Token("TOK_WINDOWSPEC", spec) :: Nil) =>
- // Safe to use Literal(1)?
- val function = UnresolvedWindowFunction(name, Literal(1) :: Nil)
+ case Token(name, args :+ Token("TOK_WINDOWSPEC", spec)) =>
+ val function = nodeToExpr(Token(name, args))
nodesToWindowSpecification(spec) match {
case reference: WindowSpecReference =>
UnresolvedWindowExpression(function, reference)
diff --git a/sql/hive/src/main/scala/org/apache/spark/sql/hive/hiveUDFs.scala b/sql/hive/src/main/scala/org/apache/spark/sql/hive/hiveUDFs.scala
index 2e8c026259..a1787fc92d 100644
--- a/sql/hive/src/main/scala/org/apache/spark/sql/hive/hiveUDFs.scala
+++ b/sql/hive/src/main/scala/org/apache/spark/sql/hive/hiveUDFs.scala
@@ -261,230 +261,6 @@ private[hive] case class HiveGenericUDF(funcWrapper: HiveFunctionWrapper, childr
}
/**
- * Resolves [[UnresolvedWindowFunction]] to [[HiveWindowFunction]].
- */
-private[spark] object ResolveHiveWindowFunction extends Rule[LogicalPlan] {
- private def shouldResolveFunction(
- unresolvedWindowFunction: UnresolvedWindowFunction,
- windowSpec: WindowSpecDefinition): Boolean = {
- unresolvedWindowFunction.childrenResolved && windowSpec.childrenResolved
- }
-
- def apply(plan: LogicalPlan): LogicalPlan = plan transformUp {
- case p: LogicalPlan if !p.childrenResolved => p
-
- // We are resolving WindowExpressions at here. When we get here, we have already
- // replaced those WindowSpecReferences.
- case p: LogicalPlan =>
- p transformExpressions {
- // We will not start to resolve the function unless all arguments are resolved
- // and all expressions in window spec are fixed.
- case WindowExpression(
- u @ UnresolvedWindowFunction(name, children),
- windowSpec: WindowSpecDefinition) if shouldResolveFunction(u, windowSpec) =>
- // First, let's find the window function info.
- val windowFunctionInfo: WindowFunctionInfo =
- Option(FunctionRegistry.getWindowFunctionInfo(name.toLowerCase)).getOrElse(
- throw new AnalysisException(s"Couldn't find window function $name"))
-
- // Get the class of this function.
- // In Hive 0.12, there is no windowFunctionInfo.getFunctionClass. So, we use
- // windowFunctionInfo.getfInfo().getFunctionClass for both Hive 0.13 and Hive 0.13.1.
- val functionClass = windowFunctionInfo.getFunctionClass()
- val newChildren =
- // Rank(), DENSE_RANK(), CUME_DIST(), and PERCENT_RANK() do not take explicit
- // input parameters and requires implicit parameters, which
- // are expressions in Order By clause.
- if (classOf[GenericUDAFRank].isAssignableFrom(functionClass)) {
- if (children.nonEmpty) {
- throw new AnalysisException(s"$name does not take input parameters.")
- }
- windowSpec.orderSpec.map(_.child)
- } else {
- children
- }
-
- // If the class is UDAF, we need to use UDAFBridge.
- val isUDAFBridgeRequired =
- if (classOf[UDAF].isAssignableFrom(functionClass)) {
- true
- } else {
- false
- }
-
- // Create the HiveWindowFunction. For the meaning of isPivotResult, see the doc of
- // HiveWindowFunction.
- val windowFunction =
- HiveWindowFunction(
- new HiveFunctionWrapper(functionClass.getName),
- windowFunctionInfo.isPivotResult,
- isUDAFBridgeRequired,
- newChildren)
-
- // Second, check if the specified window function can accept window definition.
- windowSpec.frameSpecification match {
- case frame: SpecifiedWindowFrame if !windowFunctionInfo.isSupportsWindow =>
- // This Hive window function does not support user-speficied window frame.
- throw new AnalysisException(
- s"Window function $name does not take a frame specification.")
- case frame: SpecifiedWindowFrame if windowFunctionInfo.isSupportsWindow &&
- windowFunctionInfo.isPivotResult =>
- // These two should not be true at the same time when a window frame is defined.
- // If so, throw an exception.
- throw new AnalysisException(s"Could not handle Hive window function $name because " +
- s"it supports both a user specified window frame and pivot result.")
- case _ => // OK
- }
- // Resolve those UnspecifiedWindowFrame because the physical Window operator still needs
- // a window frame specification to work.
- val newWindowSpec = windowSpec.frameSpecification match {
- case UnspecifiedFrame =>
- val newWindowFrame =
- SpecifiedWindowFrame.defaultWindowFrame(
- windowSpec.orderSpec.nonEmpty,
- windowFunctionInfo.isSupportsWindow)
- WindowSpecDefinition(windowSpec.partitionSpec, windowSpec.orderSpec, newWindowFrame)
- case _ => windowSpec
- }
-
- // Finally, we create a WindowExpression with the resolved window function and
- // specified window spec.
- WindowExpression(windowFunction, newWindowSpec)
- }
- }
-}
-
-/**
- * A [[WindowFunction]] implementation wrapping Hive's window function.
- * @param funcWrapper The wrapper for the Hive Window Function.
- * @param pivotResult If it is true, the Hive function will return a list of values representing
- * the values of the added columns. Otherwise, a single value is returned for
- * current row.
- * @param isUDAFBridgeRequired If it is true, the function returned by functionWrapper's
- * createFunction is UDAF, we need to use GenericUDAFBridge to wrap
- * it as a GenericUDAFResolver2.
- * @param children Input parameters.
- */
-private[hive] case class HiveWindowFunction(
- funcWrapper: HiveFunctionWrapper,
- pivotResult: Boolean,
- isUDAFBridgeRequired: Boolean,
- children: Seq[Expression]) extends WindowFunction
- with HiveInspectors with Unevaluable {
-
- // Hive window functions are based on GenericUDAFResolver2.
- type UDFType = GenericUDAFResolver2
-
- @transient
- protected lazy val resolver: GenericUDAFResolver2 =
- if (isUDAFBridgeRequired) {
- new GenericUDAFBridge(funcWrapper.createFunction[UDAF]())
- } else {
- funcWrapper.createFunction[GenericUDAFResolver2]()
- }
-
- @transient
- protected lazy val inputInspectors = children.map(toInspector).toArray
-
- // The GenericUDAFEvaluator used to evaluate the window function.
- @transient
- protected lazy val evaluator: GenericUDAFEvaluator = {
- val parameterInfo = new SimpleGenericUDAFParameterInfo(inputInspectors, false, false)
- resolver.getEvaluator(parameterInfo)
- }
-
- // The object inspector of values returned from the Hive window function.
- @transient
- protected lazy val returnInspector = {
- evaluator.init(GenericUDAFEvaluator.Mode.COMPLETE, inputInspectors)
- }
-
- override val dataType: DataType =
- if (!pivotResult) {
- inspectorToDataType(returnInspector)
- } else {
- // If pivotResult is true, we should take the element type out as the data type of this
- // function.
- inspectorToDataType(returnInspector) match {
- case ArrayType(dt, _) => dt
- case _ =>
- sys.error(
- s"error resolve the data type of window function ${funcWrapper.functionClassName}")
- }
- }
-
- override def nullable: Boolean = true
-
- @transient
- lazy val inputProjection = new InterpretedProjection(children)
-
- @transient
- private var hiveEvaluatorBuffer: AggregationBuffer = _
- // Output buffer.
- private var outputBuffer: Any = _
-
- @transient
- private lazy val inputDataTypes: Array[DataType] = children.map(_.dataType).toArray
-
- override def init(): Unit = {
- evaluator.init(GenericUDAFEvaluator.Mode.COMPLETE, inputInspectors)
- }
-
- // Reset the hiveEvaluatorBuffer and outputPosition
- override def reset(): Unit = {
- // We create a new aggregation buffer to workaround the bug in GenericUDAFRowNumber.
- // Basically, GenericUDAFRowNumberEvaluator.reset calls RowNumberBuffer.init.
- // However, RowNumberBuffer.init does not really reset this buffer.
- hiveEvaluatorBuffer = evaluator.getNewAggregationBuffer
- evaluator.reset(hiveEvaluatorBuffer)
- }
-
- override def prepareInputParameters(input: InternalRow): AnyRef = {
- wrap(
- inputProjection(input),
- inputInspectors,
- new Array[AnyRef](children.length),
- inputDataTypes)
- }
-
- // Add input parameters for a single row.
- override def update(input: AnyRef): Unit = {
- evaluator.iterate(hiveEvaluatorBuffer, input.asInstanceOf[Array[AnyRef]])
- }
-
- override def batchUpdate(inputs: Array[AnyRef]): Unit = {
- var i = 0
- while (i < inputs.length) {
- evaluator.iterate(hiveEvaluatorBuffer, inputs(i).asInstanceOf[Array[AnyRef]])
- i += 1
- }
- }
-
- override def evaluate(): Unit = {
- outputBuffer = unwrap(evaluator.evaluate(hiveEvaluatorBuffer), returnInspector)
- }
-
- override def get(index: Int): Any = {
- if (!pivotResult) {
- // if pivotResult is false, we will get a single value for all rows in the frame.
- outputBuffer
- } else {
- // if pivotResult is true, we will get a ArrayData having the same size with the size
- // of the window frame. At here, we will return the result at the position of
- // index in the output buffer.
- outputBuffer.asInstanceOf[ArrayData].get(index, dataType)
- }
- }
-
- override def toString: String = {
- s"$nodeName#${funcWrapper.functionClassName}(${children.mkString(",")})"
- }
-
- override def newInstance(): WindowFunction =
- new HiveWindowFunction(funcWrapper, pivotResult, isUDAFBridgeRequired, children)
-}
-
-/**
* Converts a Hive Generic User Defined Table Generating Function (UDTF) to a
* [[Generator]]. Note that the semantics of Generators do not allow
* Generators to maintain state in between input rows. Thus UDTFs that rely on partitioning
diff --git a/sql/hive/src/test/scala/org/apache/spark/sql/hive/HiveDataFrameWindowSuite.scala b/sql/hive/src/test/scala/org/apache/spark/sql/hive/HiveDataFrameWindowSuite.scala
deleted file mode 100644
index 2c98f1c3cc..0000000000
--- a/sql/hive/src/test/scala/org/apache/spark/sql/hive/HiveDataFrameWindowSuite.scala
+++ /dev/null
@@ -1,259 +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.spark.sql.hive
-
-import org.apache.spark.sql.{Row, QueryTest}
-import org.apache.spark.sql.expressions.Window
-import org.apache.spark.sql.functions._
-import org.apache.spark.sql.hive.test.TestHiveSingleton
-
-class HiveDataFrameWindowSuite extends QueryTest with TestHiveSingleton {
- import hiveContext.implicits._
- import hiveContext.sql
-
- test("reuse window partitionBy") {
- val df = Seq((1, "1"), (2, "2"), (1, "1"), (2, "2")).toDF("key", "value")
- val w = Window.partitionBy("key").orderBy("value")
-
- checkAnswer(
- df.select(
- lead("key", 1).over(w),
- lead("value", 1).over(w)),
- Row(1, "1") :: Row(2, "2") :: Row(null, null) :: Row(null, null) :: Nil)
- }
-
- test("reuse window orderBy") {
- val df = Seq((1, "1"), (2, "2"), (1, "1"), (2, "2")).toDF("key", "value")
- val w = Window.orderBy("value").partitionBy("key")
-
- checkAnswer(
- df.select(
- lead("key", 1).over(w),
- lead("value", 1).over(w)),
- Row(1, "1") :: Row(2, "2") :: Row(null, null) :: Row(null, null) :: Nil)
- }
-
- test("lead") {
- val df = Seq((1, "1"), (2, "2"), (1, "1"), (2, "2")).toDF("key", "value")
- df.registerTempTable("window_table")
-
- checkAnswer(
- df.select(
- lead("value", 1).over(Window.partitionBy($"key").orderBy($"value"))),
- sql(
- """SELECT
- | lead(value) OVER (PARTITION BY key ORDER BY value)
- | FROM window_table""".stripMargin).collect())
- }
-
- test("lag") {
- val df = Seq((1, "1"), (2, "2"), (1, "1"), (2, "2")).toDF("key", "value")
- df.registerTempTable("window_table")
-
- checkAnswer(
- df.select(
- lag("value", 1).over(Window.partitionBy($"key").orderBy($"value"))),
- sql(
- """SELECT
- | lag(value) OVER (PARTITION BY key ORDER BY value)
- | FROM window_table""".stripMargin).collect())
- }
-
- test("lead with default value") {
- val df = Seq((1, "1"), (1, "1"), (2, "2"), (1, "1"),
- (2, "2"), (1, "1"), (2, "2")).toDF("key", "value")
- df.registerTempTable("window_table")
- checkAnswer(
- df.select(
- lead("value", 2, "n/a").over(Window.partitionBy("key").orderBy("value"))),
- sql(
- """SELECT
- | lead(value, 2, "n/a") OVER (PARTITION BY key ORDER BY value)
- | FROM window_table""".stripMargin).collect())
- }
-
- test("lag with default value") {
- val df = Seq((1, "1"), (1, "1"), (2, "2"), (1, "1"),
- (2, "2"), (1, "1"), (2, "2")).toDF("key", "value")
- df.registerTempTable("window_table")
- checkAnswer(
- df.select(
- lag("value", 2, "n/a").over(Window.partitionBy($"key").orderBy($"value"))),
- sql(
- """SELECT
- | lag(value, 2, "n/a") OVER (PARTITION BY key ORDER BY value)
- | FROM window_table""".stripMargin).collect())
- }
-
- test("rank functions in unspecific window") {
- val df = Seq((1, "1"), (2, "2"), (1, "2"), (2, "2")).toDF("key", "value")
- df.registerTempTable("window_table")
- checkAnswer(
- df.select(
- $"key",
- max("key").over(Window.partitionBy("value").orderBy("key")),
- min("key").over(Window.partitionBy("value").orderBy("key")),
- mean("key").over(Window.partitionBy("value").orderBy("key")),
- count("key").over(Window.partitionBy("value").orderBy("key")),
- sum("key").over(Window.partitionBy("value").orderBy("key")),
- ntile(2).over(Window.partitionBy("value").orderBy("key")),
- rowNumber().over(Window.partitionBy("value").orderBy("key")),
- denseRank().over(Window.partitionBy("value").orderBy("key")),
- rank().over(Window.partitionBy("value").orderBy("key")),
- cumeDist().over(Window.partitionBy("value").orderBy("key")),
- percentRank().over(Window.partitionBy("value").orderBy("key"))),
- sql(
- s"""SELECT
- |key,
- |max(key) over (partition by value order by key),
- |min(key) over (partition by value order by key),
- |avg(key) over (partition by value order by key),
- |count(key) over (partition by value order by key),
- |sum(key) over (partition by value order by key),
- |ntile(2) over (partition by value order by key),
- |row_number() over (partition by value order by key),
- |dense_rank() over (partition by value order by key),
- |rank() over (partition by value order by key),
- |cume_dist() over (partition by value order by key),
- |percent_rank() over (partition by value order by key)
- |FROM window_table""".stripMargin).collect())
- }
-
- test("aggregation and rows between") {
- val df = Seq((1, "1"), (2, "2"), (1, "1"), (2, "2")).toDF("key", "value")
- df.registerTempTable("window_table")
- checkAnswer(
- df.select(
- avg("key").over(Window.partitionBy($"value").orderBy($"key").rowsBetween(-1, 2))),
- sql(
- """SELECT
- | avg(key) OVER
- | (PARTITION BY value ORDER BY key ROWS BETWEEN 1 preceding and 2 following)
- | FROM window_table""".stripMargin).collect())
- }
-
- test("aggregation and range betweens") {
- val df = Seq((1, "1"), (2, "2"), (1, "1"), (2, "2")).toDF("key", "value")
- df.registerTempTable("window_table")
- checkAnswer(
- df.select(
- avg("key").over(Window.partitionBy($"value").orderBy($"key").rangeBetween(-1, 1))),
- sql(
- """SELECT
- | avg(key) OVER
- | (PARTITION BY value ORDER BY key RANGE BETWEEN 1 preceding and 1 following)
- | FROM window_table""".stripMargin).collect())
- }
-
- test("aggregation and rows betweens with unbounded") {
- val df = Seq((1, "1"), (2, "2"), (2, "3"), (1, "3"), (3, "2"), (4, "3")).toDF("key", "value")
- df.registerTempTable("window_table")
- checkAnswer(
- df.select(
- $"key",
- last("value").over(
- Window.partitionBy($"value").orderBy($"key").rowsBetween(0, Long.MaxValue)),
- last("value").over(
- Window.partitionBy($"value").orderBy($"key").rowsBetween(Long.MinValue, 0)),
- last("value").over(Window.partitionBy($"value").orderBy($"key").rowsBetween(-1, 3))),
- sql(
- """SELECT
- | key,
- | last_value(value) OVER
- | (PARTITION BY value ORDER BY key ROWS between current row and unbounded following),
- | last_value(value) OVER
- | (PARTITION BY value ORDER BY key ROWS between unbounded preceding and current row),
- | last_value(value) OVER
- | (PARTITION BY value ORDER BY key ROWS between 1 preceding and 3 following)
- | FROM window_table""".stripMargin).collect())
- }
-
- test("aggregation and range betweens with unbounded") {
- val df = Seq((5, "1"), (5, "2"), (4, "2"), (6, "2"), (3, "1"), (2, "2")).toDF("key", "value")
- df.registerTempTable("window_table")
- checkAnswer(
- df.select(
- $"key",
- last("value").over(
- Window.partitionBy($"value").orderBy($"key").rangeBetween(-2, -1))
- .equalTo("2")
- .as("last_v"),
- avg("key").over(Window.partitionBy("value").orderBy("key").rangeBetween(Long.MinValue, 1))
- .as("avg_key1"),
- avg("key").over(Window.partitionBy("value").orderBy("key").rangeBetween(0, Long.MaxValue))
- .as("avg_key2"),
- avg("key").over(Window.partitionBy("value").orderBy("key").rangeBetween(-1, 0))
- .as("avg_key3")
- ),
- sql(
- """SELECT
- | key,
- | last_value(value) OVER
- | (PARTITION BY value ORDER BY key RANGE BETWEEN 2 preceding and 1 preceding) == "2",
- | avg(key) OVER
- | (PARTITION BY value ORDER BY key RANGE BETWEEN unbounded preceding and 1 following),
- | avg(key) OVER
- | (PARTITION BY value ORDER BY key RANGE BETWEEN current row and unbounded following),
- | avg(key) OVER
- | (PARTITION BY value ORDER BY key RANGE BETWEEN 1 preceding and current row)
- | FROM window_table""".stripMargin).collect())
- }
-
- test("reverse sliding range frame") {
- val df = Seq(
- (1, "Thin", "Cell Phone", 6000),
- (2, "Normal", "Tablet", 1500),
- (3, "Mini", "Tablet", 5500),
- (4, "Ultra thin", "Cell Phone", 5500),
- (5, "Very thin", "Cell Phone", 6000),
- (6, "Big", "Tablet", 2500),
- (7, "Bendable", "Cell Phone", 3000),
- (8, "Foldable", "Cell Phone", 3000),
- (9, "Pro", "Tablet", 4500),
- (10, "Pro2", "Tablet", 6500)).
- toDF("id", "product", "category", "revenue")
- val window = Window.
- partitionBy($"category").
- orderBy($"revenue".desc).
- rangeBetween(-2000L, 1000L)
- checkAnswer(
- df.select(
- $"id",
- avg($"revenue").over(window).cast("int")),
- Row(1, 5833) :: Row(2, 2000) :: Row(3, 5500) ::
- Row(4, 5833) :: Row(5, 5833) :: Row(6, 2833) ::
- Row(7, 3000) :: Row(8, 3000) :: Row(9, 5500) ::
- Row(10, 6000) :: Nil)
- }
-
- // This is here to illustrate the fact that reverse order also reverses offsets.
- test("reverse unbounded range frame") {
- val df = Seq(1, 2, 4, 3, 2, 1).
- map(Tuple1.apply).
- toDF("value")
- val window = Window.orderBy($"value".desc)
- checkAnswer(
- df.select(
- $"value",
- sum($"value").over(window.rangeBetween(Long.MinValue, 1)),
- sum($"value").over(window.rangeBetween(1, Long.MaxValue))),
- Row(1, 13, null) :: Row(2, 13, 2) :: Row(4, 7, 9) ::
- Row(3, 11, 6) :: Row(2, 13, 2) :: Row(1, 13, null) :: Nil)
-
- }
-}
diff --git a/sql/hive/src/test/scala/org/apache/spark/sql/hive/execution/WindowQuerySuite.scala b/sql/hive/src/test/scala/org/apache/spark/sql/hive/execution/WindowQuerySuite.scala
new file mode 100644
index 0000000000..c05dbfd760
--- /dev/null
+++ b/sql/hive/src/test/scala/org/apache/spark/sql/hive/execution/WindowQuerySuite.scala
@@ -0,0 +1,230 @@
+/*
+ * 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.spark.sql.hive.execution
+
+import org.apache.spark.sql._
+import org.apache.spark.sql.hive.test.{TestHive, TestHiveSingleton}
+import org.apache.spark.sql.test.SQLTestUtils
+
+/**
+ * This suite contains a couple of Hive window tests which fail in the typical setup due to tiny
+ * numerical differences or due semantic differences between Hive and Spark.
+ */
+class WindowQuerySuite extends QueryTest with SQLTestUtils with TestHiveSingleton {
+
+ override def beforeAll(): Unit = {
+ sql("DROP TABLE IF EXISTS part")
+ sql(
+ """
+ |CREATE TABLE part(
+ | p_partkey INT,
+ | p_name STRING,
+ | p_mfgr STRING,
+ | p_brand STRING,
+ | p_type STRING,
+ | p_size INT,
+ | p_container STRING,
+ | p_retailprice DOUBLE,
+ | p_comment STRING)
+ """.stripMargin)
+ val testData1 = TestHive.getHiveFile("data/files/part_tiny.txt").getCanonicalPath
+ sql(
+ s"""
+ |LOAD DATA LOCAL INPATH '$testData1' overwrite into table part
+ """.stripMargin)
+ }
+
+ override def afterAll(): Unit = {
+ sql("DROP TABLE IF EXISTS part")
+ }
+
+ test("windowing.q -- 15. testExpressions") {
+ // Moved because:
+ // - Spark uses a different default stddev (sample instead of pop)
+ // - Tiny numerical differences in stddev results.
+ // - Different StdDev behavior when n=1 (NaN instead of 0)
+ checkAnswer(sql(s"""
+ |select p_mfgr,p_name, p_size,
+ |rank() over(distribute by p_mfgr sort by p_name) as r,
+ |dense_rank() over(distribute by p_mfgr sort by p_name) as dr,
+ |cume_dist() over(distribute by p_mfgr sort by p_name) as cud,
+ |percent_rank() over(distribute by p_mfgr sort by p_name) as pr,
+ |ntile(3) over(distribute by p_mfgr sort by p_name) as nt,
+ |count(p_size) over(distribute by p_mfgr sort by p_name) as ca,
+ |avg(p_size) over(distribute by p_mfgr sort by p_name) as avg,
+ |stddev(p_size) over(distribute by p_mfgr sort by p_name) as st,
+ |first_value(p_size % 5) over(distribute by p_mfgr sort by p_name) as fv,
+ |last_value(p_size) over(distribute by p_mfgr sort by p_name) as lv,
+ |first_value(p_size) over w1 as fvW1
+ |from part
+ |window w1 as (distribute by p_mfgr sort by p_mfgr, p_name
+ | rows between 2 preceding and 2 following)
+ """.stripMargin),
+ // scalastyle:off
+ Seq(
+ Row("Manufacturer#1", "almond antique burnished rose metallic", 2, 1, 1, 0.3333333333333333, 0.0, 1, 2, 2.0, 0.0, 2, 2, 2),
+ Row("Manufacturer#1", "almond antique burnished rose metallic", 2, 1, 1, 0.3333333333333333, 0.0, 1, 2, 2.0, 0.0, 2, 2, 2),
+ Row("Manufacturer#1", "almond antique chartreuse lavender yellow", 34, 3, 2, 0.5, 0.4, 2, 3, 12.666666666666666, 18.475208614068027, 2, 34, 2),
+ Row("Manufacturer#1", "almond antique salmon chartreuse burlywood", 6, 4, 3, 0.6666666666666666, 0.6, 2, 4, 11.0, 15.448840301675292, 2, 6, 2),
+ Row("Manufacturer#1", "almond aquamarine burnished black steel", 28, 5, 4, 0.8333333333333334, 0.8, 3, 5, 14.4, 15.388307249337076, 2, 28, 34),
+ Row("Manufacturer#1", "almond aquamarine pink moccasin thistle", 42, 6, 5, 1.0, 1.0, 3, 6, 19.0, 17.787636155487327, 2, 42, 6),
+ Row("Manufacturer#2", "almond antique violet chocolate turquoise", 14, 1, 1, 0.2, 0.0, 1, 1, 14.0, Double.NaN, 4, 14, 14),
+ Row("Manufacturer#2", "almond antique violet turquoise frosted", 40, 2, 2, 0.4, 0.25, 1, 2, 27.0, 18.384776310850235, 4, 40, 14),
+ Row("Manufacturer#2", "almond aquamarine midnight light salmon", 2, 3, 3, 0.6, 0.5, 2, 3, 18.666666666666668, 19.42506971244462, 4, 2, 14),
+ Row("Manufacturer#2", "almond aquamarine rose maroon antique", 25, 4, 4, 0.8, 0.75, 2, 4, 20.25, 16.17353805861084, 4, 25, 40),
+ Row("Manufacturer#2", "almond aquamarine sandy cyan gainsboro", 18, 5, 5, 1.0, 1.0, 3, 5, 19.8, 14.042791745233567, 4, 18, 2),
+ Row("Manufacturer#3", "almond antique chartreuse khaki white", 17, 1, 1, 0.2, 0.0, 1, 1, 17.0,Double.NaN, 2, 17, 17),
+ Row("Manufacturer#3", "almond antique forest lavender goldenrod", 14, 2, 2, 0.4, 0.25, 1, 2, 15.5, 2.1213203435596424, 2, 14, 17),
+ Row("Manufacturer#3", "almond antique metallic orange dim", 19, 3, 3, 0.6, 0.5, 2, 3, 16.666666666666668, 2.516611478423583, 2, 19, 17),
+ Row("Manufacturer#3", "almond antique misty red olive", 1, 4, 4, 0.8, 0.75, 2, 4, 12.75, 8.098353742170895, 2, 1, 14),
+ Row("Manufacturer#3", "almond antique olive coral navajo", 45, 5, 5, 1.0, 1.0, 3, 5, 19.2, 16.037456157383566, 2, 45, 19),
+ Row("Manufacturer#4", "almond antique gainsboro frosted violet", 10, 1, 1, 0.2, 0.0, 1, 1, 10.0, Double.NaN, 0, 10, 10),
+ Row("Manufacturer#4", "almond antique violet mint lemon", 39, 2, 2, 0.4, 0.25, 1, 2, 24.5, 20.506096654409877, 0, 39, 10),
+ Row("Manufacturer#4", "almond aquamarine floral ivory bisque", 27, 3, 3, 0.6, 0.5, 2, 3, 25.333333333333332, 14.571661996262929, 0, 27, 10),
+ Row("Manufacturer#4", "almond aquamarine yellow dodger mint", 7, 4, 4, 0.8, 0.75, 2, 4, 20.75, 15.01943185787443, 0, 7, 39),
+ Row("Manufacturer#4", "almond azure aquamarine papaya violet", 12, 5, 5, 1.0, 1.0, 3, 5, 19.0, 13.583077707206124, 0, 12, 27),
+ Row("Manufacturer#5", "almond antique blue firebrick mint", 31, 1, 1, 0.2, 0.0, 1, 1, 31.0, Double.NaN, 1, 31, 31),
+ Row("Manufacturer#5", "almond antique medium spring khaki", 6, 2, 2, 0.4, 0.25, 1, 2, 18.5, 17.67766952966369, 1, 6, 31),
+ Row("Manufacturer#5", "almond antique sky peru orange", 2, 3, 3, 0.6, 0.5, 2, 3, 13.0, 15.716233645501712, 1, 2, 31),
+ Row("Manufacturer#5", "almond aquamarine dodger light gainsboro", 46, 4, 4, 0.8, 0.75, 2, 4, 21.25, 20.902551678363736, 1, 46, 6),
+ Row("Manufacturer#5", "almond azure blanched chiffon midnight", 23, 5, 5, 1.0, 1.0, 3, 5, 21.6, 18.1190507477627, 1, 23, 2)))
+ // scalastyle:on
+ }
+
+ test("windowing.q -- 20. testSTATs") {
+ // Moved because:
+ // - Spark uses a different default stddev/variance (sample instead of pop)
+ // - Tiny numerical differences in aggregation results.
+ checkAnswer(sql("""
+ |select p_mfgr,p_name, p_size, sdev, sdev_pop, uniq_data, var, cor, covarp
+ |from (
+ |select p_mfgr,p_name, p_size,
+ |stddev_pop(p_retailprice) over w1 as sdev,
+ |stddev_pop(p_retailprice) over w1 as sdev_pop,
+ |collect_set(p_size) over w1 as uniq_size,
+ |var_pop(p_retailprice) over w1 as var,
+ |corr(p_size, p_retailprice) over w1 as cor,
+ |covar_pop(p_size, p_retailprice) over w1 as covarp
+ |from part
+ |window w1 as (distribute by p_mfgr sort by p_mfgr, p_name
+ | rows between 2 preceding and 2 following)
+ |) t lateral view explode(uniq_size) d as uniq_data
+ |order by p_mfgr,p_name, p_size, sdev, sdev_pop, uniq_data, var, cor, covarp
+ """.stripMargin),
+ // scalastyle:off
+ Seq(
+ Row("Manufacturer#1", "almond antique burnished rose metallic", 2, 258.10677784349247, 258.10677784349247, 2, 66619.10876874997, 0.811328754177887, 2801.7074999999995),
+ Row("Manufacturer#1", "almond antique burnished rose metallic", 2, 258.10677784349247, 258.10677784349247, 6, 66619.10876874997, 0.811328754177887, 2801.7074999999995),
+ Row("Manufacturer#1", "almond antique burnished rose metallic", 2, 258.10677784349247, 258.10677784349247, 34, 66619.10876874997, 0.811328754177887, 2801.7074999999995),
+ Row("Manufacturer#1", "almond antique burnished rose metallic", 2, 273.70217881648085, 273.70217881648085, 2, 74912.88268888886, 1.0, 4128.782222222221),
+ Row("Manufacturer#1", "almond antique burnished rose metallic", 2, 273.70217881648085, 273.70217881648085, 34, 74912.88268888886, 1.0, 4128.782222222221),
+ Row("Manufacturer#1", "almond antique chartreuse lavender yellow", 34, 230.9015158547037, 230.9015158547037, 2, 53315.510023999974, 0.6956393773976641, 2210.7864),
+ Row("Manufacturer#1", "almond antique chartreuse lavender yellow", 34, 230.9015158547037, 230.9015158547037, 6, 53315.510023999974, 0.6956393773976641, 2210.7864),
+ Row("Manufacturer#1", "almond antique chartreuse lavender yellow", 34, 230.9015158547037, 230.9015158547037, 28, 53315.510023999974, 0.6956393773976641, 2210.7864),
+ Row("Manufacturer#1", "almond antique chartreuse lavender yellow", 34, 230.9015158547037, 230.9015158547037, 34, 53315.510023999974, 0.6956393773976641, 2210.7864),
+ Row("Manufacturer#1", "almond antique salmon chartreuse burlywood", 6, 202.73109328368943, 202.73109328368943, 2, 41099.89618399999, 0.6307859771012139, 2009.9536000000007),
+ Row("Manufacturer#1", "almond antique salmon chartreuse burlywood", 6, 202.73109328368943, 202.73109328368943, 6, 41099.89618399999, 0.6307859771012139, 2009.9536000000007),
+ Row("Manufacturer#1", "almond antique salmon chartreuse burlywood", 6, 202.73109328368943, 202.73109328368943, 28, 41099.89618399999, 0.6307859771012139, 2009.9536000000007),
+ Row("Manufacturer#1", "almond antique salmon chartreuse burlywood", 6, 202.73109328368943, 202.73109328368943, 34, 41099.89618399999, 0.6307859771012139, 2009.9536000000007),
+ Row("Manufacturer#1", "almond antique salmon chartreuse burlywood", 6, 202.73109328368943, 202.73109328368943, 42, 41099.89618399999, 0.6307859771012139, 2009.9536000000007),
+ Row("Manufacturer#1", "almond aquamarine burnished black steel", 28, 121.60645179738611, 121.60645179738611, 6, 14788.129118749992, 0.2036684720435979, 331.1337500000004),
+ Row("Manufacturer#1", "almond aquamarine burnished black steel", 28, 121.60645179738611, 121.60645179738611, 28, 14788.129118749992, 0.2036684720435979, 331.1337500000004),
+ Row("Manufacturer#1", "almond aquamarine burnished black steel", 28, 121.60645179738611, 121.60645179738611, 34, 14788.129118749992, 0.2036684720435979, 331.1337500000004),
+ Row("Manufacturer#1", "almond aquamarine burnished black steel", 28, 121.60645179738611, 121.60645179738611, 42, 14788.129118749992, 0.2036684720435979, 331.1337500000004),
+ Row("Manufacturer#1", "almond aquamarine pink moccasin thistle", 42, 96.57515864168516, 96.57515864168516, 6, 9326.761266666656, -1.4442181184933883E-4, -0.20666666666708502),
+ Row("Manufacturer#1", "almond aquamarine pink moccasin thistle", 42, 96.57515864168516, 96.57515864168516, 28, 9326.761266666656, -1.4442181184933883E-4, -0.20666666666708502),
+ Row("Manufacturer#1", "almond aquamarine pink moccasin thistle", 42, 96.57515864168516, 96.57515864168516, 42, 9326.761266666656, -1.4442181184933883E-4, -0.20666666666708502),
+ Row("Manufacturer#2", "almond antique violet chocolate turquoise", 14, 142.23631697518977, 142.23631697518977, 2, 20231.16986666666, -0.4936952655452319, -1113.7466666666658),
+ Row("Manufacturer#2", "almond antique violet chocolate turquoise", 14, 142.23631697518977, 142.23631697518977, 14, 20231.16986666666, -0.4936952655452319, -1113.7466666666658),
+ Row("Manufacturer#2", "almond antique violet chocolate turquoise", 14, 142.23631697518977, 142.23631697518977, 40, 20231.16986666666, -0.4936952655452319, -1113.7466666666658),
+ Row("Manufacturer#2", "almond antique violet turquoise frosted", 40, 137.7630649884068, 137.7630649884068, 2, 18978.662074999997, -0.5205630897335946, -1004.4812499999995),
+ Row("Manufacturer#2", "almond antique violet turquoise frosted", 40, 137.7630649884068, 137.7630649884068, 14, 18978.662074999997, -0.5205630897335946, -1004.4812499999995),
+ Row("Manufacturer#2", "almond antique violet turquoise frosted", 40, 137.7630649884068, 137.7630649884068, 25, 18978.662074999997, -0.5205630897335946, -1004.4812499999995),
+ Row("Manufacturer#2", "almond antique violet turquoise frosted", 40, 137.7630649884068, 137.7630649884068, 40, 18978.662074999997, -0.5205630897335946, -1004.4812499999995),
+ Row("Manufacturer#2", "almond aquamarine midnight light salmon", 2, 130.03972279269132, 130.03972279269132, 2, 16910.329504000005, -0.46908967495720255, -766.1791999999995),
+ Row("Manufacturer#2", "almond aquamarine midnight light salmon", 2, 130.03972279269132, 130.03972279269132, 14, 16910.329504000005, -0.46908967495720255, -766.1791999999995),
+ Row("Manufacturer#2", "almond aquamarine midnight light salmon", 2, 130.03972279269132, 130.03972279269132, 18, 16910.329504000005, -0.46908967495720255, -766.1791999999995),
+ Row("Manufacturer#2", "almond aquamarine midnight light salmon", 2, 130.03972279269132, 130.03972279269132, 25, 16910.329504000005, -0.46908967495720255, -766.1791999999995),
+ Row("Manufacturer#2", "almond aquamarine midnight light salmon", 2, 130.03972279269132, 130.03972279269132, 40, 16910.329504000005, -0.46908967495720255, -766.1791999999995),
+ Row("Manufacturer#2", "almond aquamarine rose maroon antique", 25, 135.55100986344593, 135.55100986344593, 2, 18374.076275000018, -0.6091405874714462, -1128.1787499999987),
+ Row("Manufacturer#2", "almond aquamarine rose maroon antique", 25, 135.55100986344593, 135.55100986344593, 18, 18374.076275000018, -0.6091405874714462, -1128.1787499999987),
+ Row("Manufacturer#2", "almond aquamarine rose maroon antique", 25, 135.55100986344593, 135.55100986344593, 25, 18374.076275000018, -0.6091405874714462, -1128.1787499999987),
+ Row("Manufacturer#2", "almond aquamarine rose maroon antique", 25, 135.55100986344593, 135.55100986344593, 40, 18374.076275000018, -0.6091405874714462, -1128.1787499999987),
+ Row("Manufacturer#2", "almond aquamarine sandy cyan gainsboro", 18, 156.44019460768035, 156.44019460768035, 2, 24473.534488888898, -0.9571686373491605, -1441.4466666666676),
+ Row("Manufacturer#2", "almond aquamarine sandy cyan gainsboro", 18, 156.44019460768035, 156.44019460768035, 18, 24473.534488888898, -0.9571686373491605, -1441.4466666666676),
+ Row("Manufacturer#2", "almond aquamarine sandy cyan gainsboro", 18, 156.44019460768035, 156.44019460768035, 25, 24473.534488888898, -0.9571686373491605, -1441.4466666666676),
+ Row("Manufacturer#3", "almond antique chartreuse khaki white", 17, 196.77422668858057, 196.77422668858057, 14, 38720.0962888889, 0.5557168646224995, 224.6944444444446),
+ Row("Manufacturer#3", "almond antique chartreuse khaki white", 17, 196.77422668858057, 196.77422668858057, 17, 38720.0962888889, 0.5557168646224995, 224.6944444444446),
+ Row("Manufacturer#3", "almond antique chartreuse khaki white", 17, 196.77422668858057, 196.77422668858057, 19, 38720.0962888889, 0.5557168646224995, 224.6944444444446),
+ Row("Manufacturer#3", "almond antique forest lavender goldenrod", 14, 275.1414418985261, 275.1414418985261, 1, 75702.81305000003, -0.6720833036576083, -1296.9000000000003),
+ Row("Manufacturer#3", "almond antique forest lavender goldenrod", 14, 275.1414418985261, 275.1414418985261, 14, 75702.81305000003, -0.6720833036576083, -1296.9000000000003),
+ Row("Manufacturer#3", "almond antique forest lavender goldenrod", 14, 275.1414418985261, 275.1414418985261, 17, 75702.81305000003, -0.6720833036576083, -1296.9000000000003),
+ Row("Manufacturer#3", "almond antique forest lavender goldenrod", 14, 275.1414418985261, 275.1414418985261, 19, 75702.81305000003, -0.6720833036576083, -1296.9000000000003),
+ Row("Manufacturer#3", "almond antique metallic orange dim", 19, 260.23473614412046, 260.23473614412046, 1, 67722.11789600001, -0.5703526513979519, -2129.0664),
+ Row("Manufacturer#3", "almond antique metallic orange dim", 19, 260.23473614412046, 260.23473614412046, 14, 67722.11789600001, -0.5703526513979519, -2129.0664),
+ Row("Manufacturer#3", "almond antique metallic orange dim", 19, 260.23473614412046, 260.23473614412046, 17, 67722.11789600001, -0.5703526513979519, -2129.0664),
+ Row("Manufacturer#3", "almond antique metallic orange dim", 19, 260.23473614412046, 260.23473614412046, 19, 67722.11789600001, -0.5703526513979519, -2129.0664),
+ Row("Manufacturer#3", "almond antique metallic orange dim", 19, 260.23473614412046, 260.23473614412046, 45, 67722.11789600001, -0.5703526513979519, -2129.0664),
+ Row("Manufacturer#3", "almond antique misty red olive", 1, 275.913996235693, 275.913996235693, 1, 76128.53331875002, -0.5774768996448021, -2547.7868749999993),
+ Row("Manufacturer#3", "almond antique misty red olive", 1, 275.913996235693, 275.913996235693, 14, 76128.53331875002, -0.5774768996448021, -2547.7868749999993),
+ Row("Manufacturer#3", "almond antique misty red olive", 1, 275.913996235693, 275.913996235693, 19, 76128.53331875002, -0.5774768996448021, -2547.7868749999993),
+ Row("Manufacturer#3", "almond antique misty red olive", 1, 275.913996235693, 275.913996235693, 45, 76128.53331875002, -0.5774768996448021, -2547.7868749999993),
+ Row("Manufacturer#3", "almond antique olive coral navajo", 45, 260.58159187137954, 260.58159187137954, 1, 67902.7660222222, -0.8710736366736884, -4099.731111111111),
+ Row("Manufacturer#3", "almond antique olive coral navajo", 45, 260.58159187137954, 260.58159187137954, 19, 67902.7660222222, -0.8710736366736884, -4099.731111111111),
+ Row("Manufacturer#3", "almond antique olive coral navajo", 45, 260.58159187137954, 260.58159187137954, 45, 67902.7660222222, -0.8710736366736884, -4099.731111111111),
+ Row("Manufacturer#4", "almond antique gainsboro frosted violet", 10, 170.1301188959661, 170.1301188959661, 10, 28944.25735555556, -0.6656975320098423, -1347.4777777777779),
+ Row("Manufacturer#4", "almond antique gainsboro frosted violet", 10, 170.1301188959661, 170.1301188959661, 27, 28944.25735555556, -0.6656975320098423, -1347.4777777777779),
+ Row("Manufacturer#4", "almond antique gainsboro frosted violet", 10, 170.1301188959661, 170.1301188959661, 39, 28944.25735555556, -0.6656975320098423, -1347.4777777777779),
+ Row("Manufacturer#4", "almond antique violet mint lemon", 39, 242.26834609323197, 242.26834609323197, 7, 58693.95151875002, -0.8051852719193339, -2537.328125),
+ Row("Manufacturer#4", "almond antique violet mint lemon", 39, 242.26834609323197, 242.26834609323197, 10, 58693.95151875002, -0.8051852719193339, -2537.328125),
+ Row("Manufacturer#4", "almond antique violet mint lemon", 39, 242.26834609323197, 242.26834609323197, 27, 58693.95151875002, -0.8051852719193339, -2537.328125),
+ Row("Manufacturer#4", "almond antique violet mint lemon", 39, 242.26834609323197, 242.26834609323197, 39, 58693.95151875002, -0.8051852719193339, -2537.328125),
+ Row("Manufacturer#4", "almond aquamarine floral ivory bisque", 27, 234.10001662537323, 234.10001662537323, 7, 54802.81778400003, -0.6046935574240581, -1719.8079999999995),
+ Row("Manufacturer#4", "almond aquamarine floral ivory bisque", 27, 234.10001662537323, 234.10001662537323, 10, 54802.81778400003, -0.6046935574240581, -1719.8079999999995),
+ Row("Manufacturer#4", "almond aquamarine floral ivory bisque", 27, 234.10001662537323, 234.10001662537323, 12, 54802.81778400003, -0.6046935574240581, -1719.8079999999995),
+ Row("Manufacturer#4", "almond aquamarine floral ivory bisque", 27, 234.10001662537323, 234.10001662537323, 27, 54802.81778400003, -0.6046935574240581, -1719.8079999999995),
+ Row("Manufacturer#4", "almond aquamarine floral ivory bisque", 27, 234.10001662537323, 234.10001662537323, 39, 54802.81778400003, -0.6046935574240581, -1719.8079999999995),
+ Row("Manufacturer#4", "almond aquamarine yellow dodger mint", 7, 247.33427141977316, 247.33427141977316, 7, 61174.241818750015, -0.5508665654707869, -1719.0368749999975),
+ Row("Manufacturer#4", "almond aquamarine yellow dodger mint", 7, 247.33427141977316, 247.33427141977316, 12, 61174.241818750015, -0.5508665654707869, -1719.0368749999975),
+ Row("Manufacturer#4", "almond aquamarine yellow dodger mint", 7, 247.33427141977316, 247.33427141977316, 27, 61174.241818750015, -0.5508665654707869, -1719.0368749999975),
+ Row("Manufacturer#4", "almond aquamarine yellow dodger mint", 7, 247.33427141977316, 247.33427141977316, 39, 61174.241818750015, -0.5508665654707869, -1719.0368749999975),
+ Row("Manufacturer#4", "almond azure aquamarine papaya violet", 12, 283.33443305668936, 283.33443305668936, 7, 80278.4009555556, -0.7755740084632333, -1867.4888888888881),
+ Row("Manufacturer#4", "almond azure aquamarine papaya violet", 12, 283.33443305668936, 283.33443305668936, 12, 80278.4009555556, -0.7755740084632333, -1867.4888888888881),
+ Row("Manufacturer#4", "almond azure aquamarine papaya violet", 12, 283.33443305668936, 283.33443305668936, 27, 80278.4009555556, -0.7755740084632333, -1867.4888888888881),
+ Row("Manufacturer#5", "almond antique blue firebrick mint", 31, 83.69879024746344, 83.69879024746344, 2, 7005.487488888881, 0.3900430308728505, 418.9233333333353),
+ Row("Manufacturer#5", "almond antique blue firebrick mint", 31, 83.69879024746344, 83.69879024746344, 6, 7005.487488888881, 0.3900430308728505, 418.9233333333353),
+ Row("Manufacturer#5", "almond antique blue firebrick mint", 31, 83.69879024746344, 83.69879024746344, 31, 7005.487488888881, 0.3900430308728505, 418.9233333333353),
+ Row("Manufacturer#5", "almond antique medium spring khaki", 6, 316.68049612345885, 316.68049612345885, 2, 100286.53662500005, -0.7136129117761831, -4090.853749999999),
+ Row("Manufacturer#5", "almond antique medium spring khaki", 6, 316.68049612345885, 316.68049612345885, 6, 100286.53662500005, -0.7136129117761831, -4090.853749999999),
+ Row("Manufacturer#5", "almond antique medium spring khaki", 6, 316.68049612345885, 316.68049612345885, 31, 100286.53662500005, -0.7136129117761831, -4090.853749999999),
+ Row("Manufacturer#5", "almond antique medium spring khaki", 6, 316.68049612345885, 316.68049612345885, 46, 100286.53662500005, -0.7136129117761831, -4090.853749999999),
+ Row("Manufacturer#5", "almond antique sky peru orange", 2, 285.4050629824216, 285.4050629824216, 2, 81456.04997600004, -0.712858514567818, -3297.2011999999986),
+ Row("Manufacturer#5", "almond antique sky peru orange", 2, 285.4050629824216, 285.4050629824216, 6, 81456.04997600004, -0.712858514567818, -3297.2011999999986),
+ Row("Manufacturer#5", "almond antique sky peru orange", 2, 285.4050629824216, 285.4050629824216, 23, 81456.04997600004, -0.712858514567818, -3297.2011999999986),
+ Row("Manufacturer#5", "almond antique sky peru orange", 2, 285.4050629824216, 285.4050629824216, 31, 81456.04997600004, -0.712858514567818, -3297.2011999999986),
+ Row("Manufacturer#5", "almond antique sky peru orange", 2, 285.4050629824216, 285.4050629824216, 46, 81456.04997600004, -0.712858514567818, -3297.2011999999986),
+ Row("Manufacturer#5", "almond aquamarine dodger light gainsboro", 46, 285.43749038756283, 285.43749038756283, 2, 81474.56091875004, -0.9841287871533909, -4871.028125000002),
+ Row("Manufacturer#5", "almond aquamarine dodger light gainsboro", 46, 285.43749038756283, 285.43749038756283, 6, 81474.56091875004, -0.9841287871533909, -4871.028125000002),
+ Row("Manufacturer#5", "almond aquamarine dodger light gainsboro", 46, 285.43749038756283, 285.43749038756283, 23, 81474.56091875004, -0.9841287871533909, -4871.028125000002),
+ Row("Manufacturer#5", "almond aquamarine dodger light gainsboro", 46, 285.43749038756283, 285.43749038756283, 46, 81474.56091875004, -0.9841287871533909, -4871.028125000002),
+ Row("Manufacturer#5", "almond azure blanched chiffon midnight", 23, 315.9225931564038, 315.9225931564038, 2, 99807.08486666666, -0.9978877469246935, -5664.856666666666),
+ Row("Manufacturer#5", "almond azure blanched chiffon midnight", 23, 315.9225931564038, 315.9225931564038, 23, 99807.08486666666, -0.9978877469246935, -5664.856666666666),
+ Row("Manufacturer#5", "almond azure blanched chiffon midnight", 23, 315.9225931564038, 315.9225931564038, 46, 99807.08486666666, -0.9978877469246935, -5664.856666666666)))
+ // scalastyle:on
+ }
+}