add date range filter
This commit is contained in:
@@ -1,5 +1,13 @@
|
||||
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 {
|
||||
private String query;
|
||||
|
||||
@@ -13,6 +21,10 @@ public class PlotSettings {
|
||||
|
||||
private int limit;
|
||||
|
||||
private String dateFrom;
|
||||
|
||||
private String dateTo;
|
||||
|
||||
public String getQuery() {
|
||||
return query;
|
||||
}
|
||||
@@ -60,4 +72,38 @@ public class PlotSettings {
|
||||
public void setLimit(final int 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.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.lucares.pdb.api.Entry;
|
||||
@@ -53,13 +54,19 @@ public class Plotter {
|
||||
}
|
||||
|
||||
public File plot(final PlotSettings plotSettings) throws InternalPlottingException {
|
||||
|
||||
final String tmpSubDir = uniqueDirectoryName();
|
||||
final Path tmpDir = tmpBaseDir.resolve(tmpSubDir);
|
||||
try {
|
||||
Files.createDirectories(tmpDir);
|
||||
final List<DataSeries> dataSeries = new ArrayList<>();
|
||||
|
||||
final String query = plotSettings.getQuery();
|
||||
final String groupBy = plotSettings.getGroupBy();
|
||||
final int height = plotSettings.getHeight();
|
||||
final int width = plotSettings.getWidth();
|
||||
final OffsetDateTime dateFrom = plotSettings.dateFrom();
|
||||
final OffsetDateTime dateTo = plotSettings.dateTo();
|
||||
|
||||
final Result result = db.get(query, groupBy);
|
||||
|
||||
@@ -70,16 +77,18 @@ public class Plotter {
|
||||
|
||||
final Stream<Entry> entries = groupResult.asStream();
|
||||
|
||||
final File dataFile = File.createTempFile("data", ".dat", tmpBaseDir.toFile());
|
||||
final CsvSummary csvSummary = toCsv(entries, dataFile);
|
||||
final File dataFile = File.createTempFile("data", ".dat", tmpDir.toFile());
|
||||
final CsvSummary csvSummary = toCsv(entries, dataFile, dateFrom, dateTo);
|
||||
|
||||
final String title = title(groupResult.getGroupedBy(), csvSummary.getValues());
|
||||
final DataSeries dataSerie = new DataSeries(dataFile, title, csvSummary.getValues());
|
||||
if (dataSerie.getValues() > 0) {
|
||||
dataSeries.add(dataSerie);
|
||||
|
||||
maxDate = maxDate.compareTo(csvSummary.getMaxDate()) > 0 ? maxDate : csvSummary.getMaxDate();
|
||||
minDate = minDate.compareTo(csvSummary.getMinDate()) < 0 ? minDate : csvSummary.getMinDate();
|
||||
}
|
||||
}
|
||||
|
||||
sortAndLimit(dataSeries, plotSettings);
|
||||
|
||||
@@ -96,9 +105,16 @@ public class Plotter {
|
||||
throw new IllegalStateException("Plotting was interrupted.");
|
||||
} catch (final IOException 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) {
|
||||
|
||||
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();
|
||||
int count = 0;
|
||||
final long fromEpochMilli = dateFrom.toInstant().toEpochMilli();
|
||||
final long toEpochMilli = dateTo.toInstant().toEpochMilli();
|
||||
OffsetDateTime maxDate = OffsetDateTime.MIN;
|
||||
OffsetDateTime minDate = OffsetDateTime.MAX;
|
||||
final int separator = ',';
|
||||
@@ -190,8 +209,9 @@ public class Plotter {
|
||||
while (it.hasNext()) {
|
||||
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 String value = String.valueOf(entry.getValue());
|
||||
final String formattedDate = date.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
|
||||
output.write(formattedDate);
|
||||
output.write(separator);
|
||||
@@ -203,6 +223,7 @@ public class Plotter {
|
||||
minDate = minDate.compareTo(date) < 0 ? minDate : date;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("wrote " + count + " values to csv in: " + (System.nanoTime() - start) / 1_000_000.0 + "ms");
|
||||
return new CsvSummary(count, maxDate, minDate);
|
||||
|
||||
@@ -94,10 +94,10 @@ public class PdbController implements HardcodedValues, CollectionUtils {
|
||||
produces = MediaType.APPLICATION_JSON_UTF8_VALUE //
|
||||
)
|
||||
@ResponseBody
|
||||
List<String> fields(@RequestParam(name = "query") final String query) {
|
||||
List<String> fields() {
|
||||
|
||||
try {
|
||||
final List<String> fields = db.getDb().getFields(query);
|
||||
final List<String> fields = db.getDb().getFields();
|
||||
|
||||
return fields;
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@ class PlotSettingsTransformer {
|
||||
result.setWidth(request.getWidth());
|
||||
result.setLimit(request.getLimit());
|
||||
result.setLimitBy(toLimit(request.getLimitBy()));
|
||||
result.setDateFrom(request.getDateFrom());
|
||||
result.setDateTo(request.getDateTo());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,10 @@ public class PlotRequest {
|
||||
|
||||
private int limit = Integer.MAX_VALUE;
|
||||
|
||||
private String dateFrom;
|
||||
|
||||
private String dateTo;
|
||||
|
||||
public String getQuery() {
|
||||
return query;
|
||||
}
|
||||
@@ -65,4 +69,20 @@ public class PlotRequest {
|
||||
public void setLimit(final int 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;
|
||||
}
|
||||
|
||||
#search-bar .autocomplete, #search-bar .autocomplete ul {
|
||||
#search-bar .autocomplete {
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
#search-bar #search-input {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
#filter-bar {
|
||||
|
||||
}
|
||||
|
||||
@@ -29,6 +29,13 @@
|
||||
<option value="FEWEST_VALUES">fewest values</option>
|
||||
</select>
|
||||
<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>
|
||||
</div>
|
||||
<div id="result-view">
|
||||
|
||||
@@ -3,12 +3,12 @@ $(document).ready(function(){
|
||||
|
||||
$('#search-submit').click(plot);
|
||||
|
||||
renderFields();
|
||||
renderGroupBy();
|
||||
|
||||
$('#search-limit-by').change(function () {
|
||||
var optionSelected = $(this).find("option:selected");
|
||||
var valueSelected = optionSelected.val();
|
||||
console.log(valueSelected);
|
||||
|
||||
if (valueSelected == "NO_LIMIT"){
|
||||
$('#search-limit-value').hide();
|
||||
}else{
|
||||
@@ -23,6 +23,9 @@ $(document).ready(function(){
|
||||
var caretIndex = document.getElementById('search-input').selectionStart;
|
||||
return 'caretIndex=' + caretIndex + '&query';
|
||||
},
|
||||
_Pre: function() {
|
||||
return encodeURI(this.Input.value);
|
||||
},
|
||||
_Post: function(response) {
|
||||
var result = [];
|
||||
var responseObject = JSON.parse(response);
|
||||
@@ -40,10 +43,9 @@ $(document).ready(function(){
|
||||
});
|
||||
});
|
||||
|
||||
function renderFields()
|
||||
function renderGroupBy()
|
||||
{
|
||||
var request = {};
|
||||
request['query'] = $('#search-input').val();
|
||||
|
||||
var success = function(response){
|
||||
|
||||
@@ -85,6 +87,8 @@ function plot(event){
|
||||
request['groupBy'] = $('#search-group-by').val();
|
||||
request['limitBy'] = $('#search-limit-by').val();
|
||||
request['limit'] = parseInt($('#search-limit-value').val());
|
||||
request['dateFrom'] = $('#search-date-from').val();
|
||||
request['dateTo'] = $('#search-date-to').val();
|
||||
|
||||
|
||||
var success = function(response){
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
dependencies {
|
||||
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'
|
||||
|
||||
|
||||
|
||||
@@ -8,13 +8,15 @@ import java.nio.file.SimpleFileVisitor;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.List;
|
||||
import java.util.function.BiPredicate;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
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> {
|
||||
|
||||
@@ -22,7 +24,7 @@ public class FileUtils {
|
||||
public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException {
|
||||
|
||||
Files.delete(file);
|
||||
LOGGER.info("deleted: " + file.toFile().getAbsolutePath());
|
||||
LOGGER.trace("deleted: {}", file);
|
||||
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
@@ -31,7 +33,7 @@ public class FileUtils {
|
||||
public FileVisitResult postVisitDirectory(final Path dir, final IOException exc) throws IOException {
|
||||
|
||||
Files.delete(dir);
|
||||
LOGGER.info("deleted: " + dir.toFile().getAbsolutePath());
|
||||
LOGGER.trace("deleted: {}", dir);
|
||||
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
@@ -44,14 +46,13 @@ public class FileUtils {
|
||||
|
||||
while (attempt <= maxAttempts) {
|
||||
try {
|
||||
LOGGER.info(
|
||||
"deleting '" + path.toFile().getAbsolutePath() + "' attempt " + attempt + " of " + maxAttempts);
|
||||
LOGGER.debug("deleting '{}' attempt {} of {}", path.toFile().getAbsolutePath(), attempt, maxAttempts);
|
||||
Files.walkFileTree(path, new RecursiveDeleter());
|
||||
break;
|
||||
} catch (final IOException e) {
|
||||
final String msg = "failed to delete '" + path.toFile().getAbsolutePath() + "' on attempt " + attempt
|
||||
+ " of " + maxAttempts;
|
||||
LOGGER.log(Level.WARNING, msg, e);
|
||||
LOGGER.warn(msg, e);
|
||||
}
|
||||
attempt++;
|
||||
}
|
||||
|
||||
@@ -182,8 +182,9 @@ public class PerformanceDb implements AutoCloseable, CollectionUtils {
|
||||
return db.proposeTagForQuery(query, caretIndex);
|
||||
}
|
||||
|
||||
public List<String> getFields(final String query) {
|
||||
final List<Field> fields = db.getAvailableFieldsForQuery(query);
|
||||
public List<String> getFields() {
|
||||
|
||||
final List<Field> fields = db.getAvailableFields();
|
||||
|
||||
return map(fields, Field::getName);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user