Временные ряды #59
@ -61,6 +61,7 @@ dependencies {
|
|||||||
implementation group: 'commons-io', name: 'commons-io', version: '2.6'
|
implementation group: 'commons-io', name: 'commons-io', version: '2.6'
|
||||||
implementation group: 'net.sourceforge.htmlunit', name: 'htmlunit', version: '2.35.0'
|
implementation group: 'net.sourceforge.htmlunit', name: 'htmlunit', version: '2.35.0'
|
||||||
implementation group: 'com.github.javaparser', name: 'javaparser-core', version: '3.20.2'
|
implementation group: 'com.github.javaparser', name: 'javaparser-core', version: '3.20.2'
|
||||||
|
implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.12.0'
|
||||||
|
|
||||||
implementation group: 'io.springfox', name: 'springfox-boot-starter', version: '3.0.0'
|
implementation group: 'io.springfox', name: 'springfox-boot-starter', version: '3.0.0'
|
||||||
|
|
||||||
|
@ -3,7 +3,11 @@ package ru.ulstu.extractor.model;
|
|||||||
import org.hibernate.annotations.Fetch;
|
import org.hibernate.annotations.Fetch;
|
||||||
import org.hibernate.annotations.FetchMode;
|
import org.hibernate.annotations.FetchMode;
|
||||||
|
|
||||||
import javax.persistence.*;
|
import javax.persistence.CascadeType;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.FetchType;
|
||||||
|
import javax.persistence.JoinColumn;
|
||||||
|
import javax.persistence.OneToMany;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -15,11 +19,18 @@ public class TimeSeries extends BaseEntity {
|
|||||||
@Fetch(FetchMode.SUBSELECT)
|
@Fetch(FetchMode.SUBSELECT)
|
||||||
private List<TimeSeriesValue> values = new ArrayList<>();
|
private List<TimeSeriesValue> values = new ArrayList<>();
|
||||||
|
|
||||||
|
public TimeSeries() {
|
||||||
|
}
|
||||||
|
|
||||||
public TimeSeries(String name) {
|
public TimeSeries(String name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TimeSeries(String name, List<TimeSeriesValue> values) {
|
||||||
|
this.name = name;
|
||||||
|
this.values = values;
|
||||||
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,15 @@ public class TimeSeriesValue extends BaseEntity {
|
|||||||
@ManyToOne(fetch = FetchType.LAZY)
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
private TimeSeries timeSeries;
|
private TimeSeries timeSeries;
|
||||||
|
|
||||||
|
public TimeSeriesValue() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public TimeSeriesValue(Date date, Integer value) {
|
||||||
|
this.timeSeries = timeSeries;
|
||||||
|
this.date = date;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
public TimeSeriesValue(TimeSeries timeSeries, Date date, Integer value) {
|
public TimeSeriesValue(TimeSeries timeSeries, Date date, Integer value) {
|
||||||
this.timeSeries = timeSeries;
|
this.timeSeries = timeSeries;
|
||||||
this.date = date;
|
this.date = date;
|
||||||
@ -34,11 +43,11 @@ public class TimeSeriesValue extends BaseEntity {
|
|||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TimeSeries getTimeSeriesType() {
|
public TimeSeries getTimeSeries() {
|
||||||
return timeSeries;
|
return timeSeries;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTimeSeriesType(TimeSeries timeSeries) {
|
public void setTimeSeries(TimeSeries timeSeries) {
|
||||||
this.timeSeries = timeSeries;
|
this.timeSeries = timeSeries;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,59 @@
|
|||||||
|
package ru.ulstu.extractor.ts;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.time.DateUtils;
|
||||||
|
import ru.ulstu.extractor.model.TimeSeries;
|
||||||
|
import ru.ulstu.extractor.model.TimeSeriesValue;
|
||||||
|
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Класс для регулировки дискретности временного ряда.
|
||||||
|
* Можно создать временной ряд с точками с секундными отметками, затем суммировать значения,
|
||||||
|
* применив одно из значений TimeSeriesInterval
|
||||||
|
*/
|
||||||
|
public class TimeSeriesDateMapper {
|
||||||
|
|
||||||
|
public TimeSeries mapTimeSeriesToInterval(TimeSeriesInterval timeSeriesInterval, TimeSeries timeSeries) {
|
||||||
|
List<TimeSeriesValue> trimmedTimeSeriesValues = timeSeries.getValues()
|
||||||
|
.stream()
|
||||||
|
.map(timeSeriesValue -> new TimeSeriesValue(trimTo(timeSeriesInterval, timeSeriesValue.getDate()),
|
||||||
|
timeSeriesValue.getValue()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
Map<Date, Integer> groupedTimeSeriesValues = trimmedTimeSeriesValues
|
||||||
|
.stream()
|
||||||
|
.collect(Collectors.groupingBy(TimeSeriesValue::getDate,
|
||||||
|
Collectors.summingInt(TimeSeriesValue::getValue)));
|
||||||
|
|
||||||
|
return new TimeSeries(timeSeries.getName(), groupedTimeSeriesValues.entrySet()
|
||||||
|
.stream()
|
||||||
|
.map(e -> new TimeSeriesValue(e.getKey(), e.getValue()))
|
||||||
|
.collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Date trimTo(TimeSeriesInterval timeSeriesInterval, Date date) {
|
||||||
|
return DateUtils.truncate(date, timeSeriesInterval.calendarField);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Интервальность временного ряда при преобразовании
|
||||||
|
*/
|
||||||
|
public enum TimeSeriesInterval {
|
||||||
|
SECOND(Calendar.SECOND),
|
||||||
|
MINUTE(Calendar.MINUTE),
|
||||||
|
HOUR(Calendar.HOUR_OF_DAY),
|
||||||
|
DAY(Calendar.DAY_OF_MONTH),
|
||||||
|
WEEK(Calendar.WEEK_OF_MONTH),
|
||||||
|
MONTH(Calendar.MONTH),
|
||||||
|
YEAR(Calendar.YEAR);
|
||||||
|
|
||||||
|
private final int calendarField;
|
||||||
|
|
||||||
|
TimeSeriesInterval(int calendarField) {
|
||||||
|
this.calendarField = calendarField;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
103
src/test/java/ru/ulstu/TimeSeriesMapperTest.java
Normal file
103
src/test/java/ru/ulstu/TimeSeriesMapperTest.java
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
package ru.ulstu;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import ru.ulstu.extractor.model.TimeSeries;
|
||||||
|
import ru.ulstu.extractor.model.TimeSeriesValue;
|
||||||
|
import ru.ulstu.extractor.ts.TimeSeriesDateMapper;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.GregorianCalendar;
|
||||||
|
|
||||||
|
public class TimeSeriesMapperTest {
|
||||||
|
@Test
|
||||||
|
public void testMappingByDay() {
|
||||||
|
Calendar c1 = GregorianCalendar.getInstance();
|
||||||
|
c1.set(2020, 5, 1, 1, 1, 1);
|
||||||
|
Calendar c2 = GregorianCalendar.getInstance();
|
||||||
|
c2.set(2020, 5, 2, 2, 1, 1);
|
||||||
|
TimeSeries timeSeries = new TimeSeries("Тестовый",
|
||||||
|
Arrays.asList(new TimeSeriesValue(c1.getTime(), 10),
|
||||||
|
new TimeSeriesValue(c2.getTime(), 10)));
|
||||||
|
TimeSeriesDateMapper mapper = new TimeSeriesDateMapper();
|
||||||
|
timeSeries = mapper.mapTimeSeriesToInterval(TimeSeriesDateMapper.TimeSeriesInterval.MONTH, timeSeries);
|
||||||
|
Assert.assertEquals(1, timeSeries.getValues().size());
|
||||||
|
Assert.assertEquals(Integer.valueOf(20), timeSeries.getValues().get(0).getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMappingByDayDifferent() {
|
||||||
|
Calendar c1 = GregorianCalendar.getInstance();
|
||||||
|
c1.set(2020, 5, 1, 1, 1, 1);
|
||||||
|
Calendar c2 = GregorianCalendar.getInstance();
|
||||||
|
c2.set(2020, 5, 2, 1, 1, 1);
|
||||||
|
TimeSeries timeSeries = new TimeSeries("Тестовый",
|
||||||
|
Arrays.asList(new TimeSeriesValue(c1.getTime(), 10),
|
||||||
|
new TimeSeriesValue(c2.getTime(), 10)));
|
||||||
|
TimeSeriesDateMapper mapper = new TimeSeriesDateMapper();
|
||||||
|
timeSeries = mapper.mapTimeSeriesToInterval(TimeSeriesDateMapper.TimeSeriesInterval.MONTH, timeSeries);
|
||||||
|
Assert.assertEquals(1, timeSeries.getValues().size());
|
||||||
|
Assert.assertEquals(Integer.valueOf(20), timeSeries.getValues().get(0).getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMappingByMonth() {
|
||||||
|
Calendar c1 = GregorianCalendar.getInstance();
|
||||||
|
c1.set(2020, 5, 1, 1, 1, 1);
|
||||||
|
Calendar c2 = GregorianCalendar.getInstance();
|
||||||
|
c2.set(2020, 5, 2, 1, 1, 1);
|
||||||
|
TimeSeries timeSeries = new TimeSeries("Тестовый",
|
||||||
|
Arrays.asList(new TimeSeriesValue(c1.getTime(), 10),
|
||||||
|
new TimeSeriesValue(c2.getTime(), 10)));
|
||||||
|
TimeSeriesDateMapper mapper = new TimeSeriesDateMapper();
|
||||||
|
timeSeries = mapper.mapTimeSeriesToInterval(TimeSeriesDateMapper.TimeSeriesInterval.MONTH, timeSeries);
|
||||||
|
Assert.assertEquals(1, timeSeries.getValues().size());
|
||||||
|
Assert.assertEquals(Integer.valueOf(20), timeSeries.getValues().get(0).getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMappingByMonthDifferent() {
|
||||||
|
Calendar c1 = GregorianCalendar.getInstance();
|
||||||
|
c1.set(2020, 5, 1, 1, 1, 1);
|
||||||
|
Calendar c2 = GregorianCalendar.getInstance();
|
||||||
|
c2.set(2020, 6, 2, 1, 1, 1);
|
||||||
|
TimeSeries timeSeries = new TimeSeries("Тестовый",
|
||||||
|
Arrays.asList(new TimeSeriesValue(c1.getTime(), 10),
|
||||||
|
new TimeSeriesValue(c2.getTime(), 10)));
|
||||||
|
TimeSeriesDateMapper mapper = new TimeSeriesDateMapper();
|
||||||
|
timeSeries = mapper.mapTimeSeriesToInterval(TimeSeriesDateMapper.TimeSeriesInterval.MONTH, timeSeries);
|
||||||
|
Assert.assertEquals(2, timeSeries.getValues().size());
|
||||||
|
Assert.assertEquals(Integer.valueOf(10), timeSeries.getValues().get(0).getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMappingByYear() {
|
||||||
|
Calendar c1 = GregorianCalendar.getInstance();
|
||||||
|
c1.set(2020, 5, 1, 1, 1, 1);
|
||||||
|
Calendar c2 = GregorianCalendar.getInstance();
|
||||||
|
c2.set(2020, 5, 2, 1, 1, 1);
|
||||||
|
TimeSeries timeSeries = new TimeSeries("Тестовый",
|
||||||
|
Arrays.asList(new TimeSeriesValue(c1.getTime(), 10),
|
||||||
|
new TimeSeriesValue(c2.getTime(), 10)));
|
||||||
|
TimeSeriesDateMapper mapper = new TimeSeriesDateMapper();
|
||||||
|
timeSeries = mapper.mapTimeSeriesToInterval(TimeSeriesDateMapper.TimeSeriesInterval.YEAR, timeSeries);
|
||||||
|
Assert.assertEquals(1, timeSeries.getValues().size());
|
||||||
|
Assert.assertEquals(Integer.valueOf(20), timeSeries.getValues().get(0).getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMappingByYearDifferent() {
|
||||||
|
Calendar c1 = GregorianCalendar.getInstance();
|
||||||
|
c1.set(2020, 5, 1, 1, 1, 1);
|
||||||
|
Calendar c2 = GregorianCalendar.getInstance();
|
||||||
|
c2.set(2021, 5, 2, 1, 1, 1);
|
||||||
|
TimeSeries timeSeries = new TimeSeries("Тестовый",
|
||||||
|
Arrays.asList(new TimeSeriesValue(c1.getTime(), 10),
|
||||||
|
new TimeSeriesValue(c2.getTime(), 10)));
|
||||||
|
TimeSeriesDateMapper mapper = new TimeSeriesDateMapper();
|
||||||
|
timeSeries = mapper.mapTimeSeriesToInterval(TimeSeriesDateMapper.TimeSeriesInterval.YEAR, timeSeries);
|
||||||
|
Assert.assertEquals(2, timeSeries.getValues().size());
|
||||||
|
Assert.assertEquals(Integer.valueOf(10), timeSeries.getValues().get(0).getValue());
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user