summaryrefslogtreecommitdiffstats
path: root/container-search/src/main/java/com/yahoo/prelude/semantics/engine/Evaluation.java
diff options
context:
space:
mode:
Diffstat (limited to 'container-search/src/main/java/com/yahoo/prelude/semantics/engine/Evaluation.java')
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/semantics/engine/Evaluation.java145
1 files changed, 94 insertions, 51 deletions
diff --git a/container-search/src/main/java/com/yahoo/prelude/semantics/engine/Evaluation.java b/container-search/src/main/java/com/yahoo/prelude/semantics/engine/Evaluation.java
index 85bcdf8bd20..7bfcc08f21b 100644
--- a/container-search/src/main/java/com/yahoo/prelude/semantics/engine/Evaluation.java
+++ b/container-search/src/main/java/com/yahoo/prelude/semantics/engine/Evaluation.java
@@ -2,6 +2,7 @@
package com.yahoo.prelude.semantics.engine;
import com.yahoo.prelude.query.*;
+import com.yahoo.prelude.semantics.RuleBase;
import com.yahoo.search.Query;
import com.yahoo.search.query.QueryTree;
@@ -32,11 +33,13 @@ public class Evaluation {
/** The rule evaluation context, can be reset once the rule is evaluated */
private final RuleEvaluation ruleEvaluation;
+ private final RuleBase ruleBase;
+
/**
* The amount of context information to collect about this evaluation.
* 0 means no context information, higher numbers means more context information.
*/
- private int traceLevel = 0;
+ private final int traceLevel;
private String traceIndentation = "";
@@ -49,8 +52,8 @@ public class Evaluation {
/** Should we allow stemmed matches? */
private boolean stemming = true;
- public Evaluation(Query query) {
- this(query,0);
+ public Evaluation(Query query, RuleBase ruleBase) {
+ this(query, ruleBase, 0);
}
/**
@@ -59,13 +62,17 @@ public class Evaluation {
* @param query the query this evaluation is for
* @param traceLevel the amount of tracing to do
*/
- public Evaluation(Query query, int traceLevel) {
+ public Evaluation(Query query, RuleBase ruleBase, int traceLevel) {
this.query = query;
+ this.ruleBase = ruleBase;
this.traceLevel = traceLevel;
reset();
ruleEvaluation = new RuleEvaluation(this);
}
+ /** Returns the rule base this evaluates over */
+ public RuleBase ruleBase() { return ruleBase; }
+
/** Resets the item iterator to point to the first item */
public void reset() {
if (flattenedItems != null)
@@ -134,11 +141,11 @@ public class Evaluation {
/** Adds an item to the query being evaluated in a way consistent with the query type */
// TODO: Add this functionality to Query?
public void addItem(Item item, TermType termType) {
- Item root= query.getModel().getQueryTree().getRoot();
- if (root==null)
+ Item root = query.getModel().getQueryTree().getRoot();
+ if (root == null)
query.getModel().getQueryTree().setRoot(item);
else
- query.getModel().getQueryTree().setRoot(combineItems(root,item,termType));
+ query.getModel().getQueryTree().setRoot(combineItems(root, item, termType));
}
/** Removes this item */
@@ -151,18 +158,18 @@ public class Evaluation {
* equal items
*/
public void removeItemByIdentity(Item item) {
- int position=findIndexByIdentity(item);
- if (position>=0)
+ int position = findIndexByIdentity(item);
+ if (position >= 0)
item.getParent().removeItem(position);
else
item.getParent().removeItem(item); // Fallback to removeField by equal()
}
private int findIndexByIdentity(Item item) {
- int position=0;
- for (Iterator<Item> i=item.getParent().getItemIterator(); i.hasNext(); ) {
- Item child=i.next();
- if (item==child) {
+ int position = 0;
+ for (Iterator<Item> i = item.getParent().getItemIterator(); i.hasNext(); ) {
+ Item child = i.next();
+ if (item == child) {
return position;
}
position++;
@@ -172,7 +179,7 @@ public class Evaluation {
/** Removes an item, prefers the one at/close to the given position if there are multiple ones */
public void removeItem(int position,Item item) {
- Item removeCandidate=item.getParent().getItem(position);
+ Item removeCandidate = item.getParent().getItem(position);
if (removeCandidate.equals(item)) // Remove based on position
item.getParent().removeItem(position);
else
@@ -189,7 +196,7 @@ public class Evaluation {
if (!(item instanceof SegmentItem)) {
return item;
}
- CompositeItem converted = null;
+ CompositeItem converted;
if (item instanceof AndSegmentItem) {
converted = new AndItem();
} else if (item instanceof PhraseSegmentItem) {
@@ -238,16 +245,21 @@ public class Evaluation {
/**
* Inserts an item to the query being evaluated in a way consistent with the query type
*
- * @param item the item to insert
+ * @param items the item to insert
* @param parent the parent of this item, or null to set the root
* @param index the index at which to insert this into the parent
* @param desiredParentType the desired type of the composite which contains item when this returns
*/
- public void insertItem(Item item, CompositeItem parent, int index, TermType desiredParentType) {
+ public void insertItems(List<Item> items, CompositeItem parent, int index, TermType desiredParentType) {
if (isEmpty(parent)) {
- CompositeItem newParent = (CompositeItem)desiredParentType.createItemClass();
- newParent.addItem(item);
- query.getModel().getQueryTree().setRoot(newParent);
+ if (items.size() == 1 && desiredParentType.hasItemClass(items.get(0).getClass())) {
+ query.getModel().getQueryTree().setRoot(items.get(0));
+ }
+ else {
+ CompositeItem newParent = (CompositeItem) desiredParentType.createItemClass();
+ items.forEach(item -> newParent.addItem(item));
+ query.getModel().getQueryTree().setRoot(newParent);
+ }
return;
}
@@ -260,17 +272,31 @@ public class Evaluation {
}
if (( desiredParentType == TermType.DEFAULT || desiredParentType.hasItemClass(parent.getClass()) )
- && equalIndexNameIfParentIsPhrase(item, parent)) {
- addItem(parent, index, item, desiredParentType);
+ && equalIndexNameIfParentIsPhrase(items, parent)) {
+ for (Item item : items)
+ addItem(parent, index, item, desiredParentType);
+ }
+ else if (parent.items().isEmpty()) {
+ CompositeItem parentsParent = parent.getParent();
+ CompositeItem newParent = newParent(desiredParentType);
+ items.forEach(item -> newParent.addItem(item));
+ parentsParent.setItem(parentsParent.getItemIndex(parent), newParent);
+ }
+ else if (items.size() ==1 && desiredParentType.hasItemClass(items.get(0).getClass())) { // This will never happen
+ for (Item item : items)
+ addItem(parent, index, item, desiredParentType);
}
else if (incompatible(desiredParentType, parent)) {
- insertIncompatibleItem(item, parent, query, desiredParentType);
+ for (Item item : items)
+ insertIncompatibleItem(item, parent, query, desiredParentType);
}
else {
- insertIncompatibleItemAsParent(item, parent, query, desiredParentType);
+ for (Item item : items)
+ insertIncompatibleItemAsParent(item, parent, query, desiredParentType);
}
}
+ /** Returns true if this item represents an empty query *tree*. */
private boolean isEmpty(Item item) {
if (item == null) return true;
if (item instanceof QueryTree && ((QueryTree) item).isEmpty()) return true;
@@ -278,8 +304,9 @@ public class Evaluation {
}
/** Returns true if the desired type cannot have childCandidate as a child */
- private boolean incompatible(TermType desiredParentType, Item childCandidate) {
- return desiredParentType == TermType.EQUIV && childCandidate.getItemType() != Item.ItemType.EQUIV;
+ private boolean incompatible(TermType desiredParentType, CompositeItem parent) {
+ return desiredParentType == TermType.EQUIV
+ && (parent.getItemType() != Item.ItemType.EQUIV && parent.getItemType() != Item.ItemType.PHRASE);
}
private void addItem(CompositeItem parent, int index, Item item, TermType desiredParentType) {
@@ -287,7 +314,7 @@ public class Evaluation {
if (index == 0 && parent.getItem(0) == null) { // Case 1: The current positive is null and we are adding a positive
parent.setItem(0, item);
}
- else if (index<=1 && !(parent.getItem(0) instanceof CompositeItem)) { // Case 2: The positive must become a composite
+ else if (index <= 1 && !(parent.getItem(0) instanceof CompositeItem)) { // Case 2: The positive must become a composite
CompositeItem positiveComposite = (CompositeItem)desiredParentType.createItemClass();
positiveComposite.addItem(parent.getItem(0));
positiveComposite.addItem(index, item);
@@ -313,50 +340,46 @@ public class Evaluation {
}
/** A special purpose check used to simplify the above */
- private boolean equalIndexNameIfParentIsPhrase(Item item,CompositeItem parent) {
+ private boolean equalIndexNameIfParentIsPhrase(List<Item> items, CompositeItem parent) {
if ( ! (parent instanceof PhraseItem)) return true;
- if ( ! (item instanceof IndexedItem)) return true;
+ var phrase = (PhraseItem)parent;
- return ((PhraseItem)parent).getIndexName().equals(((IndexedItem)item).getIndexName());
+ for (Item item : items) {
+ if ( ! (item instanceof IndexedItem)) continue;
+ var indexedItem = (IndexedItem)item;
+ if (! indexedItem.getIndexName().equals(phrase.getIndexName())) return false;
+ }
+ return true;
}
private void insertIncompatibleItem(Item item, CompositeItem parent, Query query, TermType desiredParentType) {
- CompositeItem newParent;
- if (desiredParentType == TermType.DEFAULT)
- newParent = new AndItem();
- else
- newParent = (CompositeItem)desiredParentType.createItemClass();
+ CompositeItem newParent = newParent(desiredParentType);
newParent.addItem(item);
parent.addItem(newParent);
}
- private void insertIncompatibleItemAsParent(Item item, CompositeItem parent, Query query, TermType desiredParentType) {
- // Create new parent
- CompositeItem newParent;
- if (desiredParentType == TermType.DEFAULT)
- newParent = new AndItem();
- else
- newParent = (CompositeItem)desiredParentType.createItemClass();
+ private CompositeItem newParent(TermType desiredParentType) {
+ return desiredParentType == TermType.DEFAULT ? new AndItem() : (CompositeItem)desiredParentType.createItemClass();
+ }
- // Save previous parent parent
+ private void insertIncompatibleItemAsParent(Item item, CompositeItem parent, Query query, TermType desiredParentType) {
CompositeItem parentsParent = parent.getParent();
+ CompositeItem newParent = newParent(desiredParentType);
+ if (! (parentsParent instanceof QueryTree) && parentsParent.getItemType() == newParent.getItemType()) { // Collapse
+ newParent = parentsParent;
+ }
+
// Add items to new parent
newParent.addItem(parent);
newParent.addItem(item);
- // Insert new parent as root or child of old parents parent
- if (parentsParent == null) {
- query.getModel().getQueryTree().setRoot(newParent);
-
- }
- else {
+ if (newParent != parentsParent) // Insert new parent as root or child of old parent's parent
parentsParent.setItem(parentsParent.getItemIndex(parent), newParent);
- }
}
- private Item combineItems(Item first,Item second,TermType termType) {
+ private Item combineItems(Item first, Item second, TermType termType) {
if (first instanceof NullItem) {
return second;
} else if (first instanceof NotItem) {
@@ -378,6 +401,10 @@ public class Evaluation {
return composite;
}
else {
+ if (combined instanceof EquivItem) {
+ first = makeEquivCompatible(first);
+ second = makeEquivCompatible(second);
+ }
combined.addItem(first);
combined.addItem(second); // Also works for nots
return combined;
@@ -394,6 +421,22 @@ public class Evaluation {
}
}
+ private Item makeEquivCompatible(Item item) {
+ if (item instanceof AndItem || item instanceof WeakAndItem) {
+ PhraseItem phrase = new PhraseItem();
+ List<Item> children = ((CompositeItem)item).items();
+ if (children.isEmpty()) return phrase;
+ String index = ((IndexedItem)children.get(0)).getIndexName();
+ for (var child : ((CompositeItem)item).items())
+ phrase.addItem(child);
+ phrase.setIndexName(index);
+ return phrase;
+ }
+ else {
+ return item; // Compatible, or can't be made so
+ }
+ }
+
private CompositeItem createType(TermType termType) {
if (termType == TermType.DEFAULT) {
if (query.getModel().getType() == Query.Type.ANY)