group by multiple fields

Before we could only group by a single field. But it is acutally
very useful to group by multiple fields. For example to see the
graph for a small set of methods grouped by host and project.
This commit is contained in:
2017-04-12 19:16:19 +02:00
parent 6cc6e679a4
commit 8baf05962f
9 changed files with 169 additions and 72 deletions

View File

@@ -2,6 +2,7 @@ package org.lucares.performance.db;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -10,8 +11,8 @@ import org.lucares.pdb.api.Tags;
public class Grouping {
public static final String NO_GROUPING = null;
public static final String DEFAULT_GROUP = "<none>";
public static final List<String> NO_GROUPING = Collections.emptyList();
private final List<Group> groups = new ArrayList<>();
private Grouping(final Group group) {
@@ -22,7 +23,7 @@ public class Grouping {
this.groups.addAll(groups);
}
public static Grouping groupBy(final List<PdbReader> pdbReaders, final String groupByField) {
public static Grouping groupBy(final List<PdbReader> pdbReaders, final List<String> groupByField) {
final Grouping result;
if (noGrouping(groupByField)) {
@@ -30,33 +31,29 @@ public class Grouping {
result = new Grouping(group);
} else {
final Map<String, Group> grouping = new HashMap<>();
final Map<Tags, Group> grouping = new HashMap<>();
for (final PdbReader pdbReader : pdbReaders) {
final Tags tags = pdbReader.getPdbFile().getTags();
final String value = tags.getValue(groupByField);
final Tags groupTags = tags.subset(groupByField);
final String groupName = value != null ? value : DEFAULT_GROUP;
addIfNotExists(grouping, groupByField, groupName);
grouping.get(groupName).addReader(pdbReader);
addIfNotExists(grouping, groupTags);
grouping.get(groupTags).addReader(pdbReader);
}
result = new Grouping(grouping.values());
}
return result;
}
private static boolean noGrouping(final String groupByField) {
return groupByField == NO_GROUPING || groupByField.isEmpty();
private static boolean noGrouping(final List<String> groupByField) {
return groupByField == null || groupByField.isEmpty();
}
private static void addIfNotExists(final Map<String, Group> grouping, final String groupByField,
final String value) {
if (!grouping.containsKey(value)) {
final Tags tags = Tags.create(groupByField, value);
private static void addIfNotExists(final Map<Tags, Group> grouping, final Tags groupTags) {
if (!grouping.containsKey(groupTags)) {
final List<PdbReader> readers = new ArrayList<>();
grouping.put(value, new Group(tags, readers));
grouping.put(groupTags, new Group(groupTags, readers));
}
}

View File

@@ -152,7 +152,7 @@ public class PerformanceDb implements AutoCloseable, CollectionUtils {
* the tag to group by
* @return {@link Result}
*/
public Result get(final String query, final String groupBy) {
public Result get(final String query, final List<String> groupBy) {
final List<PdbReader> pdbReaders = tagsToFile.getReaders(query);

View File

@@ -166,7 +166,7 @@ public class PerformanceDbTest {
}
}
public void testGroupBy() throws Exception {
public void testGroupBySingleField() throws Exception {
try (PerformanceDb db = new PerformanceDb(dataDirectory)) {
final OffsetDateTime from = DateUtils.getDate(2016, 1, 1, 00, 00, 00);
final OffsetDateTime to = DateUtils.getDate(2016, 1, 1, 23, 59, 50);
@@ -177,36 +177,77 @@ public class PerformanceDbTest {
final String key = "myKey";
final Tags tagsOne = Tags.create(key, "one", "commonKey", "commonValue");
final Tags tagsTwo = Tags.create(key, "two", "commonKey", "commonValue");
final Tags tagsThree = Tags.create(key, "three", "commonKey", "commonValue");
final Tags tagsThree = Tags.create("commonKey", "commonValue");
final List<Entry> entriesOne = storeEntries(db, timeRange, numberOfEntries, tagsOne, 1);
final List<Entry> entriesTwo = storeEntries(db, timeRange, numberOfEntries, tagsTwo, 2);
final List<Entry> entriesThree = storeEntries(db, timeRange, numberOfEntries, tagsThree, 3);
final Result result = db.get("commonKey=commonValue", key);
final Result result = db.get("commonKey=commonValue", Arrays.asList(key));
final List<GroupResult> groups = result.getGroups();
final List<String> actualGroup = new ArrayList<>();
for (final GroupResult groupResult : groups) {
final String groupedByValue = groupResult.getGroupedBy().getValue(key);
actualGroup.add(groupedByValue);
final Tags groupedBy = groupResult.getGroupedBy();
switch (groupedByValue) {
case "one":
if (groupedBy.equals(Tags.create(key, "one"))) {
Assert.assertEquals(groupResult.asList(), entriesOne);
break;
case "two":
Assert.assertEquals(groupResult.asList(), entriesTwo);
break;
case "three":
Assert.assertEquals(groupResult.asList(), entriesThree);
break;
} else if (groupedBy.equals(Tags.create(key, "two"))) {
default:
break;
Assert.assertEquals(groupResult.asList(), entriesTwo);
} else if (groupedBy.isEmpty()) {
Assert.assertEquals(groupResult.asList(), entriesThree);
} else {
Assert.fail("unexpected group: " + groupResult.getGroupedBy());
}
}
}
}
public void testGroupByMultipleFields() throws Exception {
try (PerformanceDb db = new PerformanceDb(dataDirectory)) {
final OffsetDateTime from = DateUtils.getDate(2016, 1, 1, 00, 00, 00);
final OffsetDateTime to = DateUtils.getDate(2016, 1, 1, 23, 59, 50);
final TimeRange timeRange = new TimeRange(from, to);
final long numberOfEntries = timeRange.duration().toHours();
final String key1 = "myKey1";
final String key2 = "myKey2";
final Tags tagsOne = Tags.create(key1, "one", key2, "aaa", "commonKey", "commonValue");
final Tags tagsTwoA = Tags.create(key1, "two", key2, "bbb", "commonKey", "commonValue");
final Tags tagsTwoB = Tags.create(key1, "two", key2, "bbb", "commonKey", "commonValue");
final Tags tagsThree = Tags.create(key1, "three", "commonKey", "commonValue");
final List<Entry> entriesOne = storeEntries(db, timeRange, numberOfEntries, tagsOne, 1);
final List<Entry> entriesTwo = storeEntries(db, timeRange, numberOfEntries, tagsTwoA, 2);
entriesTwo.addAll(storeEntries(db, timeRange, numberOfEntries, tagsTwoB, 3));
final List<Entry> entriesThree = storeEntries(db, timeRange, numberOfEntries, tagsThree, 4);
final Result result = db.get("commonKey=commonValue", Arrays.asList(key1, key2));
final List<GroupResult> groups = result.getGroups();
for (final GroupResult groupResult : groups) {
final Tags groupedBy = groupResult.getGroupedBy();
if (groupedBy.equals(Tags.create(key1, "one", key2, "aaa"))) {
Assert.assertEquals(groupResult.asList(), entriesOne);
} else if (groupedBy.equals(Tags.create(key1, "two", key2, "bbb"))) {
// there is no defined order of the entries.
// eventually we might return them in ascending order, but
// that is not yet implemented
final List<Entry> actualEntries = groupResult.asList();
entriesTwo.sort(EntryByDateComparator.INSTANCE);
actualEntries.sort(EntryByDateComparator.INSTANCE);
Assert.assertEquals(actualEntries, entriesTwo);
} else if (groupedBy.equals(Tags.create(key1, "three"))) {
Assert.assertEquals(groupResult.asList(), entriesThree);
} else {
Assert.fail("unexpected group: " + groupedBy);
}
}
Assert.assertEquals(actualGroup, Arrays.asList("one", "two", "three"));
}
}
@@ -225,8 +266,4 @@ public class PerformanceDbTest {
index++;
}
}
public void testBlockingIteratorInput() throws Exception {
}
}