You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tajo.apache.org by ji...@apache.org on 2013/11/28 13:28:14 UTC

git commit: TAJO-279: Improving the query_executor page of web UI. (Wan Heo via jihoon)

Updated Branches:
  refs/heads/master 1f80cd24b -> 87437f171


TAJO-279: Improving the query_executor page of web UI. (Wan Heo via jihoon)


Project: http://git-wip-us.apache.org/repos/asf/incubator-tajo/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-tajo/commit/87437f17
Tree: http://git-wip-us.apache.org/repos/asf/incubator-tajo/tree/87437f17
Diff: http://git-wip-us.apache.org/repos/asf/incubator-tajo/diff/87437f17

Branch: refs/heads/master
Commit: 87437f1718e5e55ca4eb4517fcb3a00707cbc5a9
Parents: 1f80cd2
Author: Jihoon Son <ji...@apache.org>
Authored: Thu Nov 28 21:27:33 2013 +0900
Committer: Jihoon Son <ji...@apache.org>
Committed: Thu Nov 28 21:27:33 2013 +0900

----------------------------------------------------------------------
 .../tajo/webapp/QueryExecutorServlet.java       |  19 ++-
 .../webapps/admin/WEB-INF/jetty-web.xml         |  23 ++++
 .../src/main/resources/webapps/admin/getCSV.jsp |  31 +++++
 .../resources/webapps/admin/query_executor.jsp  | 131 +++++++++++++++++--
 4 files changed, 194 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/87437f17/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/webapp/QueryExecutorServlet.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/webapp/QueryExecutorServlet.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/webapp/QueryExecutorServlet.java
index c95ff14..d1670c4 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/webapp/QueryExecutorServlet.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/webapp/QueryExecutorServlet.java
@@ -6,6 +6,7 @@ import org.apache.hadoop.util.StringUtils;
 import org.apache.tajo.QueryId;
 import org.apache.tajo.TajoProtos;
 import org.apache.tajo.catalog.TableDesc;
+import org.apache.tajo.catalog.statistics.TableStats;
 import org.apache.tajo.client.QueryStatus;
 import org.apache.tajo.client.TajoClient;
 import org.apache.tajo.conf.TajoConf;
@@ -114,6 +115,11 @@ public class QueryExecutorServlet extends HttpServlet {
           }
         }
         QueryRunner queryRunner = new QueryRunner(queryRunnerId, query);
+        try {
+          queryRunner.sizeLimit = Integer.parseInt(request.getParameter("limitSize"));
+        } catch (java.lang.NumberFormatException nfe) {
+          queryRunner.sizeLimit = 1048576;
+        }
         synchronized(queryRunners) {
           queryRunners.put(queryRunnerId, queryRunner);
         }
@@ -150,6 +156,8 @@ public class QueryExecutorServlet extends HttpServlet {
             errorResponse(response, queryRunner.error);
             return;
           }
+          returnValue.put("numOfRows", queryRunner.numOfRows);
+          returnValue.put("resultSize", queryRunner.resultSize);
           returnValue.put("resultData", queryRunner.queryResult);
           returnValue.put("resultColumns", queryRunner.columnNames);
           returnValue.put("runningTime", JSPUtil.getElapsedTime(queryRunner.startTime, queryRunner.finishTime));
@@ -217,6 +225,9 @@ public class QueryExecutorServlet extends HttpServlet {
     AtomicBoolean stop = new AtomicBoolean(false);
     QueryId queryId;
     String query;
+    long resultSize;
+    int sizeLimit;
+    long numOfRows;
     Exception error;
 
     AtomicInteger progress = new AtomicInteger(0);
@@ -311,6 +322,7 @@ public class QueryExecutorServlet extends HttpServlet {
               try {
                 ResultSetMetaData rsmd = res.getMetaData();
                 TableDesc desc = tajoClient.getResultDesc(tajoQueryId);
+                resultSize = desc.getStats().getNumBytes();
                 LOG.info("Tajo Query Result: " + desc.getPath() + "\n");
 
                 int numOfColumns = rsmd.getColumnCount();
@@ -319,10 +331,15 @@ public class QueryExecutorServlet extends HttpServlet {
                 }
                 queryResult = new ArrayList<List<Object>>();
 
+                if(sizeLimit < resultSize) {
+                    numOfRows = (long)((float)(desc.getStats().getNumRows()) * ((float)sizeLimit / (float)resultSize));
+                } else {
+                    numOfRows = desc.getStats().getNumRows();
+                }
                 int rowCount = 0;
                 boolean hasMoreData = false;
                 while (res.next()) {
-                  if(rowCount > 1000) {
+                  if(rowCount > numOfRows) {
                     hasMoreData = true;
                     break;
                   }

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/87437f17/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/WEB-INF/jetty-web.xml
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/WEB-INF/jetty-web.xml b/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/WEB-INF/jetty-web.xml
new file mode 100644
index 0000000..7221fbc
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/WEB-INF/jetty-web.xml
@@ -0,0 +1,23 @@
+<?xml version="1.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.
+-->
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN"
+  "http://jetty.mortbay.org/configure.dtd">
+<Configure id="WebAppContext" class="org.mortbay.jetty.webapp.WebAppContext">
+  <Set name="maxFormContentSize" type="int">2147483647</Set>
+</Configure>

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/87437f17/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/getCSV.jsp
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/getCSV.jsp b/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/getCSV.jsp
new file mode 100644
index 0000000..f398304
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/getCSV.jsp
@@ -0,0 +1,31 @@
+<%
+  /*
+  * 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.
+  */
+%>
+<%@ page language = "java" contentType = "charset=utf-8" %>
+<%
+  response.setHeader("Content-Type", "application/octet-stream;");
+  response.setHeader("Content-Disposition", "attachment; filename=\"result.csv\";");
+  response.setHeader("Content-Description", "JSP Generated Data");
+  response.setHeader("cache-control", "no-cache");
+  response.setHeader("expires", "0");
+  response.setHeader("pragma", "no-cache");
+  out.print(request.getParameter("csvData"));
+  out.flush();
+%>
+

http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/87437f17/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/query_executor.jsp
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/query_executor.jsp b/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/query_executor.jsp
index 21e0309..9e5fa99 100644
--- a/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/query_executor.jsp
+++ b/tajo-core/tajo-core-backend/src/main/resources/webapps/admin/query_executor.jsp
@@ -18,7 +18,6 @@
   */
 %>
 <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
-
 <%@ page import="java.util.*" %>
 <%@ page import="org.apache.tajo.webapp.StaticHttpServer" %>
 <%@ page import="org.apache.tajo.master.*" %>
@@ -35,7 +34,6 @@
 <link rel="stylesheet" type = "text/css" href = "/static/style.css" />
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 <title>Tajo</title>
-
 <style type="text/css">
   #progress_bar {
     border:1px solid #000000;
@@ -45,13 +43,16 @@
     border-radius: 16px;
   }
   #progress_status {background:#fbcb46; width:0%; height:16px; border-radius: 10px; }
-
 </style>
 <script src="/static/js/jquery.js" type="text/javascript"></script>
 <script type="text/javascript">
 var progressInterval = 1000;
 var progressTimer = null;
 var queryRunnerId = null;
+var PRINT_LIMIT = 25;
+var SIZE_LIMIT = 104857600; // Limit size of displayed results.(Bytes)
+var pageNum = 0;
+var pageCount, storedColumns, storedData;
 
 $(document).ready(function() {
   $('#btnSubmit').click(function() {
@@ -66,7 +67,16 @@ function init() {
   $("#queryResult").html("");
   queryRunnerId = null;
 }
+
 function runQuery() {
+  if(Math.ceil(Number($("#sizeLimit").val())) >= 2048) {
+    SIZE_LIMIT = 2048 * 1024 * 1024 - 1;
+  } else if(Math.ceil(Number($("#sizeLimit").val())) > 0) {
+    SIZE_LIMIT = Number($("#sizeLimit").val()) * 1024 * 1024;
+  }
+  if(Math.ceil(Number($("#printLimit").val())) > 0) {
+    PRINT_LIMIT = Number($("#printLimit").val());
+  }
   if(progressTimer != null) {
     alert("Already query running.");
     return;
@@ -77,7 +87,7 @@ function runQuery() {
   $.ajax({
     type: "POST",
     url: "query_exec",
-    data: { action: "runQuery", query: query}
+    data: { action: "runQuery", query: query, limitSize:SIZE_LIMIT }
   })
   .done(function(msg) {
     var resultJson = $.parseJSON(msg);
@@ -139,17 +149,21 @@ function getResult() {
     data: { action: "getQueryResult", queryRunnerId: queryRunnerId }
   })
   .done(function(msg) {
+    var printedLine = 0;
     var resultJson = $.parseJSON(msg);
     if(resultJson.success == "false") {
       alert(resultJson.errorMessage);
       $("#queryStatus").html(getQueryStatusHtml(resultJson));
       return;
     }
-    console.log(resultJson);
     $("#queryResult").html("");
     var resultColumns = resultJson.resultColumns;
     var resultData = resultJson.resultData;
-
+	
+    storedColumns = resultColumns;
+    storedData = resultData; 
+    pageCount = Math.ceil((storedData.length / PRINT_LIMIT)) - 1 ;
+	
     var resultTable = "<table width='100%' class='border_table'><tr>";
     for(var i = 0; i < resultColumns.length; i++) {
       resultTable += "<th>" + resultColumns[i] + "</th>";
@@ -160,11 +174,102 @@ function getResult() {
       for(var j = 0; j < resultData[i].length; j++) {
         resultTable += "<td>" + resultData[i][j] + "</td>";
       }
-      resultTable += "</tr>";
+      resultTable += "</tr>";	  
+      if(++printedLine >= PRINT_LIMIT) break;
     }
     resultTable += "</table>";
     $("#queryResult").html(resultTable);
-  });
+    $("#queryResultTools").html("");
+    $("#queryResultTools").append("<input type='button' value='Download to CSV' onclick='getCSV();'/> ");
+    $("#queryResultTools").append("<input type='button' value='Prev' onclick='getPrev();'/> ");
+    $("#queryResultTools").append("<input type='button' value='Next' onclick='getNext();'/> ");
+    var selectPage = "<select id='selectPage'>";
+    for(var i = 0; i <= pageCount; i++) {
+      selectPage += "<option value="+i+">"+(i+1)+"</option>";
+    }
+    selectPage += "</select>";
+    $("#queryResultTools").append(selectPage);
+    $("#selectPage").change(getSelectedPage);
+  })
+}
+
+function getCSV() {
+  var csvData = "";
+  var rowCount = storedData.length;
+  var colCount = storedColumns.length;
+  for(var colIndex = 0; colIndex < colCount; colIndex++) {
+    if(colIndex == 0) {
+      csvData += storedColumns[colIndex];  
+    } else {
+      csvData += "," + storedColumns[colIndex];
+    }
+  }
+  csvData += "\n";
+  for(var rowIndex=0; rowIndex < rowCount; rowIndex++) {
+    for(var colIndex = 0; colIndex < colCount; colIndex++){
+      if(colIndex == 0) {
+        csvData += storedData[rowIndex][colIndex];
+      } else {
+        csvData += "," + storedData[rowIndex][colIndex];
+      }
+    }   
+    csvData += "\n";
+  }
+  $("#csvData").val(csvData);
+  $("#dataForm").submit();  
+}
+
+function getNext() {
+	var printedLine = 0;	
+	if(pageCount > pageNum) {
+		pageNum++;
+		document.getElementById("selectPage").options.selectedIndex = pageNum;
+	}else {
+		alert("There's no next page.");
+		return;
+	}
+	getPage();
+}
+
+function getPrev() {
+	if(pageNum > 0  ) {
+		pageNum--;
+		document.getElementById("selectPage").options.selectedIndex = pageNum;
+	} else {
+		alert("There's no previous page.");
+		return;
+	}
+	getPage();
+}
+
+function getSelectedPage() {
+  if(pageNum >= 0 &&  pageNum <= pageCount ) {
+    pageNum = $("#selectPage option:selected").val();
+  } else {
+    alert("Out of range.");
+    return;
+  }
+  getPage();
+}
+
+function getPage() {
+  var printedLine = 0;
+  $("#queryResult").html("");
+  var resultTable = "<table width='100%' class='border_table'><tr>";
+  for(var i = 0; i < storedColumns.length; i++) {
+    resultTable += "<th>" + storedColumns[i] + "</th>";
+  }
+  resultTable += "</tr>";
+  for(var i = pageNum * PRINT_LIMIT; i < storedData.length; i++) {
+    resultTable += "<tr>";
+    for(var j = 0; j < storedData[i].length; j++) {
+      resultTable += "<td>" + storedData[i][j] + "</td>";
+    }
+    resultTable += "</tr>";
+    if(++printedLine >= PRINT_LIMIT) break;
+  }
+  resultTable += "</table>";
+  $("#queryResult").html(resultTable);
 }
 
 </script>
@@ -177,7 +282,11 @@ function getResult() {
   <hr/>
   <h3>Query</h3>
   <textarea id="query" style="width:800px; height:250px; font-family:Tahoma; font-size:12px;"></textarea>
-  <p/>
+  <p />
+  Limit : <input id="sizeLimit" type="text" value="10" style="width:30px; text-align:center;" /> MB
+  <p />
+  Rows/Page : <input id="printLimit" type="text" value="25" style="width:30px; text-align:center;" />
+  <hr />
   <input id="btnSubmit" type="submit" value="Submit">
   <hr/>
   <div>
@@ -197,6 +306,10 @@ function getResult() {
   <hr/>
   <h3>Query Result</h3>
   <div id="queryResult"></div>
+  <hr/>
+  <div id="queryResultTools"></div>
+  <hr/>
+  <div style="dispaly:none;"><form name="dataForm" id="dataForm" method="post" action="getCSV.jsp"><input type="hidden" id="csvData" name="csvData" value="" /></div>
 </div>
 </body>
 </html>