DRILL-5802: Provide a sortable table for tables within a query profile Using the DataTables jQuery library, we can now sort tables (fragments and operators) to group like values or sort on a column. In addition, additional tooltips have been provided for these columns
closes #969 Project: http://git-wip-us.apache.org/repos/asf/drill/repo Commit: http://git-wip-us.apache.org/repos/asf/drill/commit/bec436f8 Tree: http://git-wip-us.apache.org/repos/asf/drill/tree/bec436f8 Diff: http://git-wip-us.apache.org/repos/asf/drill/diff/bec436f8 Branch: refs/heads/master Commit: bec436f87d14a27180658b0b00b90ba6c6161f72 Parents: da88bf7 Author: Kunal Khatua <kkha...@maprtech.com> Authored: Mon Oct 2 21:34:01 2017 -0700 Committer: Paul Rogers <prog...@maprtech.com> Committed: Wed Oct 4 12:34:17 2017 -0700 ---------------------------------------------------------------------- .../server/rest/profile/FragmentWrapper.java | 47 +++++- .../server/rest/profile/OperatorWrapper.java | 36 +++- .../exec/server/rest/profile/TableBuilder.java | 10 +- .../src/main/resources/rest/profile/profile.ftl | 23 +++ .../resources/rest/static/img/black-asc.gif | Bin 0 -> 48 bytes .../resources/rest/static/img/black-desc.gif | Bin 0 -> 49 bytes .../rest/static/img/black-unsorted.gif | Bin 0 -> 54 bytes .../static/js/jquery.dataTables-1.10.16.min.js | 164 +++++++++++++++++++ 8 files changed, 266 insertions(+), 14 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/drill/blob/bec436f8/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/profile/FragmentWrapper.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/profile/FragmentWrapper.java b/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/profile/FragmentWrapper.java index b25b92a..2233f2e 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/profile/FragmentWrapper.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/profile/FragmentWrapper.java @@ -17,12 +17,9 @@ */ package org.apache.drill.exec.server.rest.profile; -import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collections; -import java.util.Date; import java.util.List; -import java.util.Locale; import org.apache.drill.exec.proto.UserBitShared.MajorFragmentProfile; import org.apache.drill.exec.proto.UserBitShared.MinorFragmentProfile; @@ -205,14 +202,23 @@ public class FragmentWrapper { tb.appendBytes(maxMem.getMaxMemoryUsed()); } - public static final String[] FRAGMENT_COLUMNS = {"Minor Fragment ID", "Host Name", "Start", "End", - "Runtime", "Max Records", "Max Batches", "Last Update", "Last Progress", "Peak Memory", "State"}; + public static final String[] FRAGMENT_COLUMNS = { + FragmentTblTxt.MINOR_FRAGMENT, FragmentTblTxt.HOSTNAME, FragmentTblTxt.START_TIME, FragmentTblTxt.END_TIME, + FragmentTblTxt.RUNTIME, FragmentTblTxt.MAX_RECORDS, FragmentTblTxt.MAX_BATCHES, FragmentTblTxt.LAST_UPDATE, + FragmentTblTxt.LAST_PROGRESS, FragmentTblTxt.PEAK_MEMORY, FragmentTblTxt.STATE + }; + + public static final String[] FRAGMENT_COLUMNS_TOOLTIP = { + FragmentTblTooltip.MINOR_FRAGMENT, FragmentTblTooltip.HOSTNAME, FragmentTblTooltip.START_TIME, FragmentTblTooltip.END_TIME, + FragmentTblTooltip.RUNTIME, FragmentTblTooltip.MAX_RECORDS, FragmentTblTooltip.MAX_BATCHES, FragmentTblTooltip.LAST_UPDATE, + FragmentTblTooltip.LAST_PROGRESS, FragmentTblTooltip.PEAK_MEMORY, FragmentTblTooltip.STATE + }; // Not including minor fragment ID private static final int NUM_NULLABLE_FRAGMENTS_COLUMNS = FRAGMENT_COLUMNS.length - 1; public String getContent() { - final TableBuilder builder = new TableBuilder(FRAGMENT_COLUMNS, null); + final TableBuilder builder = new TableBuilder(FRAGMENT_COLUMNS, FRAGMENT_COLUMNS_TOOLTIP, true); // Use only minor fragments that have complete profiles // Complete iff the fragment profile has at least one operator profile, and start and end times. @@ -261,6 +267,34 @@ public class FragmentWrapper { return builder.build(); } + private class FragmentTblTxt { + static final String MINOR_FRAGMENT = "Minor Fragment"; + static final String HOSTNAME = "Hostname"; + static final String START_TIME = "Start"; + static final String END_TIME = "End"; + static final String RUNTIME = "Runtime"; + static final String MAX_BATCHES = "Max Batches"; + static final String MAX_RECORDS = "Max Records"; + static final String LAST_UPDATE = "Last Update"; + static final String LAST_PROGRESS = "Last Progress"; + static final String PEAK_MEMORY = "Peak Memory"; + static final String STATE = "State"; + } + + private class FragmentTblTooltip { + static final String MINOR_FRAGMENT = "Minor Fragment ID"; + static final String HOSTNAME = "Host on which the fragment ran"; + static final String START_TIME = "Fragment Start Time"; + static final String END_TIME = "Fragment End Time"; + static final String RUNTIME = "Duration of the Fragment"; + static final String MAX_BATCHES = "Max Records processed by the fragment"; + static final String MAX_RECORDS = "Max Batches processed by the fragment"; + static final String LAST_UPDATE = "Last time fragment reported heartbeat"; + static final String LAST_PROGRESS = "Last time fragment reported back metrics"; + static final String PEAK_MEMORY = "Fragment Peak Memory Usage"; + static final String STATE = "State of the fragment"; + } + private class OverviewTblTxt { static final String MAJOR_FRAGMENT = "Major Fragment"; static final String MINOR_FRAGMENTS_REPORTING = "Minor Fragments Reporting"; @@ -294,4 +328,3 @@ public class FragmentWrapper { } } - http://git-wip-us.apache.org/repos/asf/drill/blob/bec436f8/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/profile/OperatorWrapper.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/profile/OperatorWrapper.java b/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/profile/OperatorWrapper.java index fce8998..cca9563 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/profile/OperatorWrapper.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/profile/OperatorWrapper.java @@ -63,11 +63,18 @@ public class OperatorWrapper { return String.format("operator-%d-%d", major, opsAndHosts.get(0).getLeft().getLeft().getOperatorId()); } - public static final String [] OPERATOR_COLUMNS = {"Minor Fragment", "Host Name", "Setup Time", "Process Time", "Wait Time", - "Max Batches", "Max Records", "Peak Memory"}; + public static final String [] OPERATOR_COLUMNS = { + OperatorTblTxt.MINOR_FRAGMENT, OperatorTblTxt.HOSTNAME, OperatorTblTxt.SETUP_TIME, OperatorTblTxt.PROCESS_TIME, OperatorTblTxt.WAIT_TIME, + OperatorTblTxt.MAX_BATCHES, OperatorTblTxt.MAX_RECORDS, OperatorTblTxt.PEAK_MEMORY + }; + + public static final String [] OPERATOR_COLUMNS_TOOLTIP = { + OperatorTblTooltip.MINOR_FRAGMENT, OperatorTblTooltip.HOSTNAME, OperatorTblTooltip.SETUP_TIME, OperatorTblTooltip.PROCESS_TIME, OperatorTblTooltip.WAIT_TIME, + OperatorTblTooltip.MAX_BATCHES, OperatorTblTooltip.MAX_RECORDS, OperatorTblTooltip.PEAK_MEMORY + }; public String getContent() { - TableBuilder builder = new TableBuilder(OPERATOR_COLUMNS, null); + TableBuilder builder = new TableBuilder(OPERATOR_COLUMNS, OPERATOR_COLUMNS_TOOLTIP, true); for (ImmutablePair<ImmutablePair<OperatorProfile, Integer>, String> ip : opsAndHosts) { int minor = ip.getLeft().getRight(); @@ -223,6 +230,28 @@ public class OperatorWrapper { return builder.build(); } + private class OperatorTblTxt { + static final String MINOR_FRAGMENT = "Minor Fragment"; + static final String HOSTNAME = "Hostname"; + static final String SETUP_TIME = "Setup Time"; + static final String PROCESS_TIME = "Process Time"; + static final String WAIT_TIME = "Wait Time"; + static final String MAX_BATCHES = "Max Batches"; + static final String MAX_RECORDS = "Max Records"; + static final String PEAK_MEMORY = "Peak Memory"; + } + + private class OperatorTblTooltip { + static final String MINOR_FRAGMENT = "Operator's Minor Fragment"; + static final String HOSTNAME = "Host on which the minor fragment ran"; + static final String SETUP_TIME = "Setup Time for the minor fragment's operator"; + static final String PROCESS_TIME = "Process Time for the minor fragment's operator"; + static final String WAIT_TIME = "Wait Time for the minor fragment's operator"; + static final String MAX_BATCHES = "Max Batches processed by the minor fragment's operator"; + static final String MAX_RECORDS = "Max Records processed by the minor fragment's operator"; + static final String PEAK_MEMORY = "Peak Memory usage by the minor fragment's operator"; + } + private class OverviewTblTxt { static final String OPERATOR_ID = "Operator ID"; static final String TYPE_OF_OPERATOR = "Type"; @@ -257,4 +286,3 @@ public class OperatorWrapper { static final String MAX_PEAK_MEMORY = "Highest memory consumption by a fragment"; } } - http://git-wip-us.apache.org/repos/asf/drill/blob/bec436f8/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/profile/TableBuilder.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/profile/TableBuilder.java b/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/profile/TableBuilder.java index 07598c5..b49382b 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/profile/TableBuilder.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/profile/TableBuilder.java @@ -34,12 +34,16 @@ public class TableBuilder { private int width; public TableBuilder(final String[] columns, final String[] columnTooltip) { + this(columns, columnTooltip, false); + } + + public TableBuilder(final String[] columns, final String[] columnTooltip, final boolean isSortable) { sb = new StringBuilder(); width = columns.length; format.setMaximumFractionDigits(3); - sb.append("<table class=\"table table-bordered text-right\">\n<tr>"); + sb.append("<table class=\"table table-bordered text-right"+(isSortable? " sortable" : "")+"\">\n<thead><tr>"); for (int i = 0; i < columns.length; i++) { String cn = columns[i]; String ctt = ""; @@ -51,7 +55,7 @@ public class TableBuilder { } sb.append("<th" + ctt + ">" + cn + "</th>"); } - sb.append("</tr>\n"); + sb.append("</tr></thead>\n<tbody>\n"); } public void appendCell(final String s) { @@ -208,7 +212,7 @@ public class TableBuilder { public String build() { String rv; - rv = sb.append("\n</table>").toString(); + rv = sb.append("\n</tbody>\n</table>").toString(); sb = null; return rv; } http://git-wip-us.apache.org/repos/asf/drill/blob/bec436f8/exec/java-exec/src/main/resources/rest/profile/profile.ftl ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/resources/rest/profile/profile.ftl b/exec/java-exec/src/main/resources/rest/profile/profile.ftl index 9318afc..468297e 100644 --- a/exec/java-exec/src/main/resources/rest/profile/profile.ftl +++ b/exec/java-exec/src/main/resources/rest/profile/profile.ftl @@ -14,12 +14,35 @@ <script src="/static/js/d3.v3.js"></script> <script src="/static/js/dagre-d3.min.js"></script> <script src="/static/js/graph.js"></script> +<script src="/static/js/jquery.dataTables-1.10.16.min.js"></script> + <script> var globalconfig = { "queryid" : "${model.getQueryId()}", "operators" : ${model.getOperatorsJSON()?no_esc} }; + + $(document).ready(function() { + $(".sortable").DataTable( { + "searching": false, + "lengthChange": false, + "paging": false, + "info": false + } + );} ); </script> +<style> +/* DataTables Sorting: inherited via sortable class */ +table.sortable thead .sorting,.sorting_asc,.sorting_desc { + background-repeat: no-repeat; + background-position: center right; + cursor: pointer; +} +/* Sorting Symbols */ +table.sortable thead .sorting { background-image: url("/static/img/black-unsorted.gif"); } +table.sortable thead .sorting_asc { background-image: url("/static/img/black-asc.gif"); } +table.sortable thead .sorting_desc { background-image: url("/static/img/black-desc.gif"); } +</style> </#macro> <#macro page_body> http://git-wip-us.apache.org/repos/asf/drill/blob/bec436f8/exec/java-exec/src/main/resources/rest/static/img/black-asc.gif ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/resources/rest/static/img/black-asc.gif b/exec/java-exec/src/main/resources/rest/static/img/black-asc.gif new file mode 100644 index 0000000..730533f Binary files /dev/null and b/exec/java-exec/src/main/resources/rest/static/img/black-asc.gif differ http://git-wip-us.apache.org/repos/asf/drill/blob/bec436f8/exec/java-exec/src/main/resources/rest/static/img/black-desc.gif ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/resources/rest/static/img/black-desc.gif b/exec/java-exec/src/main/resources/rest/static/img/black-desc.gif new file mode 100644 index 0000000..4c3b610 Binary files /dev/null and b/exec/java-exec/src/main/resources/rest/static/img/black-desc.gif differ http://git-wip-us.apache.org/repos/asf/drill/blob/bec436f8/exec/java-exec/src/main/resources/rest/static/img/black-unsorted.gif ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/resources/rest/static/img/black-unsorted.gif b/exec/java-exec/src/main/resources/rest/static/img/black-unsorted.gif new file mode 100644 index 0000000..5647f65 Binary files /dev/null and b/exec/java-exec/src/main/resources/rest/static/img/black-unsorted.gif differ