I am trying to use JSP on server-side to perform a variable number of queries and output the result of all of them as a single block of JSON data for an ExtJS line chart.
The reason the number of queries is variable is because each one represent a different series (a different line) on the line chart, and the number of series is different depending on the line chart that the user selects.
I am using hibernate and my persistence class returns each query data as a: List<Map<String, Object>> (each Map represents one row).
There will always be at least one series (one line on the graph, one query to execute), so the way I was thinking of setting this up is as follows:
1) Have the initial query run and get the first series
2) Run another query to check for any other series that should be on the graph
3) For each "other" series found in the second query run a query that gets the data for that series (same number of rows) and then merge that data into the first List<Map<String, Object>> that was returned in #1 as another column. The query is set-up to order it properly it just needs to be merged at the same index level.
4) Output that List as JSON.
My problem is with #3, I am not sure how to go about the merging the data.
Here's what I have so far:
GenericSelectCommand graphData = new GenericSelectCommand(graphDataQuery);
GenericSelectCommand backSeriesData = new GenericSelectCommand(backSeriesQuery);
List<Map<String, Object>> graphDataList;
List<Map<String, Object>> backSeriesList;
try
{
Persistor myPersistor = new Persistor();
// 1) GET THE INITIAL LINE CHART SERIES
myPersistor.executeTransact(graphData);
graphDataList = graphData.getRows();
// 2) LOOK FOR ANY ADDITIONAL SERIES THAT SHOULD BE ON THE LINE CHART
myPersistor.executeTransact(backSeriesData);
backSeriesList = backSeriesData.getRows();
// 3) FOR EACH ADDITIONAL SERIES FOUND, RUN A QUERY AND APPEND THE DATA TO THE INITIAL LINE CHART SERIES (graphDataList)
for (int i = 0; i < backSeriesList.size(); i++)
{
Map<String, Object> backSeriesBean = backSeriesList.get(i);
// THIS QUERY RETURNS ONE COLUMN OF INT VALUES (THE LINE CHART DATA) WITH THE EXACT SAME NUMBER OF ROWS AS THE INITIAL LINE CHART SERIES (graphDataList)
String backDataQuery = "exec runQuery 'getBackData', '" + backSeriesBean.get("series_id") + "'";
GenericSelectCommand backData = new GenericSelectCommand(backDataQuery);
myPersistor.executeTransact(backData);
List<Map<String, Object>> backDataList = backData.getRows();
// FOR EACH RECORD IN THE BACK DATA (Map<String, Object>)
for (int i = 0; i < backDataList.size(); i++)
{
Map<String, Object> backDataBean = backDataList.get(i);
// HOW DO I ADD IT TO THE RECORD AT THE SAME INDEX LEVEL IN graphDataList (List<Map<String, Object>>)
}
}
}
catch (Throwable e)
{
System.err.println("Error: ");
System.err.println(e.getCause());
}
finally
{
myPersistor.closeSession();
}
// 4) RETURN THE DATA AS JSON NOW THAT IT IS MERGED
for (int i = 0; i < graphDataList.size(); i++)
{
Map<String, Object> graphDataBean = graphDataList.get(i);
out.println(/*JSON FORMAT + graphDataBean.get('data') + JSON FORMAT*/)
}
SOLUTION:
GenericSelectCommand graphData = new GenericSelectCommand(graphDataQuery);
GenericSelectCommand backSeries = new GenericSelectCommand(backSeriesQuery);
List<Map<String, Object>> graphDataList = Collections.emptyList();
List<Map<String, Object>> backSeriesList = Collections.emptyList();
List backDataListArray = new ArrayList();
try
{
// GET THE INITIAL LINE CHART SERIES
Persistor.instance().executeTransact(graphData);
graphDataList = graphData.getRows();
// LOOK FOR ANY ADDITIONAL SERIES THAT SHOULD BE ON THE LINE CHART
Persistor.instance().executeTransact(backSeries);
backSeriesList = backSeries.getRows();
// FOR EACH ADDITIONAL SERIES FOUND, RUN THE QUERY AND ADD IT TO backDataListArray
for (int i = 0; i < backSeriesList.size(); i++)
{
Map<String, Object> backSeriesBean = backSeriesList.get(i);
String backDataQuery = "exec runQuery 'getBackData', " + backSeriesBean.get("series_id");
GenericSelectCommand backData = new GenericSelectCommand(backDataQuery);
Persistor.instance().executeTransact(backData);
List<Map<String, Object>> backDataList = backData.getRows();
backDataListArray.add(backDataList);
}
}
catch (Throwable e)
{
System.err.println("Error: ");
System.err.println(e.getCause());
}
finally
{
Persistor.instance().closeSession();
}
// FOR EACH RECORD IN THE ORIGINAL QUERY, WRITE THE JSON STRING
for (int i = 0; i < graphDataList.size(); i++)
{
StringBuilder backDataString = new StringBuilder();
// BUILD THE BACK DATA STRING (IF THERE IS ANY)
for (int j = 0; j < backDataListArray.size(); j++)
{
List<Map<String, Object>> backDataList = (List<Map<String, Object>>) backDataListArray.get(j);
Map<String, Object> backDataBean = backDataList.get(i);
Map<String, Object> backSeriesBean = backSeriesList.get(j);
backDataString.append(backSeriesBean.get("the_series") + ": " + backDataBean.get("the_count") + ", ");
}
Map<String, Object> graphDataBean = graphDataList.get(i);
out.println("{the_quota: " + graphDataBean.get("the_quota") + ", " + "count_pt_year: " + graphDataBean.get("count_pt_year") + ", " + backDataString + "date_string: '" + graphDataBean.get("date_string") + "'}" + (i + 1 == graphDataList.size() ? "" : "," ));
}
I would not merge the lists. I would just create an outer list for each query and then go through the outer list and return each series list. You can just create the outer list as:
List outerList = new ArrayList();
I would not worry about specifying the types for the outer list as it just makes it more complicated for little benefit.
Related
In my SQL Server I have the following result sets after all the condition filtering and sum query execution.
I would like to be shown like this in my page (refer to the screenshot below).
I have tried the below JAVA code that gave me the results that I appended into my datatables.
<%
ArrayList<String[]> rows = sqlq.querySQL();
String rowsetdate = new String();
String rowres1 = new String();
for(String[] rowset : rows) {
rowsetdate = rowset[0];
rowres1 = rowres1 + rowset[1]+ ",";
for(String rowres2 : rowset) {
rowres1 = rowres1 + rowres2 + ",";
}
rowres1 = rowres1.substring(0, rowres1.length()-1);
rowres1 = rowres1 + "|";
}
rowres1 = rowres1.substring(0, rowres1.length()-1);
%>
<tr>
<td><%if (rowres1 == null) out.print(""); else out.print(rowres1);%></td>
</tr>
sqlq.querySQL() is used to send my SQL query to JDBC in order for me to send query to my DB.
Photo below is the appended data in my datatables after the code execution, on the left is the Date and on the right is the data.
I tried some different code,
<%
ArrayList<String[]> rows = sqlq.querySQL();
for(String[] rowset : rows) {
<tr>
<td><%if (rowset[0] == null) out.print(""); else out.print(rowset[0]);%></td>
<td><%if (rowset[1] == null) out.print(""); else out.print(rowset[1]);%></td>
</tr>
}
%>
which did not achieve my expected results also, it returns the data like how I see it in my SSMS (check screenshot below)
What did I do wrong and how should I do it to get my expected outcome? (screenshot below)
Appreciate the help from all of you.
You can use a Map that its key is date and its value again is a Map. Inner Map uses trans as key and sumtot as value.
Map<String, Map<String, String>> mapByDate = new HashMap<>();
TreeSet<String> allTrans = new TreeSet<>();
for (String[] row : rows) {
Map<String, String> mapByDateAndTrans = mapByDate.get(row[0]);
if (mapByDateAndTrans == null) {
mapByDateAndTrans = new HashMap<>();
}
mapByDateAndTrans.put(row[1], row[2]);
mapByDate.put(row[0], mapByDateAndTrans);
allTrans.add(row[1]);
}
Here is a sample code to print data as you might expect:
System.out.println("Date/Trans: " + allTrans);
for (Map.Entry<String, Map<String, String>> mapByDateEntry : mapByDate.entrySet()) {
System.out.print(mapByDateEntry.getKey() + ": ");
Map<String, String> mapByTrans = mapByDateEntry.getValue();
for (String trans : allTrans) {
String sumtot = mapByTrans.get(trans);
if (sumtot != null) {
System.out.print("[ " + sumtot + " ]");
} else {
System.out.print("[ ]");
}
}
System.out.println();
}
The output:
Date/Trans: [11200, 11201, 11202]
2019-07-02: [ 136 ][ 18 ][ 14 ]
2019-07-03: [ 164 ][ 10 ][ 8 ]
Or we can generate an HTML table content:
StringBuilder tableBuilder = new StringBuilder("<table border = 1>");
// table header
tableBuilder.append("<tr>");
tableBuilder.append("<th>date/trans</th>");
for (String trans : allTrans) {
tableBuilder.append("<th>").append(trans).append("</th>");
}
tableBuilder.append("</tr>");
// table rows
for (Map.Entry<String, Map<String, String>> mapByDateEntry : mapByDate.entrySet()) {
tableBuilder.append("<tr>");
tableBuilder.append("<td>").append(mapByDateEntry.getKey()).append("</td>");
Map<String, String> mapByTrans = mapByDateEntry.getValue();
for (String trans : allTrans) {
String sumtot = mapByTrans.get(trans);
if (sumtot != null) {
tableBuilder.append("<td>").append(sumtot).append("</td>");
} else {
tableBuilder.append("<td></td>");
}
}
tableBuilder.append("<tr>");
}
tableBuilder.append("</table>");
System.out.println(tableBuilder.toString());
The Output:
<table border = 1><tr><th>date/trans</th><th>11200</th><th>11201</th><th>11202</th></tr><tr><td>2019-07-02</td><td>136</td><td>18</td><td>14</td><tr><tr><td>2019-07-03</td><td>164</td><td>10</td><td>8</td><tr></table>
If we save generated output as an HTML file, It maybe your desired result (screenshot below). Also you can change the code to be used in JSP:
To have an ordered Map by natural order of its keys, a TreeMap can be used. So to print the data ordered by date, we can construct a new TreeMap containing the mapByDate data:
TreeMap<String, Map<String, String>> sortedMapByDate = new TreeMap<>(mapByDate);
// table rows
for (Map.Entry<String, Map<String, String>> mapByDateEntry : sortedMapByDate.entrySet()) {
tableBuilder.append("<tr>");
tableBuilder.append("<td>").append(mapByDateEntry.getKey()).append("</td>");
Map<String, String> mapByTrans = mapByDateEntry.getValue();
for (String trans : allTrans) {
String sumtot = mapByTrans.get(trans);
if (sumtot != null) {
tableBuilder.append("<td>").append(sumtot).append("</td>");
} else {
tableBuilder.append("<td></td>");
}
}
tableBuilder.append("<tr>");
}
It's wasteful to do this in Java code, that's what the window functions are for in SQL. If you have a query like SELECT datet, trans, sumtout FROM ... you can use SUM with OVER:
SELECT DISTINCT datet, SUM(sumtout) OVER (PARTITION BY datet)
FROM ...
ORDER BY datet;
So I am trying to query one of my dynamoDB tables and for some reason it is not returning any results. I have another user table that has almost the exact same index and it returns a value. Here is my code:
String fbId = requestInfo.get("requestFbId");
System.out.println("The id is " + fbId);
Map<String, AttributeValue> exAttributeVal = new HashMap<String, AttributeValue>();
exAttributeVal.put(":val", new AttributeValue().withS(fbId));
QueryRequest friendsQuery = new QueryRequest()
.withTableName(Keys.friendsTable)
.withIndexName("User-Friends-index")
.withKeyConditionExpression("userId = :val")
.withExpressionAttributeValues(exAttributeVal);
QueryResult friendsQueryResult = dynamoDbClient.query(friendsQuery);
System.out.println("The size is " + friendsQueryResult.getItems().size());
for (int i = 0; i < friendsQueryResult.getItems().size(); i++) {
System.out.println("The result is " + friendsQueryResult.getItems().get(i));
}
Does anybody know what I could be doing wrong here? This also used to work directly on my android app, but it is not working now that I have moved it into lambda
I would like to print the labels of traindata / testdata used in classification. Here is the definition of both inputs (using deep4j).
InputSplit[] inputSplit = fileSplit.sample(pathFilter, splitTrainTest, 1 - splitTrainTest);
InputSplit trainData = inputSplit[0];
InputSplit testData = inputSplit[1];
that are then transformed in DataSetIterator like this :
ImageRecordReader recordReader = new ImageRecordReader(height, width, channels, labelMaker);
recordReader.initialize(trainData, null);
trainIter = new RecordReaderDataSetIterator(recordReader, batchSize, 1, numLabels);
Then I want to print how many examples per labels where found in each iterator in this function :
public void print(DataSetIterator iter){
HashMap<String, Integer> hash = new HashMap<String, Integer>();
while(iter.hasNext()){
DataSet example = iter.next();
for(int i = 0 ; i<numLabels ; i++){
if(example.getLabels().getDouble(i)==1.){
String label = example.getLabelName(i);
if(hash.containsKey(label))
hash.put(label, hash.get(label)+1);
else
hash.put(label, 1);
}
}
}
for (String label: hash.keySet()){
System.out.println(" label : " + label.toString() + ", " + hash.get(label) + " examples");
}
}
The issue is that it displays only one example per label, whereas there should much more... And when I don't split my dataset using fileSplit.sample() the function displays the right number of examples.
Any suggestion ?
If you use a dataset you can use the toString() of the dataset.getFeatureMatrix() and dataset.getLabels()
If you want to print just the label counts, you can use dataset.labelCounts() I would look more at the dl4j javadoc:
http://deeplearning4j.org/doc
I have a Map with different values:
props = new HashMap<String, Object>();
props.put("cmis:objectTypeId", "D:ruc:PLICO");
props.put("cmis:name", "PLICO_1.pdf");
props.put("cmis:description", "Descr");
props.put("ruc:doc_surname", "Rossi");
props.put("ruc:doc_name", "Mario");
I want to do a query (QueryStatement or other) that dynamically reads this parameters (some of them can be missing) and build QueryStatement.
Does it exist an easy way to generate the query String for QueryStatement? Or do I should iterate my Map to build a String containing all the parameters and values in my query?
My solution, but maybe somebody know how to improve it without dynamically build the query string:
StringBuilder query = new StringBuilder("SELECT * FROM ? where ");
String folder = null;
if (path!=null)
{
folder = findPath(path);
if (folder==null)
{
return null;
}
query.append("IN_FOLDER(?) AND ");
}
ArrayList <String> values = new ArrayList<String>();
Map<String, Object> properties = loadAnnotationAndData(doc);
String objectType = properties.remove(MyEnum.cmis_object_type_id.getValue()).toString();
for (Map.Entry<String, Object> entry : properties.entrySet())
{
System.out.println(entry.getKey() + " - " + entry.getValue());
query.append(entry.getKey() + "=? AND ");
values.add(entry.getValue().toString());
}
query.delete(query.length()-4, query.length());
query.append(" ORDER BY cmis:creationDate");
System.out.println(query.toString());
Session cmisSession = getCmisSession();
QueryStatement qs=
cmisSession.createQueryStatement(query.toString());
int offset = 1;
qs.setType(offset++, objectType);
if (path!=null)
{
qs.setString(offset++, folder);
}
for (int i=0; i<values.size(); i++)
{
System.out.println(values.get(i).toString());
qs.setString(i+offset, values.get(i).toString());
}
I'm trying to implement an expandable listview with data from a remote server. I've already have the JSON part covered. My sample has three value sets returned (confirmed by checking logcat on the original JSON response). My problem now is while dividing the JSON return into header and child datas, the first value set is skipped. My code is as follows:
int lisDataHeaderCounter = 0;
String searchKey;
for (int i = 0; i < components.length(); i++) {
List<String> component_value = new ArrayList<String>();
searchKey = main_components.get(i);
if (!listDataHeader.contains(searchKey)) {
listDataHeader.add(searchKey);
Iterator<Map.Entry<String, String>> entries = sub_components.entrySet().iterator();
while (entries.hasNext()) {
Map.Entry<String, String> entry = entries.next();
Log.d("getValue() ", "+ " + entry.getValue());
if (searchKey == entry.getKey())
component_value.add(entry.getValue());
}
listDataChild.put(listDataHeader.get(lisDataHeaderCounter), component_value);
lisDataHeaderCounter++;
}
}
I've also tried the code below and it still has the same result.
for (Map.Entry<String, String> entry : sub_components.entrySet()) {
if (searchKey == entry.getKey())
component_value.add(entry.getValue());
}
Here is a sample of the JSON response that is being process by the above codes:
[{"activity_code":"1","activity_name":"Midterm Exam"},
{"activity_code":"1","activity_name":"Final Exam"},
{"activity_code":"2","activity_name":"Project"}]
With the current codes, in the for loop, the first value of searchKey is '1'. When I placed a Log.d(); in the while loop to check what the first value is read, I found that it is "Final Exam" and not "Midterm Exam". Is there a way for me to get the value of the first data set before it goes into the while loop?
Here is a workaround I've made to ensure that the first value would be included to the sub_components. But I guess it doesn't look neat. If anyone has a better solution, please feel free to share.
for (int i = 0; i < components.length(); i++) {
JSONObject c = components.getJSONObject(i);
String formula_code = c.getString(TAG_FORMULA_CODE);
String component_name = c.getString(TAG_ACTIVITY_NAME);
main_components.add(formula_code);
sub_components.put(formula_code, component_name);
if (!listDataHeader.contains(formula_code))
listDataHeader.add(formula_code);
if (i == 0) {
component_value.add(component_name);
}
}
for (int i = 0; i < listDataHeader.size(); i++) {
for (Map.Entry<String, String> entry : sub_components.entrySet()) {
if (listDataHeader.get(i) == entry.getKey())
component_value.add(entry.getValue());
}
listDataChild.put(listDataHeader.get(i), component_value);
component_value = new ArrayList<String>();
}
I can't see any off by one error on the two, but perhaps it's the searchKey == entry.getKey(), that might have to be searchKey.equals(entry.getKey()), but I would need to see more code to know for sure.