summaryrefslogtreecommitdiffstats
path: root/container-search
diff options
context:
space:
mode:
authorJon Bratseth <bratseth@verizonmedia.com>2019-11-07 13:03:01 +0100
committerJon Bratseth <bratseth@verizonmedia.com>2019-11-07 13:03:01 +0100
commit86c9c6916ca63c44534be8a9ae7f11bd14566712 (patch)
tree946e848adada9cb7f75823f09e73ee58346c7ea5 /container-search
parentac9ae3c5cff5012350e389ce8024c0b137ca0ec5 (diff)
YQL parsing/serialization improvements
- Serialize annotated range and weightedset with bracing - Parse Infinity in ranges - Better error messages in range parsing
Diffstat (limited to 'container-search')
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/SelectParser.java5
-rw-r--r--container-search/src/main/java/com/yahoo/search/yql/VespaSerializer.java31
-rw-r--r--container-search/src/main/java/com/yahoo/search/yql/YqlParser.java47
-rw-r--r--container-search/src/test/java/com/yahoo/search/yql/VespaSerializerTestCase.java8
-rw-r--r--container-search/src/test/java/com/yahoo/search/yql/YqlParserTestCase.java26
-rw-r--r--container-search/src/test/java/com/yahoo/select/SelectTestCase.java4
6 files changed, 90 insertions, 31 deletions
diff --git a/container-search/src/main/java/com/yahoo/search/query/SelectParser.java b/container-search/src/main/java/com/yahoo/search/query/SelectParser.java
index 83e6e122a8a..c654edda6f5 100644
--- a/container-search/src/main/java/com/yahoo/search/query/SelectParser.java
+++ b/container-search/src/main/java/com/yahoo/search/query/SelectParser.java
@@ -546,7 +546,7 @@ public class SelectParser implements Parser {
String[] operators = {null, null};
boundInspector.traverse((ObjectTraverser) (operator, bound) -> {
if (bound.type() == STRING) {
- throw new IllegalArgumentException("Expected operator LITERAL, got READ_FIELD.");
+ throw new IllegalArgumentException("Expected a numeric argument to range, but got the string '" + bound.asString() + "'");
}
if (operator.equals("=")) {
bounds[0] = (bound.type() == DOUBLE) ? Number.class.cast(bound.asDouble()) : Number.class.cast(bound.asLong());
@@ -676,7 +676,8 @@ public class SelectParser implements Parser {
//{"a":1, "b":2}
children.get(1).traverse((ObjectTraverser) (key, value) -> {
if (value.type() == STRING){
- throw new IllegalArgumentException("Expected operator LITERAL, got READ_FIELD.");
+ throw new IllegalArgumentException("Expected an integer argument, but got the string '" +
+ value.asString() + "'");
}
out.addToken(key, (int)value.asLong());
});
diff --git a/container-search/src/main/java/com/yahoo/search/yql/VespaSerializer.java b/container-search/src/main/java/com/yahoo/search/yql/VespaSerializer.java
index 4f7ab227113..5565c680efb 100644
--- a/container-search/src/main/java/com/yahoo/search/yql/VespaSerializer.java
+++ b/container-search/src/main/java/com/yahoo/search/yql/VespaSerializer.java
@@ -101,6 +101,7 @@ import com.yahoo.prelude.query.WordItem;
import com.yahoo.search.Query;
import com.yahoo.search.grouping.Continuation;
import com.yahoo.search.grouping.GroupingRequest;
+import com.yahoo.search.query.QueryTree;
/**
* Serialize Vespa query trees to YQL+ strings.
@@ -404,7 +405,7 @@ public class VespaSerializer {
boundsAnnotation = "\"" + BOUNDS + "\": " + "\"" + BOUNDS_RIGHT_OPEN + "\"";
}
if (annotations.length() > 0 || boundsAnnotation.length() > 0) {
- destination.append("[{");
+ destination.append("([{");
}
initLen = destination.length();
if (annotations.length() > 0) {
@@ -422,6 +423,9 @@ public class VespaSerializer {
.append(", ").append(intItem.getFromLimit().number())
.append(", ").append(intItem.getToLimit().number())
.append(")");
+ if (annotations.length() > 0 || boundsAnnotation.length() > 0) {
+ destination.append(")");
+ }
}
private void annotatedNumberImage(IntItem item, String rawNumber, StringBuilder image) {
@@ -1251,6 +1255,12 @@ public class VespaSerializer {
ToolBox.visit(visitor, item);
}
+ static String serialize(QueryTree item) {
+ StringBuilder out = new StringBuilder();
+ serialize(item.getRoot(), out);
+ return out.toString();
+ }
+
static String serialize(Item item) {
StringBuilder out = new StringBuilder();
serialize(item, out);
@@ -1264,10 +1274,10 @@ public class VespaSerializer {
private static void serializeWeightedSetContents(StringBuilder destination, String opName,
WeightedSetItem weightedSet, String optionalAnnotations) {
- addAnnotations(destination, weightedSet, optionalAnnotations);
+ boolean addedAnnotations = addAnnotations(destination, weightedSet, optionalAnnotations);
destination.append(opName).append('(')
- .append(normalizeIndexName(weightedSet.getIndexName()))
- .append(", {");
+ .append(normalizeIndexName(weightedSet.getIndexName()))
+ .append(", {");
int initLen = destination.length();
List<Entry<Object, Integer>> tokens = new ArrayList<>(weightedSet.getNumTokens());
for (Iterator<Entry<Object, Integer>> i = weightedSet.getTokens(); i.hasNext();) {
@@ -1281,16 +1291,19 @@ public class VespaSerializer {
destination.append("\": ").append(entry.getValue().toString());
}
destination.append("})");
+ if (addedAnnotations)
+ destination.append(")");
}
- private static void addAnnotations(StringBuilder destination, WeightedSetItem weightedSet,
- String optionalAnnotations) {
+ /** Adds annotations and returns whether any were added */
+ private static boolean addAnnotations(StringBuilder destination, WeightedSetItem weightedSet,
+ String optionalAnnotations) {
int preAnnotationValueLen;
int incomingLen = destination.length();
String annotations = leafAnnotations(weightedSet);
if (optionalAnnotations.length() > 0 || annotations.length() > 0) {
- destination.append("[{");
+ destination.append("([{");
}
preAnnotationValueLen = destination.length();
if (annotations.length() > 0) {
@@ -1302,6 +1315,10 @@ public class VespaSerializer {
}
if (destination.length() > incomingLen) {
destination.append("}]");
+ return true;
+ }
+ else {
+ return false;
}
}
diff --git a/container-search/src/main/java/com/yahoo/search/yql/YqlParser.java b/container-search/src/main/java/com/yahoo/search/yql/YqlParser.java
index dfc603846fd..306ac4e42f2 100644
--- a/container-search/src/main/java/com/yahoo/search/yql/YqlParser.java
+++ b/container-search/src/main/java/com/yahoo/search/yql/YqlParser.java
@@ -13,6 +13,7 @@ import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.StringTokenizer;
+import java.util.function.Supplier;
import com.google.common.annotations.Beta;
import com.google.common.base.Preconditions;
@@ -1087,8 +1088,8 @@ public class YqlParser implements Parser {
Preconditions.checkArgument(args.size() == 3,
"Expected 3 arguments, got %s.", args.size());
- Number lowerArg = getBound(args.get(1));
- Number upperArg = getBound(args.get(2));
+ Number lowerArg = getRangeBound(args.get(1));
+ Number upperArg = getRangeBound(args.get(2));
String bounds = getAnnotation(spec, BOUNDS, String.class, null,
"whether bounds should be open or closed");
// TODO: add support for implicit transforms
@@ -1113,20 +1114,26 @@ public class YqlParser implements Parser {
}
}
- private Number getBound(OperatorNode<ExpressionOperator> bound) {
- Number boundValue;
- OperatorNode<ExpressionOperator> currentBound = bound;
- boolean negate = false;
- if (currentBound.getOperator() == ExpressionOperator.NEGATE) {
- currentBound = currentBound.getArgument(0);
- negate = true;
- }
- assertHasOperator(currentBound, ExpressionOperator.LITERAL);
- boundValue = currentBound.getArgument(0, Number.class);
- if (negate) {
- boundValue = negate(boundValue);
+ private Number getRangeBound(OperatorNode<ExpressionOperator> bound) {
+ if (bound.getOperator() == ExpressionOperator.NEGATE)
+ return negate(getPositiveRangeBound(bound.getArgument(0)));
+ else
+ return getPositiveRangeBound(bound);
+ }
+
+ private Number getPositiveRangeBound(OperatorNode<ExpressionOperator> bound) {
+ if (bound.getOperator() == ExpressionOperator.READ_FIELD) {
+ // Why getArgument(1)? Because all of this is [mildly non-perfect] and we need to port it to JavaCC
+ if (bound.getArgument(1).toString().equals("Infinity"))
+ return Double.POSITIVE_INFINITY;
+ else
+ throw new IllegalArgumentException("Expected a numerical argument (or 'Infinity') to range but got '" +
+ bound.getArgument(1) + "'");
}
- return boundValue;
+
+ assertHasOperator(bound, ExpressionOperator.LITERAL,
+ () -> "Expected a numerical argument to range but got '" + bound.getArgument(0) + "'");
+ return bound.getArgument(0, Number.class);
}
private Item instantiateLeafItem(String field, OperatorNode<ExpressionOperator> ast) {
@@ -1506,6 +1513,16 @@ public class YqlParser implements Parser {
expectedOperator, ast.getOperator());
}
+ private static void assertHasOperator(OperatorNode<?> ast, Operator expectedOperator, Supplier<String> errorMessage) {
+ try {
+ Preconditions.checkArgument(ast.getOperator() == expectedOperator);
+ }
+ catch (IllegalArgumentException e) {
+ throw new IllegalArgumentException(errorMessage.get());
+ }
+
+ }
+
private static void assertHasFunctionName(OperatorNode<?> ast, String expectedFunctionName) {
List<String> names = ast.getArgument(0);
Preconditions.checkArgument(expectedFunctionName.equals(names.get(0)),
diff --git a/container-search/src/test/java/com/yahoo/search/yql/VespaSerializerTestCase.java b/container-search/src/test/java/com/yahoo/search/yql/VespaSerializerTestCase.java
index faf254577ce..0bbcabe4107 100644
--- a/container-search/src/test/java/com/yahoo/search/yql/VespaSerializerTestCase.java
+++ b/container-search/src/test/java/com/yahoo/search/yql/VespaSerializerTestCase.java
@@ -391,10 +391,10 @@ public class VespaSerializerTestCase {
@Test
public void testOpenIntervals() {
parseAndConfirm("range(title, 0.0, 500.0)");
- parseAndConfirm("[{\"bounds\": \"open\"}]range(title, 0.0, 500.0)");
- parseAndConfirm("[{\"bounds\": \"leftOpen\"}]range(title, 0.0, 500.0)");
- parseAndConfirm("[{\"bounds\": \"rightOpen\"}]range(title, 0.0, 500.0)");
- parseAndConfirm("[{\"id\": 500, \"bounds\": \"rightOpen\"}]range(title, 0.0, 500.0)");
+ parseAndConfirm("([{\"bounds\": \"open\"}]range(title, 0.0, 500.0))");
+ parseAndConfirm("([{\"bounds\": \"leftOpen\"}]range(title, 0.0, 500.0))");
+ parseAndConfirm("([{\"bounds\": \"rightOpen\"}]range(title, 0.0, 500.0))");
+ parseAndConfirm("([{\"id\": 500, \"bounds\": \"rightOpen\"}]range(title, 0.0, 500.0))");
}
@Test
diff --git a/container-search/src/test/java/com/yahoo/search/yql/YqlParserTestCase.java b/container-search/src/test/java/com/yahoo/search/yql/YqlParserTestCase.java
index 1d25c2301e2..8f717e74ab2 100644
--- a/container-search/src/test/java/com/yahoo/search/yql/YqlParserTestCase.java
+++ b/container-search/src/test/java/com/yahoo/search/yql/YqlParserTestCase.java
@@ -129,6 +129,18 @@ public class YqlParserTestCase {
}
@Test
+ public void testComplexExpression() {
+ String queryTreeYql = "rank((((filter contains ([{\"origin\": {\"original\": \"filter:VideoAdsCappingTestCPM\", \"offset\": 7, \"length\": 22}, \"normalizeCase\": false, \"id\": 1}]\"videoadscappingtestcpm\") AND hasRankRestriction contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 2}]\"0\") AND ((objective contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 3}]\"install_app\") AND availableExtendedFields contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 4}]\"cpiparams\")) OR (availableExtendedFields contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 5}]\"appinstallinfo\") AND availableExtendedFields contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 6}]\"appmetroplexinfo\")) OR (dummyField contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 7}]\"default\")) AND !(objective contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 8}]\"install_app\"))) AND advt_age = ([{\"id\": 9}]2147483647) AND advt_gender contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 10}]\"all\") AND advt_all_segments = ([{\"id\": 11}]2147483647) AND advt_keywords contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 12}]\"all\") AND advMobilePlatform = ([{\"id\": 13}]2147483647) AND advMobileDeviceType = ([{\"id\": 14}]2147483647) AND advMobileCon = ([{\"id\": 15}]2147483647) AND advMobileOSVersions = ([{\"id\": 16}]2147483647) AND advCarrier = ([{\"id\": 17}]2147483647) AND ([{\"id\": 18}]weightedSet(advt_supply, {\"all\": 1, \"pub223\": 1, \"sec223\": 1, \"site223\": 1})) AND (advt_day_parting contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 19, \"weight\": 1}]\"adv_tuesday\") OR advt_day_parting contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 20, \"weight\": 1}]\"adv_tuesday_17\") OR advt_day_parting contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 21, \"weight\": 1}]\"adv_tuesday_17_forty_five\") OR advt_day_parting contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 22}]\"all\")) AND isAppReengagementAd = ([{\"id\": 23}]0) AND dummyField contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 24}]\"default\") AND serveWithPromotionOnly = ([{\"id\": 26}]0) AND budgetAdvertiserThrottleRateFilter = ([{\"id\": 27}]0) AND budgetResellerThrottleRateFilter = ([{\"id\": 28}]0) AND (isMystiqueRequired = ([{\"id\": 29}]0) OR (isMystiqueRequired = ([{\"id\": 30}]1) AND useBcFactorFilter = ([{\"id\": 31}]1))) AND (((budgetCampaignThrottleRateBits = ([{\"id\": 32}]55) AND dummyField contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 33}]\"default\"))) AND !(useBcFactorFilter = ([{\"id\": 34}]1)) OR ((useBcFactorFilter = ([{\"id\": 35}]1) AND dummyField contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 36}]\"default\") AND (bcFactorTiers = ([{\"id\": 38}]127) OR bcFactorTiers = ([{\"id\": 39}]0)) AND ((firstPriceEnforced = ([{\"id\": 40}]0) AND (secondPriceEnforced = ([{\"id\": 41}]1) OR isPrivateDeal = ([{\"id\": 42}]0) OR (dummyField contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 43}]\"default\")) AND !(bcActiveTier = ([{\"id\": 44}]0)))) OR mystiqueCampaignThrottleRateBits = ([{\"id\": 45}]18)))) AND !(isOutOfDailyBudget = ([{\"id\": 37}]1))) AND testCreative = ([{\"id\": 46}]0) AND advt_geo = ([{\"id\": 47}]2147483647) AND ((adType contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 48}]\"strm_video\") AND isPortraitVideo = ([{\"id\": 49}]0)) OR adType contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 50}]\"stream_ad\")) AND ((isCPM = ([{\"id\": 51}]0) AND isOCPC = ([{\"id\": 52}]0) AND isECPC = ([{\"id\": 53}]0) AND ((priceType contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 54}]\"cpcv\") AND bid >= ([{\"id\": 55}]0.005)) OR (priceType contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 56}]\"cpv\") AND bid >= ([{\"id\": 57}]0.01)) OR (priceType contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 58}]\"cpc\") AND bid >= ([{\"id\": 59}]0.05)) OR (objective contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 60}]\"promote_content\") AND bid >= ([{\"id\": 61}]0.01)) OR hasFloorPriceUsd = ([{\"id\": 62}]1))) OR isECPC = ([{\"id\": 63}]1) OR (isCPM = ([{\"id\": 64}]1) AND isOCPM = ([{\"id\": 65}]0) AND (([{\"id\": 66}]range(bid, 0.25, Infinity)) OR hasFloorPriceUsd = ([{\"id\": 67}]1)))) AND start_date <= ([{\"id\": 68}]1572976776299L) AND end_date >= ([{\"id\": 69}]1572976776299L))) AND !(isHoldoutAd = ([{\"id\": 25}]1))) AND !((disclaimerExtensionsTypes contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 70}]\"pharma\") OR ([{\"id\": 71}]weightedSet(exclusion_advt_supply, {\"extsite223\": 1, \"pub223\": 1, \"sec223\": 1, \"site223\": 1})) OR isPersonalized = ([{\"id\": 72}]1) OR blacklist_section_ids contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 73}]\"223\") OR blacklist_publisher_ids contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 74}]\"223\") OR blacklist_site_ids contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 75}]\"223\"))), [{\"id\": 76, \"label\": \"ad_ocpc_max_cpc\"}]dotProduct(ocpc_max_cpc, {\"0\": 1}), [{\"id\": 77, \"label\": \"ad_ocpc_min_cpc\"}]dotProduct(ocpc_min_cpc, {\"0\": 1}), [{\"id\": 78, \"label\": \"ad_ocpc_max_alpha\"}]dotProduct(ocpc_max_alpha, {\"0\": 1}), [{\"id\": 79, \"label\": \"ad_ocpc_min_alpha\"}]dotProduct(ocpc_min_alpha, {\"0\": 1}), [{\"id\": 80, \"label\": \"ad_ocpc_alpha_0\"}]dotProduct(ocpc_alpha_0, {\"0\": 1}), [{\"id\": 81, \"label\": \"ad_ocpc_alpha_1\"}]dotProduct(ocpc_alpha_1, {\"0\": 1}), (bidAdjustmentDayParting contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 82, \"weight\": 1}]\"adv_tuesday\") OR bidAdjustmentDayParting contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 83, \"weight\": 1}]\"adv_tuesday_17\") OR bidAdjustmentDayParting contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 84, \"weight\": 1}]\"adv_tuesday_17_forty_five\") OR bidAdjustmentDayPartingForCostCap contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 85, \"weight\": 1}]\"adv_tuesday\") OR bidAdjustmentDayPartingForCostCap contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 86, \"weight\": 1}]\"adv_tuesday_17\") OR bidAdjustmentDayPartingForCostCap contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 87, \"weight\": 1}]\"adv_tuesday_17_forty_five\")), bidAdjustmentForCpi = ([{\"id\": 88, \"weight\": 1}]223), [{\"id\": 89, \"label\": \"boostingForBackfill\"}]dotProduct(boostingForBackfill, {\"priority\": 1000})) limit 0 timeout 3980 | all(group(adTypeForGrouping) each(group(advertiser_id) max(11) output(count() as(groupingCounter)) each(max(1) each(output(summary())))))";
+ QueryTree parsed = assertParse("select * from sources * where " + queryTreeYql + ";",
+ "RANK (+(+(AND filter:VideoAdsCappingTestCPM hasRankRestriction:0 (OR (AND objective:install_app availableExtendedFields:cpiparams) (AND availableExtendedFields:appinstallinfo availableExtendedFields:appmetroplexinfo) (+dummyField:default -objective:install_app)) advt_age:2147483647 advt_gender:all advt_all_segments:2147483647 advt_keywords:all advMobilePlatform:2147483647 advMobileDeviceType:2147483647 advMobileCon:2147483647 advMobileOSVersions:2147483647 advCarrier:2147483647 WEIGHTEDSET advt_supply{[1]:\"site223\",[1]:\"pub223\",[1]:\"all\",[1]:\"sec223\"} (OR advt_day_parting:adv_tuesday!1 advt_day_parting:adv_tuesday_17!1 advt_day_parting:adv_tuesday_17_forty_five!1 advt_day_parting:all) isAppReengagementAd:0 dummyField:default serveWithPromotionOnly:0 budgetAdvertiserThrottleRateFilter:0 budgetResellerThrottleRateFilter:0 (OR isMystiqueRequired:0 (AND isMystiqueRequired:1 useBcFactorFilter:1)) (OR (+(AND budgetCampaignThrottleRateBits:55 dummyField:default) -useBcFactorFilter:1) (+(AND useBcFactorFilter:1 dummyField:default (OR bcFactorTiers:127 bcFactorTiers:0) (OR (AND firstPriceEnforced:0 (OR secondPriceEnforced:1 isPrivateDeal:0 (+dummyField:default -bcActiveTier:0))) mystiqueCampaignThrottleRateBits:18)) -isOutOfDailyBudget:1)) testCreative:0 advt_geo:2147483647 (OR (AND adType:strm_video isPortraitVideo:0) adType:stream_ad) (OR (AND isCPM:0 isOCPC:0 isECPC:0 (OR (AND priceType:cpcv bid:[0.005;]) (AND priceType:cpv bid:[0.01;]) (AND priceType:cpc bid:[0.05;]) (AND objective:promote_content bid:[0.01;]) hasFloorPriceUsd:1)) isECPC:1 (AND isCPM:1 isOCPM:0 (OR bid:[0.25;] hasFloorPriceUsd:1))) start_date:[;1572976776299] end_date:[1572976776299;]) -isHoldoutAd:1) -(OR disclaimerExtensionsTypes:pharma WEIGHTEDSET exclusion_advt_supply{[1]:\"extsite223\",[1]:\"site223\",[1]:\"pub223\",[1]:\"sec223\"} isPersonalized:1 blacklist_section_ids:223 blacklist_publisher_ids:223 blacklist_site_ids:223)) DOTPRODUCT ocpc_max_cpc{[1]:\"0\"} DOTPRODUCT ocpc_min_cpc{[1]:\"0\"} DOTPRODUCT ocpc_max_alpha{[1]:\"0\"} DOTPRODUCT ocpc_min_alpha{[1]:\"0\"} DOTPRODUCT ocpc_alpha_0{[1]:\"0\"} DOTPRODUCT ocpc_alpha_1{[1]:\"0\"} (OR bidAdjustmentDayParting:adv_tuesday!1 bidAdjustmentDayParting:adv_tuesday_17!1 bidAdjustmentDayParting:adv_tuesday_17_forty_five!1 bidAdjustmentDayPartingForCostCap:adv_tuesday!1 bidAdjustmentDayPartingForCostCap:adv_tuesday_17!1 bidAdjustmentDayPartingForCostCap:adv_tuesday_17_forty_five!1) bidAdjustmentForCpi:223!1 DOTPRODUCT boostingForBackfill{[1000]:\"priority\"}");
+ String serializedQueryTreeYql = VespaSerializer.serialize(parsed);
+
+ // Note: All the details here are not verified
+ assertEquals("rank((((filter contains ([{\"normalizeCase\": false, \"id\": 1}]\"VideoAdsCappingTestCPM\") AND hasRankRestriction contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 2}]\"0\") AND ((objective contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 3}]\"install_app\") AND availableExtendedFields contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 4}]\"cpiparams\")) OR (availableExtendedFields contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 5}]\"appinstallinfo\") AND availableExtendedFields contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 6}]\"appmetroplexinfo\")) OR (dummyField contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 7}]\"default\")) AND !(objective contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 8}]\"install_app\"))) AND advt_age = ([{\"id\": 9}]2147483647) AND advt_gender contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 10}]\"all\") AND advt_all_segments = ([{\"id\": 11}]2147483647) AND advt_keywords contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 12}]\"all\") AND advMobilePlatform = ([{\"id\": 13}]2147483647) AND advMobileDeviceType = ([{\"id\": 14}]2147483647) AND advMobileCon = ([{\"id\": 15}]2147483647) AND advMobileOSVersions = ([{\"id\": 16}]2147483647) AND advCarrier = ([{\"id\": 17}]2147483647) AND ([{\"id\": 18}]weightedSet(advt_supply, {\"all\": 1, \"pub223\": 1, \"sec223\": 1, \"site223\": 1})) AND (advt_day_parting contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 19, \"weight\": 1}]\"adv_tuesday\") OR advt_day_parting contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 20, \"weight\": 1}]\"adv_tuesday_17\") OR advt_day_parting contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 21, \"weight\": 1}]\"adv_tuesday_17_forty_five\") OR advt_day_parting contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 22}]\"all\")) AND isAppReengagementAd = ([{\"id\": 23}]0) AND dummyField contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 24}]\"default\") AND serveWithPromotionOnly = ([{\"id\": 26}]0) AND budgetAdvertiserThrottleRateFilter = ([{\"id\": 27}]0) AND budgetResellerThrottleRateFilter = ([{\"id\": 28}]0) AND (isMystiqueRequired = ([{\"id\": 29}]0) OR (isMystiqueRequired = ([{\"id\": 30}]1) AND useBcFactorFilter = ([{\"id\": 31}]1))) AND (((budgetCampaignThrottleRateBits = ([{\"id\": 32}]55) AND dummyField contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 33}]\"default\"))) AND !(useBcFactorFilter = ([{\"id\": 34}]1)) OR ((useBcFactorFilter = ([{\"id\": 35}]1) AND dummyField contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 36}]\"default\") AND (bcFactorTiers = ([{\"id\": 38}]127) OR bcFactorTiers = ([{\"id\": 39}]0)) AND ((firstPriceEnforced = ([{\"id\": 40}]0) AND (secondPriceEnforced = ([{\"id\": 41}]1) OR isPrivateDeal = ([{\"id\": 42}]0) OR (dummyField contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 43}]\"default\")) AND !(bcActiveTier = ([{\"id\": 44}]0)))) OR mystiqueCampaignThrottleRateBits = ([{\"id\": 45}]18)))) AND !(isOutOfDailyBudget = ([{\"id\": 37}]1))) AND testCreative = ([{\"id\": 46}]0) AND advt_geo = ([{\"id\": 47}]2147483647) AND ((adType contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 48}]\"strm_video\") AND isPortraitVideo = ([{\"id\": 49}]0)) OR adType contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 50}]\"stream_ad\")) AND ((isCPM = ([{\"id\": 51}]0) AND isOCPC = ([{\"id\": 52}]0) AND isECPC = ([{\"id\": 53}]0) AND ((priceType contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 54}]\"cpcv\") AND bid >= ([{\"id\": 55}]0.005)) OR (priceType contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 56}]\"cpv\") AND bid >= ([{\"id\": 57}]0.01)) OR (priceType contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 58}]\"cpc\") AND bid >= ([{\"id\": 59}]0.05)) OR (objective contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 60}]\"promote_content\") AND bid >= ([{\"id\": 61}]0.01)) OR hasFloorPriceUsd = ([{\"id\": 62}]1))) OR isECPC = ([{\"id\": 63}]1) OR (isCPM = ([{\"id\": 64}]1) AND isOCPM = ([{\"id\": 65}]0) AND ([{\"id\": 66}]range(bid, 0.25, Infinity) OR hasFloorPriceUsd = ([{\"id\": 67}]1)))) AND start_date <= ([{\"id\": 68}]1572976776299L) AND end_date >= ([{\"id\": 69}]1572976776299L))) AND !(isHoldoutAd = ([{\"id\": 25}]1))) AND !((disclaimerExtensionsTypes contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 70}]\"pharma\") OR ([{\"id\": 71}]weightedSet(exclusion_advt_supply, {\"extsite223\": 1, \"pub223\": 1, \"sec223\": 1, \"site223\": 1})) OR isPersonalized = ([{\"id\": 72}]1) OR blacklist_section_ids contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 73}]\"223\") OR blacklist_publisher_ids contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 74}]\"223\") OR blacklist_site_ids contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 75}]\"223\"))), ([{\"id\": 76, \"label\": \"ad_ocpc_max_cpc\"}]dotProduct(ocpc_max_cpc, {\"0\": 1})), ([{\"id\": 77, \"label\": \"ad_ocpc_min_cpc\"}]dotProduct(ocpc_min_cpc, {\"0\": 1})), ([{\"id\": 78, \"label\": \"ad_ocpc_max_alpha\"}]dotProduct(ocpc_max_alpha, {\"0\": 1})), ([{\"id\": 79, \"label\": \"ad_ocpc_min_alpha\"}]dotProduct(ocpc_min_alpha, {\"0\": 1})), ([{\"id\": 80, \"label\": \"ad_ocpc_alpha_0\"}]dotProduct(ocpc_alpha_0, {\"0\": 1})), ([{\"id\": 81, \"label\": \"ad_ocpc_alpha_1\"}]dotProduct(ocpc_alpha_1, {\"0\": 1})), (bidAdjustmentDayParting contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 82, \"weight\": 1}]\"adv_tuesday\") OR bidAdjustmentDayParting contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 83, \"weight\": 1}]\"adv_tuesday_17\") OR bidAdjustmentDayParting contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 84, \"weight\": 1}]\"adv_tuesday_17_forty_five\") OR bidAdjustmentDayPartingForCostCap contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 85, \"weight\": 1}]\"adv_tuesday\") OR bidAdjustmentDayPartingForCostCap contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 86, \"weight\": 1}]\"adv_tuesday_17\") OR bidAdjustmentDayPartingForCostCap contains ([{\"normalizeCase\": false, \"implicitTransforms\": false, \"id\": 87, \"weight\": 1}]\"adv_tuesday_17_forty_five\")), bidAdjustmentForCpi = ([{\"id\": 88, \"weight\": 1}]223), ([{\"id\": 89, \"label\": \"boostingForBackfill\"}]dotProduct(boostingForBackfill, {\"priority\": 1000})))",
+ serializedQueryTreeYql);
+ }
+
+ @Test
public void testDottedFieldNames() {
assertParse("select foo from bar where my.nested.title contains \"madonna\";",
"my.nested.title:madonna");
@@ -457,6 +469,18 @@ public class YqlParserTestCase {
}
@Test
+ public void testRangeWithEndInfinity() {
+ QueryTree parsed = parse("select foo from bar where range(baz,1,Infinity);");
+ assertEquals("baz:[1;]", parsed.toString());
+ }
+
+ @Test
+ public void testRangeWithStartInfinity() {
+ QueryTree parsed = parse("select foo from bar where range(baz,-Infinity,8);");
+ assertEquals("baz:[;8]", parsed.toString());
+ }
+
+ @Test
public void testNegativeRange() {
QueryTree parsed = parse("select foo from bar where range(baz,-8,-1);");
assertEquals("baz:[-8;-1]", parsed.toString());
@@ -465,7 +489,7 @@ public class YqlParserTestCase {
@Test
public void testRangeIllegalArguments() {
assertParseFail("select foo from bar where range(baz,cox,8);",
- new IllegalArgumentException("Expected operator LITERAL, got READ_FIELD."));
+ new IllegalArgumentException("Expected a numerical argument (or 'Infinity') to range but got 'cox'"));
}
@Test
diff --git a/container-search/src/test/java/com/yahoo/select/SelectTestCase.java b/container-search/src/test/java/com/yahoo/select/SelectTestCase.java
index fa78fb75c57..261069ea1c3 100644
--- a/container-search/src/test/java/com/yahoo/select/SelectTestCase.java
+++ b/container-search/src/test/java/com/yahoo/select/SelectTestCase.java
@@ -450,7 +450,7 @@ public class SelectTestCase {
@Test
public void testRangeIllegalArguments() {
assertParseFail("{ \"range\": [\"baz\", { \">=\": \"cox\", \"<=\": -1 }] }",
- new IllegalArgumentException("Expected operator LITERAL, got READ_FIELD."));
+ new IllegalArgumentException("Expected a numeric argument to range, but got the string 'cox'"));
}
@Test
@@ -490,7 +490,7 @@ public class SelectTestCase {
assertParse("{ \"weightedSet\" : [\"description\", {\"a\":1, \"b\":2} ]}",
"WEIGHTEDSET description{[1]:\"a\",[2]:\"b\"}");
assertParseFail("{ \"weightedSet\" : [\"description\", {\"a\":\"g\", \"b\":2} ]}",
- new IllegalArgumentException("Expected operator LITERAL, got READ_FIELD."));
+ new IllegalArgumentException("Expected an integer argument, but got the string 'g'"));
assertParseFail("{ \"weightedSet\" : [\"description\" ]}",
new IllegalArgumentException("Expected 2 arguments, got 1."));
}