summaryrefslogtreecommitdiffstats
path: root/container-search/src/test/java/com/yahoo/search/yql/VespaSerializerTestCase.java
diff options
context:
space:
mode:
Diffstat (limited to 'container-search/src/test/java/com/yahoo/search/yql/VespaSerializerTestCase.java')
-rw-r--r--container-search/src/test/java/com/yahoo/search/yql/VespaSerializerTestCase.java404
1 files changed, 404 insertions, 0 deletions
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
new file mode 100644
index 00000000000..d9d8eb1b14b
--- /dev/null
+++ b/container-search/src/test/java/com/yahoo/search/yql/VespaSerializerTestCase.java
@@ -0,0 +1,404 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.search.yql;
+
+import static org.junit.Assert.*;
+
+import com.yahoo.search.Query;
+import com.yahoo.search.grouping.Continuation;
+import com.yahoo.search.grouping.GroupingRequest;
+import com.yahoo.search.grouping.request.AllOperation;
+import com.yahoo.search.grouping.request.AttributeFunction;
+import com.yahoo.search.grouping.request.CountAggregator;
+import com.yahoo.search.grouping.request.EachOperation;
+import com.yahoo.search.grouping.request.GroupingOperation;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.yahoo.prelude.query.AndSegmentItem;
+import com.yahoo.prelude.query.Item;
+import com.yahoo.prelude.query.MarkerWordItem;
+import com.yahoo.prelude.query.NotItem;
+import com.yahoo.prelude.query.PhraseSegmentItem;
+import com.yahoo.prelude.query.WordItem;
+import com.yahoo.search.query.QueryTree;
+import com.yahoo.search.query.parser.Parsable;
+import com.yahoo.search.query.parser.ParserEnvironment;
+
+import java.util.Arrays;
+
+public class VespaSerializerTestCase {
+
+ private static final String SELECT = "select ignoredfield from sourceA where ";
+ private YqlParser parser;
+
+ @Before
+ public void setUp() throws Exception {
+ ParserEnvironment env = new ParserEnvironment();
+ parser = new YqlParser(env);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ parser = null;
+ }
+
+ @Test
+ public void requireThatGroupingRequestsAreSerialized() {
+ Query query = new Query();
+ query.getModel().getQueryTree().setRoot(new WordItem("foo"));
+ assertEquals("default contains ([{\"implicitTransforms\": false}]\"foo\")",
+ VespaSerializer.serialize(query));
+
+ newGroupingRequest(query, new AllOperation().setGroupBy(new AttributeFunction("a"))
+ .addChild(new EachOperation().addOutput(new CountAggregator())));
+ assertEquals("default contains ([{\"implicitTransforms\": false}]\"foo\") " +
+ "| all(group(attribute(a)) each(output(count())))",
+ VespaSerializer.serialize(query));
+
+ newGroupingRequest(query, new AllOperation().setGroupBy(new AttributeFunction("b"))
+ .addChild(new EachOperation().addOutput(new CountAggregator())));
+ assertEquals("default contains ([{\"implicitTransforms\": false}]\"foo\") " +
+ "| all(group(attribute(a)) each(output(count()))) " +
+ "| all(group(attribute(b)) each(output(count())))",
+ VespaSerializer.serialize(query));
+ }
+
+ @Test
+ public void requireThatGroupingContinuationsAreSerialized() {
+ Query query = new Query();
+ query.getModel().getQueryTree().setRoot(new WordItem("foo"));
+ assertEquals("default contains ([{\"implicitTransforms\": false}]\"foo\")",
+ VespaSerializer.serialize(query));
+
+ newGroupingRequest(query, new AllOperation().setGroupBy(new AttributeFunction("a"))
+ .addChild(new EachOperation().addOutput(new CountAggregator())),
+ Continuation.fromString("BCBCBCBEBG"),
+ Continuation.fromString("BCBKCBACBKCCK"));
+ assertEquals("default contains ([{\"implicitTransforms\": false}]\"foo\") " +
+ "| [{ 'continuations':['BCBCBCBEBG', 'BCBKCBACBKCCK'] }]" +
+ "all(group(attribute(a)) each(output(count())))",
+ VespaSerializer.serialize(query));
+
+ newGroupingRequest(query, new AllOperation().setGroupBy(new AttributeFunction("b"))
+ .addChild(new EachOperation().addOutput(new CountAggregator())),
+ Continuation.fromString("BCBBBBBDBF"),
+ Continuation.fromString("BCBJBPCBJCCJ"));
+ assertEquals("default contains ([{\"implicitTransforms\": false}]\"foo\") " +
+ "| [{ 'continuations':['BCBCBCBEBG', 'BCBKCBACBKCCK'] }]" +
+ "all(group(attribute(a)) each(output(count()))) " +
+ "| [{ 'continuations':['BCBBBBBDBF', 'BCBJBPCBJCCJ'] }]" +
+ "all(group(attribute(b)) each(output(count())))",
+ VespaSerializer.serialize(query));
+ }
+
+ @Test
+ public final void testAnd() {
+ parseAndConfirm("(description contains \"a\" AND title contains \"that\")");
+ }
+
+ private void parseAndConfirm(String expected) {
+ parseAndConfirm(expected, expected);
+ }
+
+ private void parseAndConfirm(String expected, String toParse) {
+ QueryTree item = parser
+ .parse(new Parsable()
+ .setQuery(SELECT + toParse + ";"));
+ // System.out.println(item.toString());
+ String q = VespaSerializer.serialize(item.getRoot());
+ assertEquals(expected, q);
+ }
+
+ @Test
+ public final void testAndNot() {
+ parseAndConfirm("(description contains \"a\") AND !(title contains \"that\")");
+ }
+
+ @Test
+ public final void testEquiv() {
+ parseAndConfirm("title contains equiv(\"a\", \"b\")");
+ }
+
+ @Test
+ public final void testNear() {
+ parseAndConfirm("title contains near(\"a\", \"b\")");
+ parseAndConfirm("title contains ([{\"distance\": 50}]near(\"a\", \"b\"))");
+ }
+
+ @Test
+ public final void testNumbers() {
+ parseAndConfirm("title = 500");
+ parseAndConfirm("title > 500");
+ parseAndConfirm("title < 500");
+ }
+
+ @Test
+ public final void testAnnotatedNumbers() {
+ parseAndConfirm("title = ([{\"filter\": true}]500)");
+ parseAndConfirm("title > ([{\"filter\": true}]500)");
+ parseAndConfirm("title < ([{\"filter\": true}](-500))");
+ parseAndConfirm("title <= ([{\"filter\": true}](-500))", "([{\"filter\": true}](-500)) >= title");
+ parseAndConfirm("title <= ([{\"filter\": true}](-500))");
+ }
+
+ @Test
+ public final void testRange() {
+ parseAndConfirm("range(title, 1, 500)");
+ }
+
+ @Test
+ public final void testAnnotatedRange() {
+ parseAndConfirm("[{\"filter\": true}]range(title, 1, 500)");
+ }
+
+ @Test
+ public final void testOrderedNear() {
+ parseAndConfirm("title contains onear(\"a\", \"b\")");
+ }
+
+ @Test
+ public final void testOr() {
+ parseAndConfirm("(description contains \"a\" OR title contains \"that\")");
+ }
+
+ @Test
+ public final void testDotProduct() {
+ parseAndConfirm("dotProduct(description, {\"a\": 1, \"b\": 2})");
+ }
+
+ @Test
+ public final void testPredicate() {
+ parseAndConfirm("predicate(boolean,{\"gender\":\"male\"},{\"age\":25L})");
+ parseAndConfirm("predicate(boolean,{\"gender\":\"male\",\"hobby\":\"music\",\"hobby\":\"hiking\"}," +
+ "{\"age\":25L})",
+ "predicate(boolean,{\"gender\":\"male\",\"hobby\":[\"music\",\"hiking\"]},{\"age\":25})");
+ parseAndConfirm("predicate(boolean,{\"0x3\":{\"gender\":\"male\"},\"0x1\":{\"hobby\":\"music\"},\"0x1\":{\"hobby\":\"hiking\"}},{\"0x80ffffffffffffff\":{\"age\":23L}})",
+ "predicate(boolean,{\"0x3\":{\"gender\":\"male\"},\"0x1\":{\"hobby\":[\"music\",\"hiking\"]}},{\"0x80ffffffffffffff\":{\"age\":23L}})");
+ parseAndConfirm("predicate(boolean,0,0)");
+ parseAndConfirm("predicate(boolean,0,0)","predicate(boolean,null,void)");
+ parseAndConfirm("predicate(boolean,0,0)","predicate(boolean,{},{})");
+ }
+
+ @Test
+ public final void testPhrase() {
+ parseAndConfirm("description contains phrase(\"a\", \"b\")");
+ }
+
+ @Test
+ public final void testAnnotatedPhrase() {
+ parseAndConfirm("description contains ([{\"id\": 1}]phrase(\"a\", \"b\"))");
+ }
+
+ @Test
+ public final void testAnnotatedNear() {
+ parseAndConfirm("description contains ([{\"distance\": 37}]near(\"a\", \"b\"))");
+ }
+
+ @Test
+ public final void testAnnotatedOnear() {
+ parseAndConfirm("description contains ([{\"distance\": 37}]onear(\"a\", \"b\"))");
+ }
+
+ @Test
+ public final void testAnnotatedEquiv() {
+ parseAndConfirm("description contains ([{\"id\": 1}]equiv(\"a\", \"b\"))");
+ }
+
+ @Test
+ public final void testAnnotatedPhraseSegment() {
+ PhraseSegmentItem phraseSegment = new PhraseSegmentItem("abc", true, false);
+ phraseSegment.addItem(new WordItem("a", "indexNamePlaceholder"));
+ phraseSegment.addItem(new WordItem("b", "indexNamePlaceholder"));
+ phraseSegment.setIndexName("someIndexName");
+ phraseSegment.setLabel("labeled");
+ phraseSegment.lock();
+ String q = VespaSerializer.serialize(phraseSegment);
+ assertEquals("someIndexName contains ([{\"origin\": {\"original\": \"abc\", \"offset\": 0, \"length\": 3}, \"label\": \"labeled\"}]phrase(\"a\", \"b\"))", q);
+ }
+
+ @Test
+ public final void testAnnotatedAndSegment() {
+ AndSegmentItem andSegment = new AndSegmentItem("abc", true, false);
+ andSegment.addItem(new WordItem("a", "indexNamePlaceholder"));
+ andSegment.addItem(new WordItem("b", "indexNamePlaceholder"));
+ andSegment.setLabel("labeled");
+ andSegment.lock();
+ String q = VespaSerializer.serialize(andSegment);
+ assertEquals("indexNamePlaceholder contains ([{\"origin\": {\"original\": \"abc\", \"offset\": 0, \"length\": 3}, \"andSegmenting\": true}]phrase(\"a\", \"b\"))", q);
+ }
+
+ @Test
+ public final void testPhraseWithAnnotations() {
+ parseAndConfirm("description contains phrase(([{\"id\": 15}]\"a\"), \"b\")");
+ }
+
+ @Test
+ public final void testPhraseSegmentInPhrase() {
+ parseAndConfirm("description contains phrase(\"a\", \"b\", ([{\"origin\": {\"original\": \"c d\", \"offset\": 0, \"length\": 3}}]phrase(\"c\", \"d\")))");
+ }
+
+ @Test
+ public final void testRank() {
+ parseAndConfirm("rank(a contains \"A\", b contains \"B\")");
+ }
+
+ @Test
+ public final void testWand() {
+ parseAndConfirm("wand(description, {\"a\": 1, \"b\": 2})");
+ }
+
+ @Test
+ public final void testWeakAnd() {
+ parseAndConfirm("weakAnd(a contains \"A\", b contains \"B\")");
+ }
+
+ @Test
+ public final void testAnnotatedWeakAnd() {
+ parseAndConfirm("([{\"" + YqlParser.TARGET_NUM_HITS + "\": 10}]weakAnd(a contains \"A\", b contains \"B\"))");
+ parseAndConfirm("([{\"" + YqlParser.SCORE_THRESHOLD + "\": 10}]weakAnd(a contains \"A\", b contains \"B\"))");
+ parseAndConfirm("([{\"" + YqlParser.TARGET_NUM_HITS + "\": 10, \"" + YqlParser.SCORE_THRESHOLD
+ + "\": 20}]weakAnd(a contains \"A\", b contains \"B\"))");
+ }
+
+ @Test
+ public final void testWeightedSet() {
+ parseAndConfirm("weightedSet(description, {\"a\": 1, \"b\": 2})");
+ }
+
+ @Test
+ public final void testAnnotatedWord() {
+ parseAndConfirm("description contains ([{\"andSegmenting\": true}]\"a\")");
+ parseAndConfirm("description contains ([{\"weight\": 37}]\"a\")");
+ parseAndConfirm("description contains ([{\"id\": 37}]\"a\")");
+ parseAndConfirm("description contains ([{\"filter\": true}]\"a\")");
+ parseAndConfirm("description contains ([{\"ranked\": false}]\"a\")");
+ parseAndConfirm("description contains ([{\"significance\": 37.0}]\"a\")");
+ parseAndConfirm("description contains ([{\"implicitTransforms\": false}]\"a\")");
+ parseAndConfirm("(description contains ([{\"connectivity\": {\"id\": 2, \"weight\": 0.42}, \"id\": 1}]\"a\") AND description contains ([{\"id\": 2}]\"b\"))");
+ }
+
+ @Test
+ public final void testPrefix() {
+ parseAndConfirm("description contains ([{\"prefix\": true}]\"a\")");
+ }
+
+ @Test
+ public final void testSuffix() {
+ parseAndConfirm("description contains ([{\"suffix\": true}]\"a\")");
+ }
+
+ @Test
+ public final void testSubstring() {
+ parseAndConfirm("description contains ([{\"substring\": true}]\"a\")");
+ }
+
+ @Test
+ public final void testExoticItemTypes() {
+ Item item = MarkerWordItem.createEndOfHost();
+ String q = VespaSerializer.serialize(item);
+ assertEquals("default contains ([{\"implicitTransforms\": false}]\"$\")", q);
+ }
+
+ @Test
+ public final void testEmptyIndex() {
+ Item item = new WordItem("nalle", true);
+ String q = VespaSerializer.serialize(item);
+ assertEquals("default contains \"nalle\"", q);
+ }
+
+ @Test
+ public final void testLongAndNot() {
+ NotItem item = new NotItem();
+ item.addItem(new WordItem("a"));
+ item.addItem(new WordItem("b"));
+ item.addItem(new WordItem("c"));
+ item.addItem(new WordItem("d"));
+ String q = VespaSerializer.serialize(item);
+ assertEquals("(default contains ([{\"implicitTransforms\": false}]\"a\")) AND !(default contains ([{\"implicitTransforms\": false}]\"b\") OR default contains ([{\"implicitTransforms\": false}]\"c\") OR default contains ([{\"implicitTransforms\": false}]\"d\"))", q);
+ }
+
+ @Test
+ public final void testPhraseAsOperatorArgument() {
+ // flattening phrases is a feature, not a bug
+ parseAndConfirm("description contains phrase(\"a\", \"b\", \"c\")",
+ "description contains phrase(\"a\", phrase(\"b\", \"c\"))");
+ parseAndConfirm("description contains equiv(\"a\", phrase(\"b\", \"c\"))");
+ }
+
+ private static void newGroupingRequest(Query query, GroupingOperation grouping, Continuation... continuations) {
+ GroupingRequest request = GroupingRequest.newInstance(query);
+ request.setRootOperation(grouping);
+ request.continuations().addAll(Arrays.asList(continuations));
+ }
+
+ @Test
+ public final void testNumberTypeInt() {
+ parseAndConfirm("title = 500");
+ parseAndConfirm("title > 500");
+ parseAndConfirm("title < (-500)");
+ parseAndConfirm("title >= (-500)");
+ parseAndConfirm("title <= (-500)");
+ parseAndConfirm("range(title, 0, 500)");
+ }
+
+ @Test
+ public final void testNumberTypeLong() {
+ parseAndConfirm("title = 549755813888L");
+ parseAndConfirm("title > 549755813888L");
+ parseAndConfirm("title < (-549755813888L)");
+ parseAndConfirm("title >= (-549755813888L)");
+ parseAndConfirm("title <= (-549755813888L)");
+ parseAndConfirm("range(title, -549755813888L, 549755813888L)");
+ }
+
+ @Test
+ public final void testNumberTypeFloat() {
+ parseAndConfirm("title = 500.0"); // silly
+ parseAndConfirm("title > 500.0");
+ parseAndConfirm("title < (-500.0)");
+ parseAndConfirm("title >= (-500.0)");
+ parseAndConfirm("title <= (-500.0)");
+ parseAndConfirm("range(title, 0.0, 500.0)");
+ }
+
+ @Test
+ public final void testAnnotatedLong() {
+ parseAndConfirm("title >= ([{\"id\": 2014}](-549755813888L))");
+ }
+
+ @Test
+ public final void testHitLimit() {
+ parseAndConfirm("title <= ([{\"hitLimit\": 89}](-500))");
+ parseAndConfirm("title <= ([{\"hitLimit\": 89}](-500))");
+ parseAndConfirm("[{\"hitLimit\": 89}]range(title, 1, 500)");
+ }
+
+ @Test
+ public final 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)");
+ }
+
+ @Test
+ public final void testRegExp() {
+ parseAndConfirm("foo matches \"a b\"");
+ }
+
+ @Test
+ public final void testWordAlternatives() {
+ parseAndConfirm("foo contains" + " ([{\"origin\": {\"original\": \" trees \", \"offset\": 1, \"length\": 5}}]"
+ + "alternatives({\"trees\": 1.0, \"tree\": 0.7}))");
+ }
+
+ @Test
+ public final void testWordAlternativesInPhrase() {
+ parseAndConfirm("foo contains phrase(\"forest\","
+ + " ([{\"origin\": {\"original\": \" trees \", \"offset\": 1, \"length\": 5}}]"
+ + "alternatives({\"trees\": 1.0, \"tree\": 0.7}))"
+ + ")");
+ }
+}