Skip to content

Commit

Permalink
[SPARK-30943][SS] Show "batch ID" in tool tip string for Structured S…
Browse files Browse the repository at this point in the history
…treaming UI graphs

### What changes were proposed in this pull request?

This patch changes the tool tip string in Structured Streaming UI graphs to show batch ID (and timestamp as well) instead of only showing timestamp, which was a key for DStream but no longer a key for Structured Streaming.

This patch does some refactoring as there're some spots on confusion between js file for streaming and structured streaming.

Note that this patch doesn't actually change the x axis, as once we change it we should decouple the logic for graphs between streaming and structured streaming. It won't change UX meaningfully as in x axis we only show min and max which we still would like to know about "time" as well as batch ID.

### Why are the changes needed?

In Structured Streaming, everything is aligned for "batch ID" where the UI is only showing timestamp - end users have to manually find and correlate batch ID and the timestamp which is clearly a huge pain.

### Does this PR introduce any user-facing change?

No

### How was this patch tested?

Manually tested. Screenshots:

![Screen Shot 2020-02-25 at 7 22 38 AM](https://user-images.githubusercontent.com/1317309/75197701-40b2ce80-57a2-11ea-9578-c2eb2d1091de.png)
![Screen Shot 2020-02-25 at 7 22 44 AM](https://user-images.githubusercontent.com/1317309/75197704-427c9200-57a2-11ea-9439-e0a8303d0860.png)
![Screen Shot 2020-02-25 at 7 22 58 AM](https://user-images.githubusercontent.com/1317309/75197706-43152880-57a2-11ea-9617-1276c3ba181e.png)
![Screen Shot 2020-02-25 at 7 23 04 AM](https://user-images.githubusercontent.com/1317309/75197708-43152880-57a2-11ea-9de2-7d37eaf88102.png)
![Screen Shot 2020-02-25 at 7 23 31 AM](https://user-images.githubusercontent.com/1317309/75197710-43adbf00-57a2-11ea-9ae4-4e292de39c36.png)

Closes apache#27687 from HeartSaVioR/SPARK-30943.

Authored-by: Jungtaek Lim (HeartSaVioR) <kabhwan.opensource@gmail.com>
Signed-off-by: Shixiong Zhu <zsxwing@gmail.com>
  • Loading branch information
HeartSaVioR authored and zsxwing committed Feb 25, 2020
1 parent 02f8165 commit 9ea6c0a
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ function drawTimeline(id, data, minX, maxX, minY, maxY, unitY, batchInterval) {
.attr("cy", function(d) { return y(d.y); })
.attr("r", function(d) { return isFailedBatch(d.x) ? "2" : "3";})
.on('mouseover', function(d) {
var tip = formatYValue(d.y) + " " + unitY + " at " + timeFormat[d.x];
var tip = formatYValue(d.y) + " " + unitY + " at " + timeTipStrings[d.x];
showBootstrapTooltip(d3.select(this).node(), tip);
// show the point
d3.select(this)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,12 @@ function drawAreaStack(id, labels, values, minX, maxX, minY, maxY) {
.on('mouseover', function(d) {
var tip = '';
var idx = 0;
var _values = timeToValues[d._x]
var _values = formattedTimeToValues[d._x];
_values.forEach(function (k) {
tip += labels[idx] + ': ' + k + ' ';
idx += 1;
});
tip += " at " + d._x
tip += " at " + formattedTimeTipStrings[d._x];
showBootstrapTooltip(d3.select(this).node(), tip);
})
.on('mouseout', function() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,30 @@ private[ui] class StreamingQueryStatisticsPage(parent: StreamingQueryTab)
<script>{Unparsed(js)}</script>
}

def generateVar(values: Array[(Long, ju.Map[String, JLong])]): Seq[Node] = {
def generateTimeTipStrings(values: Array[(Long, Long)]): Seq[Node] = {
val js = "var timeTipStrings = {};\n" + values.map { case (batchId, time) =>
val formattedTime = SparkUIUtils.formatBatchTime(time, 1, showYYYYMMSS = false)
s"timeTipStrings[$time] = 'batch $batchId ($formattedTime)';"
}.mkString("\n")

<script>{Unparsed(js)}</script>
}

def generateFormattedTimeTipStrings(values: Array[(Long, Long)]): Seq[Node] = {
val js = "var formattedTimeTipStrings = {};\n" + values.map { case (batchId, time) =>
val formattedTime = SparkUIUtils.formatBatchTime(time, 1, showYYYYMMSS = false)
s"""formattedTimeTipStrings["$formattedTime"] = 'batch $batchId ($formattedTime)';"""
}.mkString("\n")

<script>{Unparsed(js)}</script>
}

def generateTimeToValues(values: Array[(Long, ju.Map[String, JLong])]): Seq[Node] = {
val durationDataPadding = SparkUIUtils.durationDataPadding(values)
val js = "var timeToValues = {};\n" + durationDataPadding.map { case (x, y) =>
val js = "var formattedTimeToValues = {};\n" + durationDataPadding.map { case (x, y) =>
val s = y.toSeq.sortBy(_._1).map(e => s""""${e._2}"""").mkString("[", ",", "]")
s"""timeToValues["${SparkUIUtils.formatBatchTime(x, 1, showYYYYMMSS = false)}"] = $s;"""
val formattedTime = SparkUIUtils.formatBatchTime(x, 1, showYYYYMMSS = false)
s"""formattedTimeToValues["$formattedTime"] = $s;"""
}.mkString("\n")

<script>{Unparsed(js)}</script>
Expand Down Expand Up @@ -112,8 +131,10 @@ private[ui] class StreamingQueryStatisticsPage(parent: StreamingQueryTab)
}

def generateStatTable(query: StreamingQueryUIData): Seq[Node] = {
val batchTimes = withNoProgress(query,
query.recentProgress.map(p => df.parse(p.timestamp).getTime), Array.empty[Long])
val batchToTimestamps = withNoProgress(query,
query.recentProgress.map(p => (p.batchId, df.parse(p.timestamp).getTime)),
Array.empty[(Long, Long)])
val batchTimes = batchToTimestamps.map(_._2)
val minBatchTime =
withNoProgress(query, df.parse(query.recentProgress.head.timestamp).getTime, 0L)
val maxBatchTime =
Expand Down Expand Up @@ -266,6 +287,9 @@ private[ui] class StreamingQueryStatisticsPage(parent: StreamingQueryTab)
</table>
// scalastyle:on

generateVar(operationDurationData) ++ generateTimeMap(batchTimes) ++ table ++ jsCollector.toHtml
generateTimeToValues(operationDurationData) ++
generateFormattedTimeTipStrings(batchToTimestamps) ++
generateTimeMap(batchTimes) ++ generateTimeTipStrings(batchToTimestamps) ++
table ++ jsCollector.toHtml
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,16 @@ private[ui] class StreamingPage(parent: StreamingTab)
<script>{Unparsed(js)}</script>
}

private def generateTimeTipStrings(times: Seq[Long]): Seq[Node] = {
// We leverage timeFormat as the value would be same as timeFormat. This means it is
// sensitive to the order - generateTimeMap should be called earlier than this.
val js = "var timeTipStrings = {};\n" + times.map { time =>
s"timeTipStrings[$time] = timeFormat[$time];"
}.mkString("\n")

<script>{Unparsed(js)}</script>
}

private def generateStatTable(): Seq[Node] = {
val batches = listener.retainedBatches

Expand Down Expand Up @@ -313,7 +323,8 @@ private[ui] class StreamingPage(parent: StreamingTab)
</table>
// scalastyle:on

generateTimeMap(batchTimes) ++ table ++ jsCollector.toHtml
generateTimeMap(batchTimes) ++ generateTimeTipStrings(batchTimes) ++ table ++
jsCollector.toHtml
}

private def generateInputDStreamsTable(
Expand Down

0 comments on commit 9ea6c0a

Please sign in to comment.