Skip to content

Commit 9cd60a4

Browse files
authored
Merge pull request #40 from redlink-gmbh/umm/develop/274-observation-bug
Umm/develop/274 observation bug
2 parents 96f9d0c + 2e1420d commit 9cd60a4

5 files changed

Lines changed: 54 additions & 31 deletions

File tree

studymanager-core/src/main/java/io/redlink/more/studymanager/core/measurement/Measurement.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
public class Measurement {
1414
public enum Type {
15-
INTEGER, DOUBLE, LONG, STRING, BOOLEAN, DATE, OBJECT, STRING_ARRAY
15+
INTEGER, DOUBLE, LONG, STRING, BOOLEAN, DATE, OBJECT, ARRAY
1616
}
1717

1818
private String id;

studymanager-observation/src/main/java/io/redlink/more/studymanager/component/observation/MultipleChoiceQuestionObservationFactory.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,17 @@
2525
public class MultipleChoiceQuestionObservationFactory<C extends Observation<P>, P extends ObservationProperties>
2626
extends ObservationFactory<C, P> {
2727

28-
public static final String FIELD_ANSWERS = "answers";
28+
public static final String FIELD_ANSWERS = "answers";
2929

3030
private static final MeasurementSet measurements = new MeasurementSet(
31-
"MULTIPLE_CHOICE_ANSWERS", Set.of(new Measurement(FIELD_ANSWERS, Measurement.Type.STRING_ARRAY))
31+
"MULTIPLE_CHOICE_ANSWERS", Set.of(new Measurement(FIELD_ANSWERS, Measurement.Type.ARRAY))
3232
);
3333

3434
private static List<Value> properties = List.of(
35-
new StringValue("question")
36-
.setName("observation.factory.multipleChoiceQuestion.configProps.questionName")
37-
.setDescription("observation.factory.multipleChoiceQuestion.configProps.questionDesc")
38-
.setRequired(true),
35+
new StringValue("question")
36+
.setName("observation.factory.multipleChoiceQuestion.configProps.questionName")
37+
.setDescription("observation.factory.multipleChoiceQuestion.configProps.questionDesc")
38+
.setRequired(true),
3939
new StringListValue("answers")
4040
.setMinSize(2)
4141
.setMaxSize(10)
@@ -68,7 +68,7 @@ public List<Value> getProperties() {
6868

6969
@Override
7070
public MultipleChoiceQuestionObservation create(MoreObservationSDK sdk, ObservationProperties properties) throws ConfigurationValidationException {
71-
return new MultipleChoiceQuestionObservation(sdk, validate((P)properties));
71+
return new MultipleChoiceQuestionObservation(sdk, validate((P) properties));
7272
}
7373

7474
@Override

studymanager-observation/src/test/java/io/redlink/more/studymanager/component/observation/lime/MultipleChoiceQuestionObservationTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public void testValidation() {
3434
MultipleChoiceQuestionObservation<?> observation = new MultipleChoiceQuestionObservation<>(sdk, properties);
3535

3636
var answerSummary = new MeasurementSummary(
37-
new Measurement(MultipleChoiceQuestionObservationFactory.FIELD_ANSWERS, Measurement.Type.STRING_ARRAY));
37+
new Measurement(MultipleChoiceQuestionObservationFactory.FIELD_ANSWERS, Measurement.Type.ARRAY));
3838
answerSummary.setArrayResult(new ArrayMeasurementSummary<>(new FieldValue<>(List.of("Antwort1", "Antwort 2"), 2)));
3939
ObservationDataSummary validSummary = new ObservationDataSummary(
4040
1,
@@ -64,7 +64,7 @@ public void testValidation() {
6464
Assertions.assertEquals(ObservationDataState.MISSING, result.state());
6565

6666
var nullAnswerSummary = new MeasurementSummary(
67-
new Measurement(MultipleChoiceQuestionObservationFactory.FIELD_ANSWERS, Measurement.Type.STRING_ARRAY));
67+
new Measurement(MultipleChoiceQuestionObservationFactory.FIELD_ANSWERS, Measurement.Type.ARRAY));
6868
nullAnswerSummary.setArrayResult(new ArrayMeasurementSummary<String>(new FieldValue<>(null, 1)));
6969
ObservationDataSummary invalidAnswerSummary = new ObservationDataSummary(
7070
1,

studymanager-services/src/main/java/io/redlink/more/studymanager/scheduling/UpsertOccurredObservationsCron.java

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -48,16 +48,16 @@ public class UpsertOccurredObservationsCron {
4848
this.calendarService = calendarService;
4949
}
5050

51-
@Scheduled(cron="0 */5 * * * ?") //every 5min
52-
protected void upsertOccurredObservations(){
51+
@Scheduled(cron = "0 */5 * * * ?") //every 5min
52+
protected void upsertOccurredObservations() {
5353
try (var stream = studyService.getStudiesByStates(Study.Status.ACTIVE_STATES)) {
5454
stream.forEach(this::upsertOccurredObservations);
5555
}
5656
}
5757

5858
private void upsertOccurredObservations(Study study) {
5959
try (var ctx = LoggingUtils.createContext()) {
60-
if(study == null || !Study.Status.ACTIVE_STATES.contains(study.getStudyState())) {
60+
if (study == null || !Study.Status.ACTIVE_STATES.contains(study.getStudyState())) {
6161
return; //nothing to do
6262
}
6363
ctx.putStudy(study);
@@ -69,22 +69,22 @@ private void upsertOccurredObservations(Study study) {
6969
Instant current = Instant.now().plus(1, ChronoUnit.MINUTES).truncatedTo(ChronoUnit.MINUTES);
7070
LOGGER.debug("Upsert Occurred Observations for Study(id: {}) ", study.getStudyId());
7171
participants.stream()
72-
.filter(participant -> participant.getStatus() == Participant.Status.ACTIVE)
73-
.forEach(participant -> {
74-
Instant lastOccurredObservation = occurredObservationService.getLatestStartTime(study.getStudyId(), participant.getParticipantId());
75-
LOGGER.debug("Upsert Occurred Observations for Study(id: {}) Participant(id: {}) and timeperiode(start:{}, end:{})", study.getStudyId(), participant.getParticipantId(), lastOccurredObservation, current);
76-
ctx.putParticipant(participant);
77-
//NOTE: from, to are currently not supported
78-
var timeline = calendarService.getTimeline(study, participant, null, null, null, null, null);
79-
for(ObservationTimelineEvent event : timeline.observationTimelineEvents()){
80-
var start = event.start().truncatedTo(ChronoUnit.MINUTES);
81-
if((lastOccurredObservation == null || start.isAfter(lastOccurredObservation)) && start.isBefore(current)){
82-
LOGGER.trace("upsert occurred observation for study: {}, observation: {}, participant: {}, start: {}, end: {}",
83-
study.getStudyId(), event.observationId(), participant.getParticipantId(), event.start(), event.end());
84-
occurredObservationService.upsert(study.getStudyId(), event.observationId(), participant.getParticipantId(), event.start(), event.end());
85-
} //else outside of time range ... ignore
86-
}
87-
});
72+
.filter(participant -> participant.getStatus() == Participant.Status.ACTIVE)
73+
.forEach(participant -> {
74+
Instant lastOccurredObservation = occurredObservationService.getLatestStartTime(study.getStudyId(), participant.getParticipantId());
75+
LOGGER.debug("Upsert Occurred Observations for Study(id: {}) Participant(id: {}) and timeperiode(start:{}, end:{})", study.getStudyId(), participant.getParticipantId(), lastOccurredObservation, current);
76+
ctx.putParticipant(participant);
77+
//NOTE: from, to are currently not supported
78+
var timeline = calendarService.getTimeline(study, participant, null, null, null, null, null);
79+
for (ObservationTimelineEvent event : timeline.observationTimelineEvents()) {
80+
var start = event.start().truncatedTo(ChronoUnit.MINUTES);
81+
if ((lastOccurredObservation == null || start.isAfter(lastOccurredObservation)) && start.isBefore(current)) {
82+
LOGGER.trace("upsert occurred observation for study: {}, observation: {}, participant: {}, start: {}, end: {}",
83+
study.getStudyId(), event.observationId(), participant.getParticipantId(), event.start(), event.end());
84+
occurredObservationService.upsert(study.getStudyId(), event.observationId(), participant.getParticipantId(), event.start(), event.end());
85+
} //else outside of time range ... ignore
86+
}
87+
});
8888
} catch (Exception e) {
8989
LOGGER.warn("Cannot execute Trigger-Job: {}", e.getMessage(), e);
9090
}

studymanager-services/src/main/java/io/redlink/more/studymanager/service/ElasticDataService.java

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import co.elastic.clients.elasticsearch.core.SearchRequest;
1616
import co.elastic.clients.elasticsearch.core.SearchResponse;
1717
import co.elastic.clients.util.ObjectBuilder;
18+
import io.redlink.more.studymanager.core.datavalidity.ArrayMeasurementSummary;
1819
import io.redlink.more.studymanager.core.datavalidity.BooleanFieldValue;
1920
import io.redlink.more.studymanager.core.datavalidity.BooleanMeasurementSummary;
2021
import io.redlink.more.studymanager.core.datavalidity.DateMeasurementSummary;
@@ -120,6 +121,7 @@ private SearchRequest.Builder buildMeasurementSetAggregations(SearchRequest.Buil
120121
Measurement.Type type = measurement.getType();
121122
switch (type) {
122123
case STRING:
124+
case ARRAY:
123125
String termsName = field + "_counts";
124126
builder.aggregations(termsName, Aggregation.of(a -> a.terms(t -> t.field(field + ".keyword").missing("missing"))));
125127
break;
@@ -129,13 +131,14 @@ private SearchRequest.Builder buildMeasurementSetAggregations(SearchRequest.Buil
129131
break;
130132
case INTEGER:
131133
case DOUBLE:
134+
case LONG:
132135
case DATE:
133136
String statsName = field + "_stats";
134137
builder.aggregations(statsName, Aggregation.of(a -> a.stats(s -> s.field(field))));
135138
String missingName = field + "_missing";
136139
builder.aggregations(missingName, Aggregation.of(a -> a.missing(m -> m.field(field))));
137140
break;
138-
case OBJECT:
141+
default:
139142
// do nothing
140143
break;
141144
}
@@ -222,6 +225,7 @@ private ObservationDataSummary parseValidationResults(MeasurementSet measurement
222225
break;
223226
case INTEGER:
224227
case DOUBLE:
228+
case LONG:
225229
String numericStatsName = field + "_stats";
226230
StatsAggregate numericStats = searchResponse.aggregations().get(numericStatsName).stats();
227231
String numericMissingName = field + "_missing";
@@ -245,7 +249,26 @@ private ObservationDataSummary parseValidationResults(MeasurementSet measurement
245249
long dateMissing = dateMiss.docCount();
246250
ms.setDateResult(new DateMeasurementSummary(dateMinInst, dateMaxInst, dateMissing));
247251
break;
248-
case OBJECT:
252+
case ARRAY:
253+
String arrayTermsName = field + "_counts";
254+
StringTermsAggregate arrayTerms = searchResponse.aggregations().get(arrayTermsName).sterms();
255+
256+
List<String> distinctValues = new ArrayList<>();
257+
long missingDocs = 0;
258+
for (StringTermsBucket bucket : arrayTerms.buckets().array()) {
259+
String key = bucket.key().stringValue();
260+
if ("missing".equals(key)) {
261+
missingDocs = bucket.docCount();
262+
} else {
263+
distinctValues.add(key);
264+
}
265+
}
266+
267+
long presentDocs = numDocs - missingDocs;
268+
FieldValue<List<String>> arrayValue = new FieldValue<>(distinctValues.isEmpty() ? null : distinctValues, presentDocs);
269+
ms.setArrayResult(new ArrayMeasurementSummary<>(arrayValue));
270+
break;
271+
default:
249272
// do nothing
250273
break;
251274
}

0 commit comments

Comments
 (0)