add date range filter
This commit is contained in:
@@ -1,5 +1,13 @@
|
|||||||
package org.lucares.pdb.plot.api;
|
package org.lucares.pdb.plot.api;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
|
import java.time.OffsetTime;
|
||||||
|
import java.time.ZoneOffset;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
public class PlotSettings {
|
public class PlotSettings {
|
||||||
private String query;
|
private String query;
|
||||||
|
|
||||||
@@ -13,6 +21,10 @@ public class PlotSettings {
|
|||||||
|
|
||||||
private int limit;
|
private int limit;
|
||||||
|
|
||||||
|
private String dateFrom;
|
||||||
|
|
||||||
|
private String dateTo;
|
||||||
|
|
||||||
public String getQuery() {
|
public String getQuery() {
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
@@ -60,4 +72,38 @@ public class PlotSettings {
|
|||||||
public void setLimit(final int limit) {
|
public void setLimit(final int limit) {
|
||||||
this.limit = limit;
|
this.limit = limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getDateFrom() {
|
||||||
|
return dateFrom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDateFrom(final String dateFrom) {
|
||||||
|
this.dateFrom = dateFrom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDateTo() {
|
||||||
|
return dateTo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDateTo(final String dateTo) {
|
||||||
|
this.dateTo = dateTo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OffsetDateTime dateFrom() {
|
||||||
|
|
||||||
|
if (StringUtils.isEmpty(dateFrom)) {
|
||||||
|
|
||||||
|
return OffsetDateTime.ofInstant(Instant.ofEpochMilli(Long.MIN_VALUE), ZoneOffset.UTC);
|
||||||
|
} else {
|
||||||
|
return LocalDate.parse(dateFrom).atTime(OffsetTime.of(0, 0, 0, 0, ZoneOffset.UTC));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public OffsetDateTime dateTo() {
|
||||||
|
if (StringUtils.isEmpty(dateTo)) {
|
||||||
|
return OffsetDateTime.ofInstant(Instant.ofEpochMilli(Long.MAX_VALUE), ZoneOffset.UTC);
|
||||||
|
} else {
|
||||||
|
return LocalDate.parse(dateTo).atTime(OffsetTime.of(23, 59, 59, 999_999_999, ZoneOffset.UTC));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import org.lucares.pdb.api.Entry;
|
import org.lucares.pdb.api.Entry;
|
||||||
@@ -53,13 +54,19 @@ public class Plotter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public File plot(final PlotSettings plotSettings) throws InternalPlottingException {
|
public File plot(final PlotSettings plotSettings) throws InternalPlottingException {
|
||||||
|
|
||||||
|
final String tmpSubDir = uniqueDirectoryName();
|
||||||
|
final Path tmpDir = tmpBaseDir.resolve(tmpSubDir);
|
||||||
try {
|
try {
|
||||||
|
Files.createDirectories(tmpDir);
|
||||||
final List<DataSeries> dataSeries = new ArrayList<>();
|
final List<DataSeries> dataSeries = new ArrayList<>();
|
||||||
|
|
||||||
final String query = plotSettings.getQuery();
|
final String query = plotSettings.getQuery();
|
||||||
final String groupBy = plotSettings.getGroupBy();
|
final String groupBy = plotSettings.getGroupBy();
|
||||||
final int height = plotSettings.getHeight();
|
final int height = plotSettings.getHeight();
|
||||||
final int width = plotSettings.getWidth();
|
final int width = plotSettings.getWidth();
|
||||||
|
final OffsetDateTime dateFrom = plotSettings.dateFrom();
|
||||||
|
final OffsetDateTime dateTo = plotSettings.dateTo();
|
||||||
|
|
||||||
final Result result = db.get(query, groupBy);
|
final Result result = db.get(query, groupBy);
|
||||||
|
|
||||||
@@ -70,15 +77,17 @@ public class Plotter {
|
|||||||
|
|
||||||
final Stream<Entry> entries = groupResult.asStream();
|
final Stream<Entry> entries = groupResult.asStream();
|
||||||
|
|
||||||
final File dataFile = File.createTempFile("data", ".dat", tmpBaseDir.toFile());
|
final File dataFile = File.createTempFile("data", ".dat", tmpDir.toFile());
|
||||||
final CsvSummary csvSummary = toCsv(entries, dataFile);
|
final CsvSummary csvSummary = toCsv(entries, dataFile, dateFrom, dateTo);
|
||||||
|
|
||||||
final String title = title(groupResult.getGroupedBy(), csvSummary.getValues());
|
final String title = title(groupResult.getGroupedBy(), csvSummary.getValues());
|
||||||
final DataSeries dataSerie = new DataSeries(dataFile, title, csvSummary.getValues());
|
final DataSeries dataSerie = new DataSeries(dataFile, title, csvSummary.getValues());
|
||||||
dataSeries.add(dataSerie);
|
if (dataSerie.getValues() > 0) {
|
||||||
|
dataSeries.add(dataSerie);
|
||||||
|
|
||||||
maxDate = maxDate.compareTo(csvSummary.getMaxDate()) > 0 ? maxDate : csvSummary.getMaxDate();
|
maxDate = maxDate.compareTo(csvSummary.getMaxDate()) > 0 ? maxDate : csvSummary.getMaxDate();
|
||||||
minDate = minDate.compareTo(csvSummary.getMinDate()) < 0 ? minDate : csvSummary.getMinDate();
|
minDate = minDate.compareTo(csvSummary.getMinDate()) < 0 ? minDate : csvSummary.getMinDate();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sortAndLimit(dataSeries, plotSettings);
|
sortAndLimit(dataSeries, plotSettings);
|
||||||
@@ -96,9 +105,16 @@ public class Plotter {
|
|||||||
throw new IllegalStateException("Plotting was interrupted.");
|
throw new IllegalStateException("Plotting was interrupted.");
|
||||||
} catch (final IOException e) {
|
} catch (final IOException e) {
|
||||||
throw new InternalPlottingException("Plotting failed.", e);
|
throw new InternalPlottingException("Plotting failed.", e);
|
||||||
|
} finally {
|
||||||
|
FileUtils.delete(tmpDir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String uniqueDirectoryName() {
|
||||||
|
return OffsetDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd_HH_mm_ss")) + "_"
|
||||||
|
+ UUID.randomUUID().toString();
|
||||||
|
}
|
||||||
|
|
||||||
private String getFormatX(final OffsetDateTime minDate, final OffsetDateTime maxDate) {
|
private String getFormatX(final OffsetDateTime minDate, final OffsetDateTime maxDate) {
|
||||||
|
|
||||||
if (minDate.until(maxDate, ChronoUnit.WEEKS) > 1) {
|
if (minDate.until(maxDate, ChronoUnit.WEEKS) > 1) {
|
||||||
@@ -176,10 +192,13 @@ public class Plotter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static CsvSummary toCsv(final Stream<Entry> entries, final File dataFile) throws IOException {
|
private static CsvSummary toCsv(final Stream<Entry> entries, final File dataFile, final OffsetDateTime dateFrom,
|
||||||
|
final OffsetDateTime dateTo) throws IOException {
|
||||||
|
|
||||||
final long start = System.nanoTime();
|
final long start = System.nanoTime();
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
final long fromEpochMilli = dateFrom.toInstant().toEpochMilli();
|
||||||
|
final long toEpochMilli = dateTo.toInstant().toEpochMilli();
|
||||||
OffsetDateTime maxDate = OffsetDateTime.MIN;
|
OffsetDateTime maxDate = OffsetDateTime.MIN;
|
||||||
OffsetDateTime minDate = OffsetDateTime.MAX;
|
OffsetDateTime minDate = OffsetDateTime.MAX;
|
||||||
final int separator = ',';
|
final int separator = ',';
|
||||||
@@ -190,17 +209,19 @@ public class Plotter {
|
|||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
final Entry entry = it.next();
|
final Entry entry = it.next();
|
||||||
|
|
||||||
final String value = String.valueOf(entry.getValue());
|
if (fromEpochMilli <= entry.getEpochMilli() && entry.getEpochMilli() <= toEpochMilli) {
|
||||||
final OffsetDateTime date = entry.getDate();
|
final OffsetDateTime date = entry.getDate();
|
||||||
final String formattedDate = date.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
|
final String value = String.valueOf(entry.getValue());
|
||||||
output.write(formattedDate);
|
final String formattedDate = date.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
|
||||||
output.write(separator);
|
output.write(formattedDate);
|
||||||
output.write(value);
|
output.write(separator);
|
||||||
output.write(newline);
|
output.write(value);
|
||||||
|
output.write(newline);
|
||||||
|
|
||||||
count++;
|
count++;
|
||||||
maxDate = maxDate.compareTo(date) > 0 ? maxDate : date;
|
maxDate = maxDate.compareTo(date) > 0 ? maxDate : date;
|
||||||
minDate = minDate.compareTo(date) < 0 ? minDate : date;
|
minDate = minDate.compareTo(date) < 0 ? minDate : date;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -94,10 +94,10 @@ public class PdbController implements HardcodedValues, CollectionUtils {
|
|||||||
produces = MediaType.APPLICATION_JSON_UTF8_VALUE //
|
produces = MediaType.APPLICATION_JSON_UTF8_VALUE //
|
||||||
)
|
)
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
List<String> fields(@RequestParam(name = "query") final String query) {
|
List<String> fields() {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final List<String> fields = db.getDb().getFields(query);
|
final List<String> fields = db.getDb().getFields();
|
||||||
|
|
||||||
return fields;
|
return fields;
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ class PlotSettingsTransformer {
|
|||||||
result.setWidth(request.getWidth());
|
result.setWidth(request.getWidth());
|
||||||
result.setLimit(request.getLimit());
|
result.setLimit(request.getLimit());
|
||||||
result.setLimitBy(toLimit(request.getLimitBy()));
|
result.setLimitBy(toLimit(request.getLimitBy()));
|
||||||
|
result.setDateFrom(request.getDateFrom());
|
||||||
|
result.setDateTo(request.getDateTo());
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,10 @@ public class PlotRequest {
|
|||||||
|
|
||||||
private int limit = Integer.MAX_VALUE;
|
private int limit = Integer.MAX_VALUE;
|
||||||
|
|
||||||
|
private String dateFrom;
|
||||||
|
|
||||||
|
private String dateTo;
|
||||||
|
|
||||||
public String getQuery() {
|
public String getQuery() {
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
@@ -65,4 +69,20 @@ public class PlotRequest {
|
|||||||
public void setLimit(final int limit) {
|
public void setLimit(final int limit) {
|
||||||
this.limit = limit;
|
this.limit = limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getDateFrom() {
|
||||||
|
return dateFrom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDateFrom(final String dateFrom) {
|
||||||
|
this.dateFrom = dateFrom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDateTo() {
|
||||||
|
return dateTo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDateTo(final String dateTo) {
|
||||||
|
this.dateTo = dateTo;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,10 +45,14 @@ html, body {
|
|||||||
background-color: #AAA;
|
background-color: #AAA;
|
||||||
}
|
}
|
||||||
|
|
||||||
#search-bar .autocomplete, #search-bar .autocomplete ul {
|
#search-bar .autocomplete {
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#search-bar #search-input {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
#filter-bar {
|
#filter-bar {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,13 @@
|
|||||||
<option value="FEWEST_VALUES">fewest values</option>
|
<option value="FEWEST_VALUES">fewest values</option>
|
||||||
</select>
|
</select>
|
||||||
<input type="number" id="search-limit-value" name="search-limit-value" min="1" max="1000000" value="10" style="display: none;"/>
|
<input type="number" id="search-limit-value" name="search-limit-value" min="1" max="1000000" value="10" style="display: none;"/>
|
||||||
|
|
||||||
|
<label>From Date:</label>
|
||||||
|
<input id="search-date-from" type="date">
|
||||||
|
|
||||||
|
<label>To Date:</label>
|
||||||
|
<input id="search-date-to" type="date">
|
||||||
|
|
||||||
<button id="search-submit"><i class="fa fa-area-chart"> Plot</i></button>
|
<button id="search-submit"><i class="fa fa-area-chart"> Plot</i></button>
|
||||||
</div>
|
</div>
|
||||||
<div id="result-view">
|
<div id="result-view">
|
||||||
|
|||||||
@@ -3,12 +3,12 @@ $(document).ready(function(){
|
|||||||
|
|
||||||
$('#search-submit').click(plot);
|
$('#search-submit').click(plot);
|
||||||
|
|
||||||
renderFields();
|
renderGroupBy();
|
||||||
|
|
||||||
$('#search-limit-by').change(function () {
|
$('#search-limit-by').change(function () {
|
||||||
var optionSelected = $(this).find("option:selected");
|
var optionSelected = $(this).find("option:selected");
|
||||||
var valueSelected = optionSelected.val();
|
var valueSelected = optionSelected.val();
|
||||||
console.log(valueSelected);
|
|
||||||
if (valueSelected == "NO_LIMIT"){
|
if (valueSelected == "NO_LIMIT"){
|
||||||
$('#search-limit-value').hide();
|
$('#search-limit-value').hide();
|
||||||
}else{
|
}else{
|
||||||
@@ -23,6 +23,9 @@ $(document).ready(function(){
|
|||||||
var caretIndex = document.getElementById('search-input').selectionStart;
|
var caretIndex = document.getElementById('search-input').selectionStart;
|
||||||
return 'caretIndex=' + caretIndex + '&query';
|
return 'caretIndex=' + caretIndex + '&query';
|
||||||
},
|
},
|
||||||
|
_Pre: function() {
|
||||||
|
return encodeURI(this.Input.value);
|
||||||
|
},
|
||||||
_Post: function(response) {
|
_Post: function(response) {
|
||||||
var result = [];
|
var result = [];
|
||||||
var responseObject = JSON.parse(response);
|
var responseObject = JSON.parse(response);
|
||||||
@@ -40,10 +43,9 @@ $(document).ready(function(){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function renderFields()
|
function renderGroupBy()
|
||||||
{
|
{
|
||||||
var request = {};
|
var request = {};
|
||||||
request['query'] = $('#search-input').val();
|
|
||||||
|
|
||||||
var success = function(response){
|
var success = function(response){
|
||||||
|
|
||||||
@@ -85,6 +87,8 @@ function plot(event){
|
|||||||
request['groupBy'] = $('#search-group-by').val();
|
request['groupBy'] = $('#search-group-by').val();
|
||||||
request['limitBy'] = $('#search-limit-by').val();
|
request['limitBy'] = $('#search-limit-by').val();
|
||||||
request['limit'] = parseInt($('#search-limit-value').val());
|
request['limit'] = parseInt($('#search-limit-value').val());
|
||||||
|
request['dateFrom'] = $('#search-date-from').val();
|
||||||
|
request['dateTo'] = $('#search-date-to').val();
|
||||||
|
|
||||||
|
|
||||||
var success = function(response){
|
var success = function(response){
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile project(':pdb-api')
|
compile project(':pdb-api')
|
||||||
compile 'org.lucares:ludb:1.0.20170207192657'
|
compile 'org.lucares:ludb:1.0.20170218180719'
|
||||||
compile 'com.fasterxml.jackson.core:jackson-databind:2.8.6'
|
compile 'com.fasterxml.jackson.core:jackson-databind:2.8.6'
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -8,13 +8,15 @@ import java.nio.file.SimpleFileVisitor;
|
|||||||
import java.nio.file.attribute.BasicFileAttributes;
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.BiPredicate;
|
import java.util.function.BiPredicate;
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
public class FileUtils {
|
public class FileUtils {
|
||||||
private static final Logger LOGGER = Logger.getLogger(FileUtils.class.getCanonicalName());
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(FileUtils.class);
|
||||||
|
|
||||||
private static final class RecursiveDeleter extends SimpleFileVisitor<Path> {
|
private static final class RecursiveDeleter extends SimpleFileVisitor<Path> {
|
||||||
|
|
||||||
@@ -22,7 +24,7 @@ public class FileUtils {
|
|||||||
public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException {
|
public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException {
|
||||||
|
|
||||||
Files.delete(file);
|
Files.delete(file);
|
||||||
LOGGER.info("deleted: " + file.toFile().getAbsolutePath());
|
LOGGER.trace("deleted: {}", file);
|
||||||
|
|
||||||
return FileVisitResult.CONTINUE;
|
return FileVisitResult.CONTINUE;
|
||||||
}
|
}
|
||||||
@@ -31,7 +33,7 @@ public class FileUtils {
|
|||||||
public FileVisitResult postVisitDirectory(final Path dir, final IOException exc) throws IOException {
|
public FileVisitResult postVisitDirectory(final Path dir, final IOException exc) throws IOException {
|
||||||
|
|
||||||
Files.delete(dir);
|
Files.delete(dir);
|
||||||
LOGGER.info("deleted: " + dir.toFile().getAbsolutePath());
|
LOGGER.trace("deleted: {}", dir);
|
||||||
|
|
||||||
return FileVisitResult.CONTINUE;
|
return FileVisitResult.CONTINUE;
|
||||||
}
|
}
|
||||||
@@ -44,14 +46,13 @@ public class FileUtils {
|
|||||||
|
|
||||||
while (attempt <= maxAttempts) {
|
while (attempt <= maxAttempts) {
|
||||||
try {
|
try {
|
||||||
LOGGER.info(
|
LOGGER.debug("deleting '{}' attempt {} of {}", path.toFile().getAbsolutePath(), attempt, maxAttempts);
|
||||||
"deleting '" + path.toFile().getAbsolutePath() + "' attempt " + attempt + " of " + maxAttempts);
|
|
||||||
Files.walkFileTree(path, new RecursiveDeleter());
|
Files.walkFileTree(path, new RecursiveDeleter());
|
||||||
break;
|
break;
|
||||||
} catch (final IOException e) {
|
} catch (final IOException e) {
|
||||||
final String msg = "failed to delete '" + path.toFile().getAbsolutePath() + "' on attempt " + attempt
|
final String msg = "failed to delete '" + path.toFile().getAbsolutePath() + "' on attempt " + attempt
|
||||||
+ " of " + maxAttempts;
|
+ " of " + maxAttempts;
|
||||||
LOGGER.log(Level.WARNING, msg, e);
|
LOGGER.warn(msg, e);
|
||||||
}
|
}
|
||||||
attempt++;
|
attempt++;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -182,8 +182,9 @@ public class PerformanceDb implements AutoCloseable, CollectionUtils {
|
|||||||
return db.proposeTagForQuery(query, caretIndex);
|
return db.proposeTagForQuery(query, caretIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<String> getFields(final String query) {
|
public List<String> getFields() {
|
||||||
final List<Field> fields = db.getAvailableFieldsForQuery(query);
|
|
||||||
|
final List<Field> fields = db.getAvailableFields();
|
||||||
|
|
||||||
return map(fields, Field::getName);
|
return map(fields, Field::getName);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user