summaryrefslogtreecommitdiffstats
path: root/container-search/src/main/java/com/yahoo/search/grouping/result
diff options
context:
space:
mode:
authorJon Bratseth <bratseth@yahoo-inc.com>2016-06-15 23:09:44 +0200
committerJon Bratseth <bratseth@yahoo-inc.com>2016-06-15 23:09:44 +0200
commit72231250ed81e10d66bfe70701e64fa5fe50f712 (patch)
tree2728bba1131a6f6e5bdf95afec7d7ff9358dac50 /container-search/src/main/java/com/yahoo/search/grouping/result
Publish
Diffstat (limited to 'container-search/src/main/java/com/yahoo/search/grouping/result')
-rw-r--r--container-search/src/main/java/com/yahoo/search/grouping/result/AbstractList.java47
-rw-r--r--container-search/src/main/java/com/yahoo/search/grouping/result/BucketGroupId.java60
-rw-r--r--container-search/src/main/java/com/yahoo/search/grouping/result/DoubleBucketId.java21
-rw-r--r--container-search/src/main/java/com/yahoo/search/grouping/result/DoubleId.java19
-rw-r--r--container-search/src/main/java/com/yahoo/search/grouping/result/Group.java83
-rw-r--r--container-search/src/main/java/com/yahoo/search/grouping/result/GroupId.java44
-rw-r--r--container-search/src/main/java/com/yahoo/search/grouping/result/GroupList.java24
-rw-r--r--container-search/src/main/java/com/yahoo/search/grouping/result/HitList.java25
-rw-r--r--container-search/src/main/java/com/yahoo/search/grouping/result/HitRenderer.java99
-rw-r--r--container-search/src/main/java/com/yahoo/search/grouping/result/LongBucketId.java21
-rw-r--r--container-search/src/main/java/com/yahoo/search/grouping/result/LongId.java19
-rw-r--r--container-search/src/main/java/com/yahoo/search/grouping/result/NullId.java19
-rw-r--r--container-search/src/main/java/com/yahoo/search/grouping/result/RawBucketId.java23
-rw-r--r--container-search/src/main/java/com/yahoo/search/grouping/result/RawId.java21
-rw-r--r--container-search/src/main/java/com/yahoo/search/grouping/result/RootGroup.java25
-rw-r--r--container-search/src/main/java/com/yahoo/search/grouping/result/RootId.java14
-rw-r--r--container-search/src/main/java/com/yahoo/search/grouping/result/StringBucketId.java21
-rw-r--r--container-search/src/main/java/com/yahoo/search/grouping/result/StringId.java19
-rw-r--r--container-search/src/main/java/com/yahoo/search/grouping/result/ValueGroupId.java45
-rw-r--r--container-search/src/main/java/com/yahoo/search/grouping/result/package-info.java7
20 files changed, 656 insertions, 0 deletions
diff --git a/container-search/src/main/java/com/yahoo/search/grouping/result/AbstractList.java b/container-search/src/main/java/com/yahoo/search/grouping/result/AbstractList.java
new file mode 100644
index 00000000000..058c68470c4
--- /dev/null
+++ b/container-search/src/main/java/com/yahoo/search/grouping/result/AbstractList.java
@@ -0,0 +1,47 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.search.grouping.result;
+
+import com.yahoo.collections.LazyMap;
+import com.yahoo.search.grouping.Continuation;
+import com.yahoo.search.result.HitGroup;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
+ */
+public abstract class AbstractList extends HitGroup {
+
+ private final Map<String, Continuation> continuations = LazyMap.newHashMap();
+ private final String label;
+
+ /**
+ * <p>Constructs a new instance of this class.</p>
+ *
+ * @param type The type of this list.
+ * @param label The label of this list.
+ */
+ public AbstractList(String type, String label) {
+ super(type + ":" + label);
+ this.label = label;
+ }
+
+ /**
+ * <p>Returns the label of this list.</p>
+ *
+ * @return The label.
+ */
+ public String getLabel() {
+ return label;
+ }
+
+ /**
+ * <p>Returns the map of all possible {@link Continuation}s of this list.</p>
+ *
+ * @return The list of Continuations.
+ */
+ public Map<String, Continuation> continuations() {
+ return continuations;
+ }
+}
diff --git a/container-search/src/main/java/com/yahoo/search/grouping/result/BucketGroupId.java b/container-search/src/main/java/com/yahoo/search/grouping/result/BucketGroupId.java
new file mode 100644
index 00000000000..1d6dcc6762c
--- /dev/null
+++ b/container-search/src/main/java/com/yahoo/search/grouping/result/BucketGroupId.java
@@ -0,0 +1,60 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.search.grouping.result;
+
+import static com.yahoo.text.Lowercase.toLowerCase;
+
+/**
+ * This abstract class is used in {@link Group} instances where the identifying expression evaluated to a {@link
+ * com.yahoo.search.grouping.request.BucketValue}. The range is inclusive-from and exclusive-to.
+ *
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
+ */
+public abstract class BucketGroupId<T> extends GroupId {
+
+ private final T from;
+ private final T to;
+
+ /**
+ * Constructs a new instance of this class.
+ *
+ * @param type The type of this id's value.
+ * @param from The inclusive-from of the range.
+ * @param to The exclusive-to of the range.
+ */
+ public BucketGroupId(String type, T from, T to) {
+ this(type, from, String.valueOf(from), to, String.valueOf(to));
+ }
+
+ /**
+ * Constructs a new instance of this class.
+ *
+ * @param type The type of this id's value.
+ * @param from The inclusive-from of the range.
+ * @param fromImage The String representation of the <tt>from</tt> argument.
+ * @param to The exclusive-to of the range.
+ * @param toImage The String representation of the <tt>to</tt> argument.
+ */
+ public BucketGroupId(String type, T from, String fromImage, T to, String toImage) {
+ super(type, fromImage, toImage);
+ this.from = from;
+ this.to = to;
+ }
+
+ /**
+ * Returns the inclusive-from of the value range.
+ *
+ * @return The from-value.
+ */
+ public T getFrom() {
+ return from;
+ }
+
+ /**
+ * Returns the exclusive-to of the value range.
+ *
+ * @return The to-value.
+ */
+ public T getTo() {
+ return to;
+ }
+}
diff --git a/container-search/src/main/java/com/yahoo/search/grouping/result/DoubleBucketId.java b/container-search/src/main/java/com/yahoo/search/grouping/result/DoubleBucketId.java
new file mode 100644
index 00000000000..e9f7ffc04c0
--- /dev/null
+++ b/container-search/src/main/java/com/yahoo/search/grouping/result/DoubleBucketId.java
@@ -0,0 +1,21 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.search.grouping.result;
+
+/**
+ * This class is used in {@link Group} instances where the identifying expression evaluated to a {@link
+ * com.yahoo.search.grouping.request.DoubleBucket}.
+ *
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
+ */
+public class DoubleBucketId extends BucketGroupId<Double> {
+
+ /**
+ * Constructs a new instance of this class.
+ *
+ * @param from The identifying inclusive-from double.
+ * @param to The identifying exclusive-to double.
+ */
+ public DoubleBucketId(Double from, Double to) {
+ super("double_bucket", from, to);
+ }
+}
diff --git a/container-search/src/main/java/com/yahoo/search/grouping/result/DoubleId.java b/container-search/src/main/java/com/yahoo/search/grouping/result/DoubleId.java
new file mode 100644
index 00000000000..c6f0b15feb2
--- /dev/null
+++ b/container-search/src/main/java/com/yahoo/search/grouping/result/DoubleId.java
@@ -0,0 +1,19 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.search.grouping.result;
+
+/**
+ * This class is used in {@link Group} instances where the identifying expression evaluated to a {@link Double}.
+ *
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
+ */
+public class DoubleId extends ValueGroupId<Double> {
+
+ /**
+ * Constructs a new instance of this class.
+ *
+ * @param value The identifying double.
+ */
+ public DoubleId(Double value) {
+ super("double", value);
+ }
+}
diff --git a/container-search/src/main/java/com/yahoo/search/grouping/result/Group.java b/container-search/src/main/java/com/yahoo/search/grouping/result/Group.java
new file mode 100644
index 00000000000..ddf8fe6140d
--- /dev/null
+++ b/container-search/src/main/java/com/yahoo/search/grouping/result/Group.java
@@ -0,0 +1,83 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.search.grouping.result;
+
+import com.yahoo.search.result.Hit;
+import com.yahoo.search.result.HitGroup;
+import com.yahoo.search.result.Relevance;
+
+/**
+ * This class represents a single group in the grouping result model. A group may contain any number of results (stored
+ * as fields, use {@link #getField(String)} to access), {@link GroupList} and {@link HitList}. Use the {@link
+ * com.yahoo.search.grouping.GroupingRequest#getResultGroup(com.yahoo.search.Result)} to retrieve an instance of this.
+ *
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
+ */
+public class Group extends HitGroup {
+
+ private static final long serialVersionUID = 2122928012157537800L;
+ private final GroupId groupId;
+
+ /**
+ * Creates a new instance of this class.
+ *
+ * @param groupId The id to assign to this group.
+ * @param rel The relevance of this group.
+ */
+ public Group(GroupId groupId, Relevance rel) {
+ super(groupId.toString(), rel);
+ this.groupId = groupId;
+ }
+
+ /**
+ * Returns the id of this group. This is a model of the otherwise flattened {@link #getId() hit id}.
+ *
+ * @return The group id.
+ */
+ public GroupId getGroupId() {
+ return groupId;
+ }
+
+ /**
+ * Returns the {@link HitList} with the given label. The label is the one given to the {@link
+ * com.yahoo.search.grouping.request.EachOperation} that generated the list. This method returns null if no such
+ * list was found.
+ *
+ * @param label The label of the list to return.
+ * @return The requested list, or null.
+ */
+ public HitList getHitList(String label) {
+ for (Hit hit : this) {
+ if (!(hit instanceof HitList)) {
+ continue;
+ }
+ HitList lst = (HitList)hit;
+ if (!label.equals(lst.getLabel())) {
+ continue;
+ }
+ return lst;
+ }
+ return null;
+ }
+
+ /**
+ * Returns the {@link GroupList} with the given label. The label is the one given to the {@link
+ * com.yahoo.search.grouping.request.EachOperation} that generated the list. This method returns null if no such
+ * list was found.
+ *
+ * @param label The label of the list to return.
+ * @return The requested list, or null.
+ */
+ public GroupList getGroupList(String label) {
+ for (Hit hit : this) {
+ if (!(hit instanceof GroupList)) {
+ continue;
+ }
+ GroupList lst = (GroupList)hit;
+ if (!label.equals(lst.getLabel())) {
+ continue;
+ }
+ return lst;
+ }
+ return null;
+ }
+}
diff --git a/container-search/src/main/java/com/yahoo/search/grouping/result/GroupId.java b/container-search/src/main/java/com/yahoo/search/grouping/result/GroupId.java
new file mode 100644
index 00000000000..a9f5102caea
--- /dev/null
+++ b/container-search/src/main/java/com/yahoo/search/grouping/result/GroupId.java
@@ -0,0 +1,44 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.search.grouping.result;
+
+/**
+ * This abstract class represents the id of a single group in the grouping result model. A subclass corresponding to the
+ * evaluation result of generating {@link com.yahoo.search.grouping.request.GroupingExpression} is contained in all
+ * {@link Group} objects. It is used by {@link com.yahoo.search.grouping.GroupingRequest} to identify its root result
+ * group, and by all client code for identifying groups.
+ * <p>
+ * The {@link #toString()} method of this class generates a URI-compatible string on the form
+ * "group:&lt;typeName&gt;:&lt;subclassSpecific&gt;".
+ *
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
+ */
+public abstract class GroupId {
+
+ private final String type;
+ private final String image;
+
+ protected GroupId(String type, Object... args) {
+ this.type = type;
+
+ StringBuilder image = new StringBuilder("group:");
+ image.append(type);
+ for (Object arg : args) {
+ image.append(":").append(arg);
+ }
+ this.image = image.toString();
+ }
+
+ /**
+ * Returns the type name of this group id. This is the second part of the {@link #toString()} value of this.
+ *
+ * @return The type name.
+ */
+ public String getTypeName() {
+ return type;
+ }
+
+ @Override
+ public String toString() {
+ return image;
+ }
+}
diff --git a/container-search/src/main/java/com/yahoo/search/grouping/result/GroupList.java b/container-search/src/main/java/com/yahoo/search/grouping/result/GroupList.java
new file mode 100644
index 00000000000..ee8d7c33fa7
--- /dev/null
+++ b/container-search/src/main/java/com/yahoo/search/grouping/result/GroupList.java
@@ -0,0 +1,24 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.search.grouping.result;
+
+import com.yahoo.search.Result;
+import com.yahoo.search.grouping.GroupingRequest;
+
+/**
+ * This class represents a labeled group list in the grouping result model. It is contained in {@link Group}, and
+ * contains one or more {@link Group groups} itself, allowing for a hierarchy of grouping results. Use the {@link
+ * GroupingRequest#getResultGroup(Result)} to retrieve grouping results.
+ *
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
+ */
+public class GroupList extends AbstractList {
+
+ /**
+ * Constructs a new instance of this class.
+ *
+ * @param label The label to assign to this.
+ */
+ public GroupList(String label) {
+ super("grouplist", label);
+ }
+}
diff --git a/container-search/src/main/java/com/yahoo/search/grouping/result/HitList.java b/container-search/src/main/java/com/yahoo/search/grouping/result/HitList.java
new file mode 100644
index 00000000000..abc87a92ab1
--- /dev/null
+++ b/container-search/src/main/java/com/yahoo/search/grouping/result/HitList.java
@@ -0,0 +1,25 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.search.grouping.result;
+
+import com.yahoo.search.Result;
+import com.yahoo.search.grouping.GroupingRequest;
+import com.yahoo.search.result.Hit;
+
+/**
+ * <p>This class represents a labeled hit list in the grouping result model. It is contained in {@link Group}, and
+ * contains one or more {@link Hit hits} itself, making this the parent of leaf nodes in the hierarchy of grouping
+ * results. Use the {@link GroupingRequest#getResultGroup(Result)} to retrieve grouping results.</p>
+ *
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
+ */
+public class HitList extends AbstractList {
+
+ /**
+ * <p>Constructs a new instance of this class.</p>
+ *
+ * @param label The label to assign to this.
+ */
+ public HitList(String label) {
+ super("hitlist", label);
+ }
+}
diff --git a/container-search/src/main/java/com/yahoo/search/grouping/result/HitRenderer.java b/container-search/src/main/java/com/yahoo/search/grouping/result/HitRenderer.java
new file mode 100644
index 00000000000..7558af5acb5
--- /dev/null
+++ b/container-search/src/main/java/com/yahoo/search/grouping/result/HitRenderer.java
@@ -0,0 +1,99 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.search.grouping.result;
+
+import com.yahoo.search.grouping.Continuation;
+import com.yahoo.search.result.HitGroup;
+import com.yahoo.text.Utf8String;
+import com.yahoo.text.XMLWriter;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Map;
+
+/**
+ * This is a helper class for rendering grouping results.
+ *
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
+ */
+public abstract class HitRenderer {
+
+ private static final Utf8String ATR_LABEL = new Utf8String("label");
+ private static final Utf8String ATR_RELEVANCE = new Utf8String("relevance");
+ private static final Utf8String ATR_TYPE = new Utf8String("type");
+ private static final Utf8String TAG_BUCKET_FROM = new Utf8String("from");
+ private static final Utf8String TAG_BUCKET_TO = new Utf8String("to");
+ private static final Utf8String TAG_CONTINUATION = new Utf8String("continuation");
+ private static final Utf8String TAG_CONTINUATION_ID = new Utf8String("id");
+ private static final Utf8String TAG_GROUP_LIST = new Utf8String("grouplist");
+ private static final Utf8String TAG_GROUP = new Utf8String("group");
+ private static final Utf8String TAG_GROUP_ID = new Utf8String("id");
+ private static final Utf8String TAG_HIT_LIST = new Utf8String("hitlist");
+ private static final Utf8String TAG_OUTPUT = new Utf8String("output");
+
+ /**
+ * Renders the header for the given grouping hit. If the hit is not a grouping hit, this method does nothing and
+ * returns false.
+ * <p>Post-condition if this is a grouping hit: The hit tag is open.
+ *
+ * @param hit The hit whose header to render.
+ * @param writer The writer to render to.
+ * @return True if the hit was rendered.
+ * @throws IOException Thrown if there was a problem writing.
+ */
+ public static boolean renderHeader(HitGroup hit, XMLWriter writer) throws IOException {
+ if (hit instanceof GroupList) {
+ writer.openTag(TAG_GROUP_LIST).attribute(ATR_LABEL, ((GroupList)hit).getLabel());
+ renderContinuations(((GroupList)hit).continuations(), writer);
+ } else if (hit instanceof Group) {
+ writer.openTag(TAG_GROUP).attribute(ATR_RELEVANCE, hit.getRelevance().toString());
+ renderGroupId(((Group)hit).getGroupId(), writer);
+ if (hit instanceof RootGroup) {
+ renderContinuation(Continuation.THIS_PAGE, ((RootGroup)hit).continuation(), writer);
+ }
+ for (String label : hit.fieldKeys()) {
+ writer.openTag(TAG_OUTPUT).attribute(ATR_LABEL, label).content(hit.getField(label), false).closeTag();
+ }
+ } else if (hit instanceof HitList) {
+ writer.openTag(TAG_HIT_LIST).attribute(ATR_LABEL, ((HitList)hit).getLabel());
+ renderContinuations(((HitList)hit).continuations(), writer);
+ } else {
+ return false;
+ }
+ writer.closeStartTag();
+ return true;
+ }
+
+ private static void renderGroupId(GroupId id, XMLWriter writer) {
+ writer.openTag(TAG_GROUP_ID).attribute(ATR_TYPE, id.getTypeName());
+ if (id instanceof ValueGroupId) {
+ writer.content(getIdValue((ValueGroupId)id), false);
+ } else if (id instanceof BucketGroupId) {
+ BucketGroupId bucketId = (BucketGroupId)id;
+ writer.openTag(TAG_BUCKET_FROM).content(getBucketFrom(bucketId), false).closeTag();
+ writer.openTag(TAG_BUCKET_TO).content(getBucketTo(bucketId), false).closeTag();
+ }
+ writer.closeTag();
+ }
+
+ private static Object getIdValue(ValueGroupId id) {
+ return id instanceof RawId ? Arrays.toString(((RawId)id).getValue()) : id.getValue();
+ }
+
+ private static Object getBucketFrom(BucketGroupId id) {
+ return id instanceof RawBucketId ? Arrays.toString(((RawBucketId)id).getFrom()) : id.getFrom();
+ }
+
+ private static Object getBucketTo(BucketGroupId id) {
+ return id instanceof RawBucketId ? Arrays.toString(((RawBucketId)id).getTo()) : id.getTo();
+ }
+
+ private static void renderContinuations(Map<String, Continuation> continuations, XMLWriter writer) {
+ for (Map.Entry<String, Continuation> entry : continuations.entrySet()) {
+ renderContinuation(entry.getKey(), entry.getValue(), writer);
+ }
+ }
+
+ private static void renderContinuation(String id, Continuation continuation, XMLWriter writer) {
+ writer.openTag(TAG_CONTINUATION).attribute(TAG_CONTINUATION_ID, id).content(continuation, false).closeTag();
+ }
+}
diff --git a/container-search/src/main/java/com/yahoo/search/grouping/result/LongBucketId.java b/container-search/src/main/java/com/yahoo/search/grouping/result/LongBucketId.java
new file mode 100644
index 00000000000..14ced353b67
--- /dev/null
+++ b/container-search/src/main/java/com/yahoo/search/grouping/result/LongBucketId.java
@@ -0,0 +1,21 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.search.grouping.result;
+
+/**
+ * This class is used in {@link Group} instances where the identifying expression evaluated to a {@link
+ * com.yahoo.search.grouping.request.LongBucket}.
+ *
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
+ */
+public class LongBucketId extends BucketGroupId<Long> {
+
+ /**
+ * Constructs a new instance of this class.
+ *
+ * @param from The identifying inclusive-from long.
+ * @param to The identifying exclusive-to long.
+ */
+ public LongBucketId(Long from, Long to) {
+ super("long_bucket", from, to);
+ }
+}
diff --git a/container-search/src/main/java/com/yahoo/search/grouping/result/LongId.java b/container-search/src/main/java/com/yahoo/search/grouping/result/LongId.java
new file mode 100644
index 00000000000..18d2098a5a1
--- /dev/null
+++ b/container-search/src/main/java/com/yahoo/search/grouping/result/LongId.java
@@ -0,0 +1,19 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.search.grouping.result;
+
+/**
+ * This class is used in {@link Group} instances where the identifying expression evaluated to a {@link Long}.
+ *
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
+ */
+public class LongId extends ValueGroupId<Long> {
+
+ /**
+ * Constructs a new instance of this class.
+ *
+ * @param value The identifying long.
+ */
+ public LongId(Long value) {
+ super("long", value);
+ }
+}
diff --git a/container-search/src/main/java/com/yahoo/search/grouping/result/NullId.java b/container-search/src/main/java/com/yahoo/search/grouping/result/NullId.java
new file mode 100644
index 00000000000..a6473837c76
--- /dev/null
+++ b/container-search/src/main/java/com/yahoo/search/grouping/result/NullId.java
@@ -0,0 +1,19 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.search.grouping.result;
+
+/**
+ * This class is in {@link Group} instances where the identifying expression evaluated to null. For example, hits that
+ * fall outside the buckets of a {@link com.yahoo.search.grouping.request.PredefinedFunction} are added to an
+ * auto-generated group with this id.
+ *
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
+ */
+public class NullId extends GroupId {
+
+ /**
+ * Constructs a new instance of this class.
+ */
+ public NullId() {
+ super("null");
+ }
+}
diff --git a/container-search/src/main/java/com/yahoo/search/grouping/result/RawBucketId.java b/container-search/src/main/java/com/yahoo/search/grouping/result/RawBucketId.java
new file mode 100644
index 00000000000..bb0dae9d6b8
--- /dev/null
+++ b/container-search/src/main/java/com/yahoo/search/grouping/result/RawBucketId.java
@@ -0,0 +1,23 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.search.grouping.result;
+
+import java.util.Arrays;
+
+/**
+ * This class is used in {@link Group} instances where the identifying
+ * expression evaluated to a {@link com.yahoo.search.grouping.request.RawBucket}.
+ *
+ * @author <a href="mailto:lulf@yahoo-inc.com">Ulf Lilleengen</a>
+ */
+public class RawBucketId extends BucketGroupId<byte[]> {
+
+ /**
+ * Constructs a new instance of this class.
+ *
+ * @param from The identifying inclusive-from raw buffer.
+ * @param to The identifying exclusive-to raw buffer.
+ */
+ public RawBucketId(byte[] from, byte[] to) {
+ super("raw_bucket", from, Arrays.toString(from), to, Arrays.toString(to));
+ }
+}
diff --git a/container-search/src/main/java/com/yahoo/search/grouping/result/RawId.java b/container-search/src/main/java/com/yahoo/search/grouping/result/RawId.java
new file mode 100644
index 00000000000..48e9c6e4523
--- /dev/null
+++ b/container-search/src/main/java/com/yahoo/search/grouping/result/RawId.java
@@ -0,0 +1,21 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.search.grouping.result;
+
+import java.util.Arrays;
+
+/**
+ * This class is used in {@link Group} instances where the identifying expression evaluated to a {@link Byte} array.
+ *
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
+ */
+public class RawId extends ValueGroupId<byte[]> {
+
+ /**
+ * Constructs a new instance of this class.
+ *
+ * @param value The identifying byte array.
+ */
+ public RawId(byte[] value) {
+ super("raw", value, Arrays.toString(value));
+ }
+}
diff --git a/container-search/src/main/java/com/yahoo/search/grouping/result/RootGroup.java b/container-search/src/main/java/com/yahoo/search/grouping/result/RootGroup.java
new file mode 100644
index 00000000000..238f9ec68f3
--- /dev/null
+++ b/container-search/src/main/java/com/yahoo/search/grouping/result/RootGroup.java
@@ -0,0 +1,25 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.search.grouping.result;
+
+import com.yahoo.search.grouping.Continuation;
+import com.yahoo.search.result.Relevance;
+
+/**
+ * This class represents the root {@link Group} in the grouping result model. This class adds a {@link Continuation}
+ * object that can be used to paginate the result.
+ *
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
+ */
+public class RootGroup extends Group {
+
+ private final Continuation continuation;
+
+ public RootGroup(int id, Continuation continuation) {
+ super(new RootId(id), new Relevance(1.0));
+ this.continuation = continuation;
+ }
+
+ public Continuation continuation() {
+ return continuation;
+ }
+}
diff --git a/container-search/src/main/java/com/yahoo/search/grouping/result/RootId.java b/container-search/src/main/java/com/yahoo/search/grouping/result/RootId.java
new file mode 100644
index 00000000000..ebf3152646a
--- /dev/null
+++ b/container-search/src/main/java/com/yahoo/search/grouping/result/RootId.java
@@ -0,0 +1,14 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.search.grouping.result;
+
+/**
+ * This class is used in {@link RootGroup} instances.
+ *
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
+ */
+public class RootId extends GroupId {
+
+ public RootId(int id) {
+ super("root", id);
+ }
+}
diff --git a/container-search/src/main/java/com/yahoo/search/grouping/result/StringBucketId.java b/container-search/src/main/java/com/yahoo/search/grouping/result/StringBucketId.java
new file mode 100644
index 00000000000..0b4459aa4b6
--- /dev/null
+++ b/container-search/src/main/java/com/yahoo/search/grouping/result/StringBucketId.java
@@ -0,0 +1,21 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.search.grouping.result;
+
+/**
+ * This class is used in {@link Group} instances where the identifying expression evaluated to a {@link
+ * com.yahoo.search.grouping.request.StringBucket}.
+ *
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
+ */
+public class StringBucketId extends BucketGroupId<String> {
+
+ /**
+ * Constructs a new instance of this class.
+ *
+ * @param from The identifying inclusive-from string.
+ * @param to The identifying exclusive-to string.
+ */
+ public StringBucketId(String from, String to) {
+ super("string_bucket", from, to);
+ }
+}
diff --git a/container-search/src/main/java/com/yahoo/search/grouping/result/StringId.java b/container-search/src/main/java/com/yahoo/search/grouping/result/StringId.java
new file mode 100644
index 00000000000..0a82b98af44
--- /dev/null
+++ b/container-search/src/main/java/com/yahoo/search/grouping/result/StringId.java
@@ -0,0 +1,19 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.search.grouping.result;
+
+/**
+ * This class is used in {@link Group} instances where the identifying expression evaluated to a {@link String}.
+ *
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
+ */
+public class StringId extends ValueGroupId<String> {
+
+ /**
+ * Constructs a new instance of this class.
+ *
+ * @param value The identifying string.
+ */
+ public StringId(String value) {
+ super("string", value);
+ }
+}
diff --git a/container-search/src/main/java/com/yahoo/search/grouping/result/ValueGroupId.java b/container-search/src/main/java/com/yahoo/search/grouping/result/ValueGroupId.java
new file mode 100644
index 00000000000..f6e815b231c
--- /dev/null
+++ b/container-search/src/main/java/com/yahoo/search/grouping/result/ValueGroupId.java
@@ -0,0 +1,45 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.search.grouping.result;
+
+import static com.yahoo.text.Lowercase.toLowerCase;
+
+/**
+ * This abstract class is used in {@link Group} instances where the identifying expression evaluated to a singe value.
+ *
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
+ */
+public abstract class ValueGroupId<T> extends GroupId {
+
+ private final T value;
+
+ /**
+ * Constructs a new instance of this class.
+ *
+ * @param type The type of this id's value.
+ * @param value The identifying value.
+ */
+ public ValueGroupId(String type, T value) {
+ this(type, value, String.valueOf(value.toString()));
+ }
+
+ /**
+ * Constructs a new instance of this class.
+ *
+ * @param type The type of this id's value.
+ * @param value The identifying value.
+ * @param valueImage The String representation of the <tt>value</tt> argument.
+ */
+ public ValueGroupId(String type, T value, String valueImage) {
+ super(type, valueImage);
+ this.value = value;
+ }
+
+ /**
+ * Returns the identifying value.
+ *
+ * @return The value.
+ */
+ public T getValue() {
+ return value;
+ }
+}
diff --git a/container-search/src/main/java/com/yahoo/search/grouping/result/package-info.java b/container-search/src/main/java/com/yahoo/search/grouping/result/package-info.java
new file mode 100644
index 00000000000..6c70f67971d
--- /dev/null
+++ b/container-search/src/main/java/com/yahoo/search/grouping/result/package-info.java
@@ -0,0 +1,7 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+@ExportPackage
+@PublicApi
+package com.yahoo.search.grouping.result;
+
+import com.yahoo.api.annotations.PublicApi;
+import com.yahoo.osgi.annotation.ExportPackage;