Uh oh!
There was an error while loading. Please reload this page.
[SPARK-16323][SQL] Add IntegralDivide expression - #22395
Conversation
mgaido91
commented
Sep 11, 2018
cc @cloud-fan |
dongjoon-hyun
commented
Sep 11, 2018
|
SparkQA
commented
Sep 11, 2018
Test build #95954 has finished for PR 22395 at commit
|
| def - (other: Expression): Expression = Subtract(expr, other) | ||
| def * (other: Expression): Expression = Multiply(expr, other) | ||
| def / (other: Expression): Expression = Divide(expr, other) | ||
| def div (other: Expression): Expression = IntegralDivide(expr, other) |
There was a problem hiding this comment.
The failure looks like relevant.
org.scalatest.exceptions.TestFailedException:Expected"struct<[CAST((CAST(5 AS DOUBLE) / CAST(2 AS DOUBLE)) AS BIGINT):big]int>",
but got "struct<[(5 div 2):]int>"Schema did not matchfor query #19 select 5 div 2SparkQA
commented
Sep 12, 2018
Test build #95982 has finished for PR 22395 at commit
|
cloud-fan
commented
Sep 12, 2018
LGTM, cc @viirya@gatorsmile |
| 1 | ||
| """, | ||
| since = "3.0.0") | ||
| case class IntegralDivide(left: Expression, right: Expression) extends DivModLike { |
There was a problem hiding this comment.
Shall we add this to FunctionRegistry?
There was a problem hiding this comment.
I don't think so, please see the discussion at #14036 (comment)
There was a problem hiding this comment.
Ur, sorry, but why not? As @viirya suggested, without that, the description added here is not meaningless.
spark-sql> describe function 'div';
Function: div not found.
Timetaken: 0.016 seconds, Fetched1 row(s)Also, Hive accepts that like the following. (from Hive 3.1.0)
0: jdbc:hive2://ctr-e138-1518143905142-429335> describe function div;
+----------------------------------------------------+| tab_name |+----------------------------------------------------+| a div b -Divide a by b rounded to the long integer |+----------------------------------------------------+0: jdbc:hive2://ctr-e138-1518143905142-429335> select 3/2, 3 div 2, `/`(3,2), `div`(3,2);
+------+------+------+------+| _c0 | _c1 | _c2 | _c3 |+------+------+------+------+|1.5|1|1.5|1|+------+------+------+------+There was a problem hiding this comment.
@dongjoon-hyun because if we add it there, we can write: select div(3, 2), which is not supported by Hive.
hive> select div(3, 2);
NoViableAltException(13@[])
at org.apache.hadoop.hive.ql.parse.HiveParser_SelectClauseParser.selectClause(HiveParser_SelectClauseParser.java:964)
There was a problem hiding this comment.
@mgaido91 . I gave you the example of Hive in the above. :)
`div`(3,2)
There was a problem hiding this comment.
ah, sorry I missed the back-ticks. I am adding it, sorry. Thanks.
| } | ||
| @ExpressionDescription( | ||
| usage = "a _FUNC_ b - Divides a by b.", |
There was a problem hiding this comment.
nit: explicitly say this is integral divide?
There was a problem hiding this comment.
yes, thanks, I am very bad at descriptions.
SparkQA
commented
Sep 12, 2018
Test build #95995 has finished for PR 22395 at commit
|
| private lazy val div: (Any, Any) => Any = dataType match { | ||
| case i: IntegralType => i.integral.asInstanceOf[Integral[Any]].quot | ||
| } | ||
| override def evalOperation(left: Any, right: Any): Any = div(left, right) |
There was a problem hiding this comment.
Sorry I may not recall it very clearly. Can you check Hive and other databases and see if the result type of div is always long?
There was a problem hiding this comment.
Sure, so:
- Hive returns always long;
- Postgres and SQLServer don't have a
divoperator but they perform integral division when the operands are integrals and return the datatype of the operands (eg.select 3 / 2returns an integer); - Oracle doesn't support it.
So the behavior is not homogeneous among the RDBMs
There was a problem hiding this comment.
Then I'd prefer always returning long, since it was the behavior before. We can consider changing the behavior in another PR.
There was a problem hiding this comment.
+1 for @cloud-fan 's suggestion.
There was a problem hiding this comment.
Yeah, I think it is reasonable as that is what we defined: Hive Long Division: 'DIV' in AstBuilder.scala.
SparkQA
commented
Sep 13, 2018
Test build #96040 has finished for PR 22395 at commit
|
dongjoon-hyun
commented
Sep 13, 2018
Retest this please |
SparkQA
commented
Sep 13, 2018
Test build #96045 has finished for PR 22395 at commit
|
SparkQA
commented
Sep 14, 2018
Test build #96072 has finished for PR 22395 at commit
|
| } | ||
| @ExpressionDescription( | ||
| usage = "expr1 _FUNC_ expr2 - Returns `expr1`/`expr2`. It performs integral division.", |
There was a problem hiding this comment.
Let's mention that it always return long. Maybe we can take a look at how Hive document it.
There was a problem hiding this comment.
Divide a by b rounded to the long integer, this is Hive's div document.
There was a problem hiding this comment.
yes, thanks @viirya, I am updating to that sentence
cloud-fan
commented
Sep 14, 2018
LGTM except one comment |
viirya
commented
Sep 14, 2018
LGTM |
gatorsmile
commented
Sep 14, 2018
Could we check the definition of div in MySQL? Is it the same as the one implemented in this PR? https://dev.mysql.com/doc/refman/8.0/en/arithmetic-functions.html#operator_div |
mgaido91
commented
Sep 14, 2018
@gatorsmile I checked on MySQL 5.6 and there are 2 differences between MySQL's
|
SparkQA
commented
Sep 14, 2018
Test build #96079 has finished for PR 22395 at commit
|
dongjoon-hyun
commented
Sep 17, 2018
Retest this please |
| checkEvaluation(IntegralDivide(Literal(1.toLong), Literal(2.toLong)), 0L) | ||
| checkEvaluation(IntegralDivide(positiveShortLit, negativeShortLit), 0L) | ||
| checkEvaluation(IntegralDivide(positiveIntLit, negativeIntLit), 0L) | ||
| checkEvaluation(IntegralDivide(positiveLongLit, negativeLongLit), 0L) |
There was a problem hiding this comment.
Could you add a test case for divide by zero like test("/ (Divide) basic")?
For now, this PR seems to follow the behavior of Spark / instead of Hive div. We had better be clear on our decision and prevent future unintended behavior changes.
scala> sql("select 2 / 0, 2 div 0").show()
+---------------------------------------+---------+|(CAST(2ASDOUBLE) /CAST(0ASDOUBLE))|(2 div 0)|+---------------------------------------+---------+|null|null|+---------------------------------------+---------+0: jdbc:hive2://ctr-e138-1518143905142-477481>select2/0;
+-------+
| _c0 |
+-------+
| NULL |
+-------+0: jdbc:hive2://ctr-e138-1518143905142-477481>select2 div 0;
Error: Error while compiling statement: FAILED:
SemanticException [Error 10014]: Line1:7 Wrong arguments '0':
org.apache.hadoop.hive.ql.metadata.HiveException:
Unable to execute method public org.apache.hadoop.io.LongWritable org.apache.hadoop.hive.ql.udf.UDFOPLongDivide.evaluate(org.apache.hadoop.io.LongWritable,org.apache.hadoop.io.LongWritable)
with arguments {2,0}:/ by zero (state=42000,code=10014)There was a problem hiding this comment.
good catch! We should clearly define the behavior in the doc string too.
There was a problem hiding this comment.
The test for this case is present in operators.sql (anyway, if you prefer me to add a case here too, just let me know and I'll add it). And since we already have this function in our code indeed - it is just translated to a normal divide + a cast - currently we are returning null and throwing an exception for it would be a behavior change (and a quite disruptive too). Do we really want to follow Hive's behavior on this?
There was a problem hiding this comment.
I think we don't really need to change current behavior, but it is worth describing this in the doc string.
There was a problem hiding this comment.
I agree with you @viirya. I updated the doc string with the current behavior. Thanks.
SparkQA
commented
Sep 17, 2018
Test build #96114 has finished for PR 22395 at commit
|
SparkQA
commented
Sep 17, 2018
Test build #96128 has finished for PR 22395 at commit
|
| > SELECT 3 _FUNC_ 2; | ||
| 1 | ||
| """, | ||
| since = "3.0.0") |
There was a problem hiding this comment.
the next version will be 2.5.0 AFAIK.
cloud-fan
commented
Sep 17, 2018
LGTM |
SparkQA
commented
Sep 17, 2018
Test build #96141 has finished for PR 22395 at commit
|
dongjoon-hyun
commented
Sep 17, 2018
Merged to the master. |
dongjoon-hyun
commented
Sep 17, 2018
Thank you, @mgaido91 ! |
mgaido91
commented
Sep 17, 2018
thank you all for the reviews |
why are we always returning long type here? shouldn't they be the same as the left expr's type? see mysql |
dongjoon-hyun
commented
Sep 17, 2018
cloud-fan
commented
Sep 18, 2018
To clarify, it's not following hive, but following the behavior of previous Spark versions, which is same as hive. I also think returning left operand's type is more reasonable, but we should do it in another PR since it's a behavior change, and we should also add migration guide for it. @mgaido91 do you have time to do this change? Thanks! |
rxin
commented
Sep 18, 2018
via email
Looks like a use case for a legacy config. On Mon, Sep 17, 2018 at 6:41 PM Wenchen Fan ***@***.***> wrote:
To clarify, it's not following hive, but following the behavior of
previous Spark versions, which is same as hive.
I also think returning left operand's type is more reasonable, but we
should do it in another PR since it's a behavior change, and we should also
add migration guide for it.
@mgaido91 <https://github.com/mgaido91> do you have time to do this
change? Thanks!
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#22395 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AATvPDeW3F4Jsc-gS6CFrrGZY_lFXGxbks5ucE9WgaJpZM4Wjmfh>
.
-- --
excuse the brevity and lower case due to wrist injury |
mgaido91
commented
Sep 18, 2018
Sure @cloud-fan, I'll create a JIRA and submit a PR for it.
Yes, thanks for the suggestion @rxin, I agree. |
| override def inputType: AbstractDataType = IntegralType | ||
| override def dataType: DataType = LongType | ||
| override def symbol: String = "/" |
There was a problem hiding this comment.
What is the reason we are using / here? Any benefit?
There was a problem hiding this comment.
yes, exactly, it is used there
What changes were proposed in this pull request?
The PR takes over #14036 and it introduces a new expression
IntegralDividein order to avoid the several unneded cast added previously.In order to prove the performance gain, the following benchmark has been run:
The results on my laptop are:
Showing a 2-5X improvement. The benchmark doesn't include code generation as it is pretty hard to test the performance there as for such simple operations the most of the time is spent in the code generation/compilation process.
How was this patch tested?
added UTs