summaryrefslogtreecommitdiffstats
path: root/container-search
diff options
context:
space:
mode:
authorGeir Storli <geirst@oath.com>2018-09-07 11:53:25 +0000
committerGeir Storli <geirst@oath.com>2018-09-10 12:18:49 +0000
commit2b799d684ffc9129f51025d2b835e2b1f587a7b8 (patch)
tree256321ceb53cf44f4d33ca789c36ba321574c0f1 /container-search
parente3d76a10ea55c9e195bb19fd7c67a760b23a15c4 (diff)
Extend grouping parser to handle map syntax with indirect key via attribute vector.
Diffstat (limited to 'container-search')
-rw-r--r--container-search/src/main/java/com/yahoo/search/grouping/request/AttributeMapLookupValue.java57
-rw-r--r--container-search/src/main/java/com/yahoo/search/grouping/vespa/ExpressionConverter.java4
-rw-r--r--container-search/src/main/javacc/com/yahoo/search/grouping/request/parser/GroupingParser.jj27
-rw-r--r--container-search/src/test/java/com/yahoo/search/grouping/request/parser/GroupingParserTestCase.java47
4 files changed, 124 insertions, 11 deletions
diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/AttributeMapLookupValue.java b/container-search/src/main/java/com/yahoo/search/grouping/request/AttributeMapLookupValue.java
new file mode 100644
index 00000000000..fb9702cc1cc
--- /dev/null
+++ b/container-search/src/main/java/com/yahoo/search/grouping/request/AttributeMapLookupValue.java
@@ -0,0 +1,57 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.search.grouping.request;
+
+/**
+ * This class represents a lookup in a map attribute in a {@link GroupingExpression}.
+ *
+ * It evaluates to the value found using the given key for the lookup in that attribute.
+ * The key is either specified explicitly or found via a key source attribute.
+ *
+ * @author geirst
+ */
+public class AttributeMapLookupValue extends AttributeValue {
+
+ private final String prefix;
+ private final String suffix;
+ private final String key;
+ private final String keySourceAttribute;
+
+ private AttributeMapLookupValue(String attributeValue, String prefix, String suffix, String key, String keySourceAttribute) {
+ super(attributeValue);
+ this.prefix = prefix;
+ this.suffix = suffix;
+ this.key = key;
+ this.keySourceAttribute = keySourceAttribute;
+ }
+
+ public static AttributeMapLookupValue fromKey(String prefix, String key, String suffix) {
+ return new AttributeMapLookupValue(prefix + "{\"" + key + "\"}" + suffix,
+ prefix, suffix, key, "");
+ }
+
+ public static AttributeMapLookupValue fromKeySourceAttribute(String prefix, String keySourceAttribute, String suffix) {
+ return new AttributeMapLookupValue(prefix + "{attribute(" + keySourceAttribute + ")}" + suffix,
+ prefix, suffix, "", keySourceAttribute);
+ }
+
+ @Override
+ public AttributeMapLookupValue copy() {
+ return new AttributeMapLookupValue(getAttributeName(), prefix, suffix, key, keySourceAttribute);
+ }
+
+ public String getKeyAttribute() {
+ return prefix + ".key";
+ }
+
+ public String getValueAttribute() {
+ return prefix + ".value" + suffix;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public String getKeySourceAttribute() {
+ return keySourceAttribute;
+ }
+}
diff --git a/container-search/src/main/java/com/yahoo/search/grouping/vespa/ExpressionConverter.java b/container-search/src/main/java/com/yahoo/search/grouping/vespa/ExpressionConverter.java
index d2dfb3c0ee7..95384fb12d3 100644
--- a/container-search/src/main/java/com/yahoo/search/grouping/vespa/ExpressionConverter.java
+++ b/container-search/src/main/java/com/yahoo/search/grouping/vespa/ExpressionConverter.java
@@ -6,6 +6,7 @@ import com.yahoo.search.grouping.request.AggregatorNode;
import com.yahoo.search.grouping.request.AndFunction;
import com.yahoo.search.grouping.request.ArrayAtLookup;
import com.yahoo.search.grouping.request.AttributeFunction;
+import com.yahoo.search.grouping.request.AttributeMapLookupValue;
import com.yahoo.search.grouping.request.AttributeValue;
import com.yahoo.search.grouping.request.AvgAggregator;
import com.yahoo.search.grouping.request.BucketValue;
@@ -263,6 +264,9 @@ class ExpressionConverter {
if (exp instanceof AndFunction) {
return addArguments(new AndFunctionNode(), (AndFunction)exp);
}
+ if (exp instanceof AttributeMapLookupValue) {
+ return new AttributeNode(((AttributeMapLookupValue)exp).getAttributeName());
+ }
if (exp instanceof AttributeValue) {
return new AttributeNode(((AttributeValue)exp).getAttributeName());
}
diff --git a/container-search/src/main/javacc/com/yahoo/search/grouping/request/parser/GroupingParser.jj b/container-search/src/main/javacc/com/yahoo/search/grouping/request/parser/GroupingParser.jj
index 0678b030bc5..6a55a32eb8a 100644
--- a/container-search/src/main/javacc/com/yahoo/search/grouping/request/parser/GroupingParser.jj
+++ b/container-search/src/main/javacc/com/yahoo/search/grouping/request/parser/GroupingParser.jj
@@ -404,14 +404,31 @@ AndFunction andFunction(GroupingOperation grp) :
AttributeValue attributeValue() :
{
- StringBuilder ret = new StringBuilder();
+ StringBuilder prefix = new StringBuilder();
+ StringBuilder suffix = new StringBuilder();
String str;
+ String key = null;
+ AttributeFunction keySourceAttr = null;
}
{
- ( str = identifier() { ret.append(str); }
- ( ( <DOT> { ret.append(token.image); } ( str = identifier() { ret.append(str); } ) ) |
- ( lcurly() str = string() { ret.append("{\"").append(str).append("\"}"); } rcurly() ) )* )
- { return new AttributeValue(ret.toString()); }
+ ( str = identifier() { prefix.append(str); }
+ ( LOOKAHEAD(2) <DOT> { prefix.append(token.image); } ( str = identifier() { prefix.append(str); } ) )*
+ ( LOOKAHEAD(3)
+ ( lcurly() key = string() rcurly() ) |
+ ( lcurly() keySourceAttr = attributeFunction() rcurly() )
+ )?
+ ( <DOT> { suffix.append(token.image); } ( str = identifier() { suffix.append(str); } ) )*
+ )
+ {
+ if (key != null) {
+ return AttributeMapLookupValue.fromKey(prefix.toString(), key, suffix.toString());
+ } else if (keySourceAttr != null) {
+ return AttributeMapLookupValue.fromKeySourceAttribute(prefix.toString(), keySourceAttr.getAttributeName(), suffix.toString());
+ } else {
+ prefix.append(suffix.toString());
+ return new AttributeValue(prefix.toString());
+ }
+ }
}
AttributeFunction attributeFunction() :
diff --git a/container-search/src/test/java/com/yahoo/search/grouping/request/parser/GroupingParserTestCase.java b/container-search/src/test/java/com/yahoo/search/grouping/request/parser/GroupingParserTestCase.java
index 2c43873036e..afbad73f982 100644
--- a/container-search/src/test/java/com/yahoo/search/grouping/request/parser/GroupingParserTestCase.java
+++ b/container-search/src/test/java/com/yahoo/search/grouping/request/parser/GroupingParserTestCase.java
@@ -2,6 +2,7 @@
package com.yahoo.search.grouping.request.parser;
import com.yahoo.search.grouping.request.AllOperation;
+import com.yahoo.search.grouping.request.AttributeMapLookupValue;
import com.yahoo.search.grouping.request.EachOperation;
import com.yahoo.search.grouping.request.GroupingOperation;
import com.yahoo.search.query.parser.Parsable;
@@ -24,12 +25,6 @@ import static org.junit.Assert.fail;
*/
public class GroupingParserTestCase {
- // --------------------------------------------------------------------------------
- //
- // Tests.
- //
- // --------------------------------------------------------------------------------
-
@Test
public void requireThatMathAllowsWhitespace() {
for (String op : Arrays.asList("+", " +", " + ", "+ ",
@@ -448,6 +443,46 @@ public class GroupingParserTestCase {
assertParse("all(group(my.little{key }))", "all(group(my.little{\"key\"}))");
assertParse("all(group(my.little{\"key\"}))", "all(group(my.little{\"key\"}))");
assertParse("all(group(my.little{\"key{}%\"}))", "all(group(my.little{\"key{}%\"}))");
+ assertParse("all(group(my.little{key}.name))", "all(group(my.little{\"key\"}.name))");
+ assertParse("all(group(my.little{key }.name))", "all(group(my.little{\"key\"}.name))");
+ assertParse("all(group(my.little{\"key\"}.name))", "all(group(my.little{\"key\"}.name))");
+ assertParse("all(group(my.little{\"key{}%\"}.name))", "all(group(my.little{\"key{}%\"}.name))");
+
+ assertAttributeMapLookup("all(group(my_map{\"my_key\"}))",
+ "my_map.key", "my_map.value", "my_key", "");
+ assertAttributeMapLookup("all(group(my_map{\"my_key\"}.name))",
+ "my_map.key", "my_map.value.name", "my_key", "");
+ assertAttributeMapLookup("all(group(my.map{\"my_key\"}))",
+ "my.map.key", "my.map.value", "my_key", "");
+ }
+
+ @Test
+ public void testMapSyntaxWithKeySourceAttribute() {
+ assertAttributeMapLookup("all(group(my_map{attribute(my_attr)}))",
+ "my_map.key", "my_map.value", "", "my_attr");
+ assertAttributeMapLookup("all(group(my_map{attribute(my_attr)}.name))",
+ "my_map.key", "my_map.value.name", "", "my_attr");
+ assertAttributeMapLookup("all(group(my.map{attribute(my_attr.name)}))",
+ "my.map.key", "my.map.value", "", "my_attr.name");
+
+ assertIllegalArgument("all(group(my_map{attribute(\"my_attr\")}))",
+ "Encountered \" <STRING> \"\\\"my_attr\\\" \"\" at line 1, column 28");
+
+ }
+
+ private static void assertAttributeMapLookup(String request,
+ String expKeyAttribute,
+ String expValueAttribute,
+ String expKey,
+ String expKeySourceAttribute) {
+ assertParse(request, request);
+ List<GroupingOperation> operations = GroupingOperation.fromStringAsList(request);
+ assertEquals(1, operations.size());
+ AttributeMapLookupValue mapLookup = (AttributeMapLookupValue)operations.get(0).getGroupBy();
+ assertEquals(expKeyAttribute, mapLookup.getKeyAttribute());
+ assertEquals(expValueAttribute, mapLookup.getValueAttribute());
+ assertEquals(expKey, mapLookup.getKey());
+ assertEquals(expKeySourceAttribute, mapLookup.getKeySourceAttribute());
}
@Test