group results by a single field

This commit is contained in:
2016-12-14 19:36:38 +01:00
parent b25060a5d2
commit d4c694dea3
9 changed files with 242 additions and 35 deletions

View File

@@ -0,0 +1,23 @@
package org.lucares.performance.db;
import java.util.List;
class Group {
private final Tags tags;
private final List<PdbFile> files;
public Group(final Tags tags, final List<PdbFile> files) {
super();
this.tags = tags;
this.files = files;
}
public Tags getTags() {
return tags;
}
public List<PdbFile> getFiles() {
return files;
}
}

View File

@@ -15,6 +15,9 @@ public class GroupResult {
this.groupedBy = groupedBy;
}
/**
* @return {@link Stream} unbound, unordered and non-parallel
*/
public Stream<Entry> asStream() {
return entries;
}

View File

@@ -0,0 +1,59 @@
package org.lucares.performance.db;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Grouping {
public static final String NO_GROUPING = null;
private final List<Group> groups = new ArrayList<>();
private Grouping(final Group group) {
this.groups.add(group);
}
private Grouping(final Collection<Group> groups) {
this.groups.addAll(groups);
}
public static Grouping groupBy(final List<PdbFile> pdbFiles, final String groupByField) {
final Grouping result;
if (groupByField == NO_GROUPING) {
final Group group = new Group(null, pdbFiles);
result = new Grouping(group);
} else {
final Map<String, Group> grouping = new HashMap<>();
for (final PdbFile pdbFile : pdbFiles) {
final Tags tags = pdbFile.getTags();
final String value = tags.getValue(groupByField);
if (value != null) {
addIfNotExists(grouping, groupByField, value);
grouping.get(value).getFiles().add(pdbFile);
}
}
result = new Grouping(grouping.values());
}
return result;
}
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);
final List<PdbFile> files = new ArrayList<>();
grouping.put(value, new Group(tags, files));
}
}
public Collection<Group> getGroups() {
return groups;
}
}

View File

@@ -3,6 +3,7 @@ package org.lucares.performance.db;
import java.io.IOException;
import java.nio.file.Path;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
@@ -112,17 +113,43 @@ public class PerformanceDb implements AutoCloseable {
}
}
/**
*
* @param query
* @return
*/
public Result get(final String query) {
return get(query, Grouping.NO_GROUPING);
}
/**
* Return the entries as an unbound, ordered and non-parallel stream.
*
* @param query
* @return {@link Stream} unbound, ordered and non-parallel
* @param groupBy
* the tag to group by
* @return {@link Result}
*/
public Result get(final String query) {
public Result get(final String query, final String groupBy) {
final List<PdbFile> pdbFiles = tagsToFile.getFilesForQuery(query);
final Stream<Entry> stream = toStream(pdbFiles);
return new Result(new GroupResult(stream, Tags.EMPTY));
final Grouping grouping = Grouping.groupBy(pdbFiles, groupBy);
final Result result = toResult(grouping);
return result;
}
private Result toResult(final Grouping grouping) {
final List<GroupResult> groupResults = new ArrayList<>();
for (final Group group : grouping.getGroups()) {
final Stream<Entry> stream = toStream(group.getFiles());
final GroupResult groupResult = new GroupResult(stream, group.getTags());
groupResults.add(groupResult);
}
final Result result = new Result(groupResults);
return result;
}
private Stream<Entry> toStream(final List<PdbFile> pdbFiles) {

View File

@@ -5,12 +5,12 @@ final class Query {
final StringBuilder result = new StringBuilder();
for (final String key : tags.getKeys()) {
tags.getValue(key).ifPresent(value -> {
result.append(key);
result.append("=");
result.append(value);
result.append(" ");
});
final String value = tags.getValue(key);
result.append(key);
result.append("=");
result.append(value);
result.append(" ");
}
return result.toString().trim();

View File

@@ -1,6 +1,8 @@
package org.lucares.performance.db;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
public class Result {
@@ -8,7 +10,11 @@ public class Result {
private final List<GroupResult> groupResults;
public Result(final GroupResult... groupResults) {
this.groupResults = Arrays.asList(groupResults);
this(Arrays.asList(groupResults));
}
public Result(final Collection<GroupResult> groupResults) {
this.groupResults = new ArrayList<>(groupResults);
}
public GroupResult singleGroup() {
@@ -17,4 +23,8 @@ public class Result {
}
return groupResults.get(0);
}
public List<GroupResult> getGroups() {
return new ArrayList<>(groupResults);
}
}

View File

@@ -0,0 +1,57 @@
package org.lucares.performance.db;
public class Tag {
private final String key;
private final String value;
public Tag(final String key, final String value) {
this.key = key;
this.value = value;
}
public String getKey() {
return key;
}
public String getValue() {
return value;
}
@Override
public String toString() {
return key + "=" + value;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((key == null) ? 0 : key.hashCode());
result = prime * result + ((value == null) ? 0 : value.hashCode());
return result;
}
@Override
public boolean equals(final Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final Tag other = (Tag) obj;
if (key == null) {
if (other.key != null)
return false;
} else if (!key.equals(other.key))
return false;
if (value == null) {
if (other.value != null)
return false;
} else if (!value.equals(other.value))
return false;
return true;
}
}

View File

@@ -4,7 +4,6 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
@@ -13,14 +12,14 @@ import java.util.function.BiConsumer;
public class Tags {
static final Tags EMPTY = new Tags();
private final Map<String, String> tags;
private final Map<String, Tag> tags;
private Tags() {
super();
tags = Collections.emptyMap();
}
private Tags(final Map<String, String> tags) {
private Tags(final Map<String, Tag> tags) {
this.tags = tags;
ensureNoInternalFields();
}
@@ -38,15 +37,15 @@ public class Tags {
}
public static Tags create(final String key1, final String value1, final String key2, final String value2) {
final Map<String, String> tags = new HashMap<>(2);
tags.put(key1, value1);
tags.put(key2, value2);
final Map<String, Tag> tags = new HashMap<>(2);
tags.put(key1, new Tag(key1, value1));
tags.put(key2, new Tag(key2, value2));
return new Tags(tags);
}
public static Tags create(final String key1, final String value1) {
final Map<String, String> tags = new HashMap<>(1);
tags.put(key1, value1);
public static Tags create(final String key, final String value) {
final Map<String, Tag> tags = new HashMap<>(1);
tags.put(key, new Tag(key, value));
return new Tags(tags);
}
@@ -54,8 +53,9 @@ public class Tags {
Objects.requireNonNull(key, "key must not be null");
Objects.requireNonNull(value, "value must not be null");
final Map<String, String> newTags = new HashMap<>(tags);
newTags.put(key.intern(), value.intern());
final Map<String, Tag> newTags = new HashMap<>(tags);
newTags.put(key, new Tag(key, value));
return new Tags(newTags);
}
@@ -71,9 +71,10 @@ public class Tags {
return result;
}
public Optional<String> getValue(final String key) {
final String value = tags.get(key);
return Optional.ofNullable(value);
public String getValue(final String key) {
final Tag tag = tags.get(key);
final String value = tag != null ? tag.getValue() : null;
return value;
}
public Set<String> getKeys() {
@@ -81,8 +82,8 @@ public class Tags {
}
public void forEach(final BiConsumer<String, String> keyValueConsumer) {
for (final Map.Entry<String, String> e : tags.entrySet()) {
keyValueConsumer.accept(e.getKey(), e.getValue());
for (final Map.Entry<String, Tag> e : tags.entrySet()) {
keyValueConsumer.accept(e.getKey(), e.getValue().getValue());
}
}
@@ -126,9 +127,11 @@ public class Tags {
for (final String key : keys) {
final String value = tags.get(key).getValue();
result.append(substr(key, cutAt));
result.append("-");
result.append(substr(tags.get(key), cutAt));
result.append(substr(value, cutAt));
result.append("_");
}

View File

@@ -163,14 +163,39 @@ public class PerformanceDbTest {
final TimeRange timeRange = new TimeRange(from, to);
final long numberOfEntries = timeRange.duration().toHours();
final Tags tagsOne = Tags.create("myKey", "one", "commonKey", "commonValue");
final Tags tagsTwo = Tags.create("myKey", "two", "commonKey", "commonValue");
final Tags tagsThree = Tags.create("myKey", "three", "commonKey", "commonValue");
storeEntries(db, timeRange, numberOfEntries, tagsOne, 1);
storeEntries(db, timeRange, numberOfEntries, tagsTwo, 2);
storeEntries(db, timeRange, numberOfEntries, tagsThree, 3);
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 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 | groupBy myKey");
final Result result = db.get("commonKey=commonValue", 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);
switch (groupedByValue) {
case "one":
Assert.assertEquals(groupResult.asList(), entriesOne);
break;
case "two":
Assert.assertEquals(groupResult.asList(), entriesTwo);
break;
case "three":
Assert.assertEquals(groupResult.asList(), entriesThree);
break;
default:
break;
}
}
Assert.assertEquals(actualGroup, Arrays.asList("one", "two", "three"));
}
}