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>