summaryrefslogtreecommitdiffstats
path: root/container-search/src/main/java/com/yahoo/prelude/query/parser/AllParser.java
diff options
context:
space:
mode:
Diffstat (limited to 'container-search/src/main/java/com/yahoo/prelude/query/parser/AllParser.java')
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/query/parser/AllParser.java186
1 files changed, 186 insertions, 0 deletions
diff --git a/container-search/src/main/java/com/yahoo/prelude/query/parser/AllParser.java b/container-search/src/main/java/com/yahoo/prelude/query/parser/AllParser.java
new file mode 100644
index 00000000000..cb540a1f982
--- /dev/null
+++ b/container-search/src/main/java/com/yahoo/prelude/query/parser/AllParser.java
@@ -0,0 +1,186 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.prelude.query.parser;
+
+import com.yahoo.prelude.query.*;
+import com.yahoo.search.query.QueryTree;
+import com.yahoo.search.query.parser.ParserEnvironment;
+
+import java.util.Iterator;
+
+import static com.yahoo.prelude.query.parser.Token.Kind.MINUS;
+import static com.yahoo.prelude.query.parser.Token.Kind.SPACE;
+
+/**
+ * Parser for queries of type all.
+ *
+ * @author <a href="mailto:steinar@yahoo-inc.com">Steinar Knutsen</a>
+ */
+public class AllParser extends SimpleParser {
+
+ public AllParser(ParserEnvironment environment) {
+ super(environment);
+ }
+
+ protected Item parseItems() {
+ int position = tokens.getPosition();
+ try {
+ return parseItemsBody();
+ } finally {
+ tokens.setPosition(position);
+ }
+ }
+
+ protected Item parseItemsBody() {
+ // Algorithm: Collect positive, negative, and and'ed items, then combine.
+ AndItem and=null;
+ NotItem not=null; // Store negatives here as we go
+ Item current;
+
+ // Find all items
+ do {
+ current=negativeItem();
+ if (current!=null) {
+ not=addNot(current,not);
+ continue;
+ }
+
+ current=positiveItem();
+ if (current==null)
+ current = indexableItem();
+ if (current == null)
+ current = compositeItem();
+
+ if (current!=null)
+ and=addAnd(current,and);
+
+ if (current == null)
+ tokens.skip();
+ } while (tokens.hasNext());
+
+ // Combine the items
+ Item topLevel=and;
+
+ if (not!=null && topLevel!=null) {
+ not.setPositiveItem(topLevel);
+ topLevel=not;
+ }
+
+ return simplifyUnnecessaryComposites(topLevel);
+ }
+
+ // Simplify if there are unnecessary composites due to single elements
+ protected final Item simplifyUnnecessaryComposites(Item item) {
+ if (item == null) return null;
+
+ QueryTree root = new QueryTree(item);
+ QueryCanonicalizer.canonicalize(root);
+
+ return root.getRoot() instanceof NullItem ? null : root.getRoot();
+ }
+
+ protected AndItem addAnd(Item item,AndItem and) {
+ if (and==null)
+ and=new AndItem();
+ and.addItem(item);
+ return and;
+ }
+
+ protected OrItem addOr(Item item,OrItem or) {
+ if (or==null)
+ or=new OrItem();
+ or.addItem(item);
+ return or;
+ }
+
+ protected NotItem addNot(Item item,NotItem not) {
+ if (not==null)
+ not=new NotItem();
+ not.addNegativeItem(item);
+ return not;
+ }
+
+ protected Item negativeItem() {
+ int position = tokens.getPosition();
+ Item item = null;
+ try {
+ if (!tokens.skipMultiple(MINUS)) return null;
+
+ if (tokens.currentIsNoIgnore(SPACE)) return null;
+
+ item = indexableItem();
+ if (item == null) {
+ item = compositeItem();
+
+ if (item != null) {
+ if (item instanceof OrItem) { // Turn into And
+ AndItem and = new AndItem();
+
+ for (Iterator<Item> i = ((OrItem) item).getItemIterator(); i.hasNext();) {
+ and.addItem(i.next());
+ }
+ item = and;
+ }
+ }
+ }
+ if (item!=null)
+ item.setProtected(true);
+ return item;
+ } finally {
+ if (item == null) {
+ tokens.setPosition(position);
+ }
+ }
+ }
+
+ /**
+ * Returns the top level item resulting from combining the given top
+ * level item and the new item. This implements most of the weird transformation
+ * rules of the parser.
+ */
+ protected Item combineItems(Item topLevelItem, Item item) {
+ if (topLevelItem == null) {
+ return item;
+ } else if (topLevelItem instanceof OrItem && item instanceof OrItem) {
+ OrItem newTopOr = new OrItem();
+
+ newTopOr.addItem(topLevelItem);
+ newTopOr.addItem(item);
+ return newTopOr;
+ } else if (item instanceof OrItem && topLevelItem instanceof RankItem) {
+ for (Iterator<Item> i = ((RankItem) topLevelItem).getItemIterator(); i.hasNext();) {
+ ((OrItem) item).addItem(0, i.next());
+ }
+ return item;
+ } else if (item instanceof OrItem && topLevelItem instanceof PhraseItem) {
+ OrItem newTopOr = new OrItem();
+
+ newTopOr.addItem(topLevelItem);
+ newTopOr.addItem(item);
+ return newTopOr;
+ } else if (!(topLevelItem instanceof RankItem)) {
+ RankItem rank = new RankItem();
+
+ if (topLevelItem instanceof NotItem) { // Strange rule, but that's how it is
+ rank.addItem(topLevelItem);
+ rank.addItem(item);
+ } else {
+ rank.addItem(item);
+ rank.addItem(topLevelItem);
+ }
+ return rank;
+ } else if ((item instanceof RankItem) && (((RankItem)item).getItem(0) instanceof OrItem)) {
+ RankItem itemAsRank = (RankItem) item;
+ OrItem or = (OrItem) itemAsRank.getItem(0);
+
+ ((RankItem) topLevelItem).addItem(0, or);
+ for (int i = 1; i < itemAsRank.getItemCount(); i++) {
+ or.addItem(0, itemAsRank.getItem(i));
+ }
+ return topLevelItem;
+ } else {
+ ((RankItem) topLevelItem).addItem(0, item);
+ return topLevelItem;
+ }
+ }
+
+}