Uh oh!
There was an error while loading. Please reload this page.
[SPARK-24305][SQL][FOLLOWUP] Avoid serialization of private fields in collection expressions. - #21352
[SPARK-24305][SQL][FOLLOWUP] Avoid serialization of private fields in collection expressions.#21352mn-mikke wants to merge 12 commits into
Conversation
… new collection expressions.
mn-mikke
commented
May 17, 2018
mgaido91
commented
May 17, 2018
in most of the cases these are lazy fields which are called only on the execution, so I don't think they are serialized. And in some cases (I am thinking to the ordering ones) with this patch we are executing the same computation for each row, which means a performance regression. I am not sure honestly we do need this. @cloud-fan what do you think? |
cloud-fan
commented
May 17, 2018
adding |
| override protected def nullSafeEval(input: Any): Any = { | ||
| var min: Any = null | ||
| val ordering = TypeUtils.getInterpretedOrdering(dataType) |
There was a problem hiding this comment.
We can't do this, nullSafeEval is called for every input record
| lazy val elementType: DataType = dataType.asInstanceOf[ArrayType].elementType | ||
| @transient | ||
| private lazy val elementType: DataType = dataType.asInstanceOf[ArrayType].elementType |
There was a problem hiding this comment.
this is not serialized since it is lazy and it is used only in the eval methods. I think we don't need this change, so.
There was a problem hiding this comment.
What about the arrayCodeGen method, isn't it executed before seriealization?
There was a problem hiding this comment.
code generation is executed on each partition so I'd say no, it is not executed before serialization.
There was a problem hiding this comment.
I feel the benefit of adding @transient is: we don't need to think about if this method is called on executor side only. We never serialize it.
There was a problem hiding this comment.
@mgaido91 Thanks for clarification! I thought that code gets generated and compiled on the driver and sent to each executor.
There was a problem hiding this comment.
sure, np. Anyway, if you all think that it is good to add it, then let's do it and ignore my comments related to @transient please.
| lazy val elementType: DataType = x.dataType.asInstanceOf[ArrayType].elementType | ||
| @transient | ||
| private lazy val elementType: DataType = x.dataType.asInstanceOf[ArrayType].elementType |
There was a problem hiding this comment.
What about genCodeForResult?
| override def inputTypes: Seq[AbstractDataType] = Seq(ArrayType) | ||
| @transient |
There was a problem hiding this comment.
Yeah, here it isn't necessary.
| override def inputTypes: Seq[AbstractDataType] = Seq(ArrayType) | ||
| @transient |
| override def dataType: DataType = children.map(_.dataType).headOption.getOrElse(StringType) | ||
| @transient |
There was a problem hiding this comment.
for all this related to code generation, please refer to #21352 (comment)
| case class Concat(children: Seq[Expression]) extends Expression { | ||
| private val MAX_ARRAY_LENGTH: Int = ByteArrayMethods.MAX_ROUNDED_ARRAY_LENGTH | ||
| private def maxArrayLength: Int = ByteArrayMethods.MAX_ROUNDED_ARRAY_LENGTH |
There was a problem hiding this comment.
since ByteArrayMethods.MAX_ROUNDED_ARRAY_LENGTH is a static value, what about using directly it in the methods instead of defining a quite useless def?
| case class Flatten(child: Expression) extends UnaryExpression { | ||
| private val MAX_ARRAY_LENGTH = ByteArrayMethods.MAX_ROUNDED_ARRAY_LENGTH | ||
| private def maxArrayLength: Int = ByteArrayMethods.MAX_ROUNDED_ARRAY_LENGTH |
| extends BinaryExpression with ExpectsInputTypes { | ||
| private val MAX_ARRAY_LENGTH = ByteArrayMethods.MAX_ROUNDED_ARRAY_LENGTH | ||
| private def maxArrayLength: Int = ByteArrayMethods.MAX_ROUNDED_ARRAY_LENGTH |
| override def dataType: DataType = childDataType.elementType | ||
| lazy val elementType: DataType = dataType.asInstanceOf[ArrayType].elementType | ||
| @transient |
SparkQA
commented
May 17, 2018
Test build #90730 has finished for PR 21352 at commit
|
SparkQA
commented
May 17, 2018
Test build #90733 has finished for PR 21352 at commit
|
SparkQA
commented
May 17, 2018
Test build #90740 has finished for PR 21352 at commit
|
SparkQA
commented
May 17, 2018
Test build #90747 has finished for PR 21352 at commit
|
ueshin
commented
May 18, 2018
Jenkins, retest this please. |
SparkQA
commented
May 18, 2018
Test build #90767 has finished for PR 21352 at commit
|
mn-mikke
commented
May 18, 2018
retest this please |
SparkQA
commented
May 18, 2018
Test build #90781 has finished for PR 21352 at commit
|
HyukjinKwon
commented
Jul 16, 2018
ok to test |
SparkQA
commented
Jul 16, 2018
Test build #93062 has finished for PR 21352 at commit
|
| private val MAX_ARRAY_LENGTH = ByteArrayMethods.MAX_ROUNDED_ARRAY_LENGTH | ||
| @transient | ||
| private lazy val childDataType: ArrayType = child.dataType.asInstanceOf[ArrayType] |
There was a problem hiding this comment.
we should only use lazy val if it can save some heavy computation. For things like this, I think def is good enough
…ering more expressions.
| @transient private lazy val dataTypeDetails: Option[(MapType, Boolean, Boolean)] = { | ||
| child.dataType match { | ||
| case ArrayType( | ||
| StructType(Array( |
There was a problem hiding this comment.
the indentation seems wrong here.
cloud-fan
commented
Jul 16, 2018
LGTM |
| override def dataType: DataType = child.dataType | ||
| @transient lazy val elementType: DataType = dataType.asInstanceOf[ArrayType].elementType | ||
| private def elementType: DataType = dataType.asInstanceOf[ArrayType].elementType |
There was a problem hiding this comment.
nit: as this is used in the eval method, with this PR we are re-evaluating this code for each row. Despite probably it is not a big issue, I'd rather not introduce perf regression. WDYT @cloud-fan ?
There was a problem hiding this comment.
+1. If it's used in eval, let's use lazy val, as it will be called for every input. Are there more places like this?
There was a problem hiding this comment.
SparkQA
commented
Jul 16, 2018
Test build #93115 has finished for PR 21352 at commit
|
SparkQA
commented
Jul 16, 2018
Test build #93116 has finished for PR 21352 at commit
|
| @transient lazy val numberOfArrays: Int = children.length | ||
| override def nullable: Boolean = children.exists(_.nullable) | ||
| @transient private lazy val arrayElementTypes = { |
There was a problem hiding this comment.
nit: I think we don't need the braces
| override def inputTypes: Seq[AbstractDataType] = Seq(MapType) | ||
| lazy val childDataType: MapType = child.dataType.asInstanceOf[MapType] | ||
| private def childDataType: MapType = child.dataType.asInstanceOf[MapType] |
There was a problem hiding this comment.
I missed that one. Thanks!
| StructField(_, valueType, valueNullable, _))), | ||
| containsNull) => Some((MapType(keyType, valueType, valueNullable), keyNullable, containsNull)) | ||
| case _ => None | ||
| @transient private lazy val dataTypeDetails: Option[(MapType, Boolean, Boolean)] = { |
There was a problem hiding this comment.
this is an unneeded change, isn't it?
There was a problem hiding this comment.
Here I wanted to be consistent in terms of formatting. (@transient to be on the same line as private lazy val dataTypeDetails) After the change, two lines were exceeding 100 characters.
There was a problem hiding this comment.
I see, but this seems an unneeded change to me and I think there are other places where we use this syntax, so I see no reason to change it
| child.dataType match { | ||
| case ArrayType( | ||
| StructType(Array( | ||
| StructField(_, kt, kn, _), |
There was a problem hiding this comment.
nit: Is there any reason to change variable names? It would be good to minimize differences for review and ease of understanding.
There was a problem hiding this comment.
the motivation is described here. I will revert this piece of code shortly.
SparkQA
commented
Jul 17, 2018
Test build #93165 has finished for PR 21352 at commit
|
mgaido91
commented
Jul 17, 2018
LGTM |
cloud-fan
commented
Jul 17, 2018
thanks, merging to master! |
SparkQA
commented
Jul 17, 2018
Test build #93175 has finished for PR 21352 at commit
|
What changes were proposed in this pull request?
The PR tries to avoid serialization of private fields of already added collection functions and follows up on comments in SPARK-23922 and SPARK-23935
How was this patch tested?
Run tests from: