aboutsummaryrefslogtreecommitdiffstats
path: root/container-search/src/main/java/com/yahoo/search/query/ranking/MatchPhase.java
diff options
context:
space:
mode:
Diffstat (limited to 'container-search/src/main/java/com/yahoo/search/query/ranking/MatchPhase.java')
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/ranking/MatchPhase.java153
1 files changed, 153 insertions, 0 deletions
diff --git a/container-search/src/main/java/com/yahoo/search/query/ranking/MatchPhase.java b/container-search/src/main/java/com/yahoo/search/query/ranking/MatchPhase.java
new file mode 100644
index 00000000000..ba25ddbe7e6
--- /dev/null
+++ b/container-search/src/main/java/com/yahoo/search/query/ranking/MatchPhase.java
@@ -0,0 +1,153 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.search.query.ranking;
+
+import com.yahoo.processing.request.CompoundName;
+import com.yahoo.search.query.Ranking;
+import com.yahoo.search.query.profile.types.FieldDescription;
+import com.yahoo.search.query.profile.types.QueryProfileType;
+
+import java.util.Objects;
+
+/**
+ * The match phase ranking settings of this query.
+ * These are the same settings for match phase that can be set in a rank profile
+ * and is used for achieving reasonable query behavior given a query which causes too many matches:
+ * The engine will fall back to retrieving the best values according to the attribute given here
+ * during matching.
+ * <p>
+ * For this feature to work well, the order given by the attribute should correlate reasonably with the order
+ * of results produced if full evaluation is performed.
+ *
+ * @author bratseth
+ */
+public class MatchPhase implements Cloneable {
+
+ /** The type representing the property arguments consumed by this */
+ private static final QueryProfileType argumentType;
+
+ public static final String ATTRIBUTE = "attribute";
+ public static final String ASCENDING = "ascending";
+ public static final String MAX_HITS = "maxHits";
+ public static final String MAX_FILTER_COVERAGE = "maxFilterCoverage";
+
+ static {
+ argumentType =new QueryProfileType(Ranking.MATCH_PHASE);
+ argumentType.setStrict(true);
+ argumentType.setBuiltin(true);
+ argumentType.addField(new FieldDescription(ATTRIBUTE, "string"));
+ argumentType.addField(new FieldDescription(ASCENDING, "boolean"));
+ argumentType.addField(new FieldDescription(MAX_HITS, "long"));
+ argumentType.addField(new FieldDescription(MAX_FILTER_COVERAGE, "double"));
+ argumentType.addField(new FieldDescription(Ranking.DIVERSITY, "query-profile", "diversity"));
+ argumentType.freeze();
+ }
+ public static QueryProfileType getArgumentType() { return argumentType; }
+
+ private String attribute = null;
+ private boolean ascending = false;
+ private Long maxHits = null;
+ private Double maxFilterCoverage = 1.0;
+ private Diversity diversity = new Diversity();
+
+ /**
+ * Sets the attribute field which will be used to decide the best matches after it has been determined
+ * during matching that this query is going to cause too many matches.
+ * Set to null (default) to disable degradation.
+ * <p>
+ * If this is set, make sure to also set the maxHits value.
+ * Otherwise, the attribute setting is ignored.
+ * <p>
+ * This attribute should have fast-search turned on.
+ */
+ public void setAttribute(String attribute) { this.attribute = attribute; }
+
+ /** Returns the attribute to use for degradation, or null if none */
+ public String getAttribute() { return attribute; }
+
+ /**
+ * Set to true to sort by the attribute in ascending order when this is in use during the match phase,
+ * false (default) to use descending order.
+ */
+ public void setAscending(boolean ascending) { this.ascending = ascending; }
+
+ /**
+ * Returns the order to sort the attribute during the path phase when this takes effect.
+ */
+ public boolean getAscending() { return ascending; }
+
+ /**
+ * Sets the max hits to aim for producing in the match phase.
+ * This must be set if an attribute value is set.
+ * It should be set to a reasonable fraction of the total documents on each partition.
+ */
+ public void setMaxHits(long maxHits) { this.maxHits = maxHits; }
+
+ public void setMaxFilterCoverage(double maxFilterCoverage) {
+ if ((maxFilterCoverage < 0.0) || (maxFilterCoverage > 1.0)) {
+ throw new IllegalArgumentException("maxFilterCoverage must be in the range [0.0, 1.0]. It is " + maxFilterCoverage);
+ }
+ this.maxFilterCoverage = maxFilterCoverage;
+ }
+
+ /** Returns the max hits to aim for producing in the match phase on each content node, or null if not set */
+ public Long getMaxHits() { return maxHits; }
+
+ public Double getMaxFilterCoverage() { return maxFilterCoverage; }
+
+ public Diversity getDiversity() { return diversity; }
+
+ public void setDiversity(Diversity diversity) {
+ this.diversity = diversity;
+ }
+
+ /** Internal operation - DO NOT USE */
+ public void prepare(RankProperties rankProperties) {
+ if (attribute == null || maxHits == null) return;
+
+ rankProperties.put("vespa.matchphase.degradation.attribute", attribute);
+ if (ascending) { // backend default is descending
+ rankProperties.put("vespa.matchphase.degradation.ascendingorder", "true");
+ }
+ rankProperties.put("vespa.matchphase.degradation.maxhits", String.valueOf(maxHits));
+ rankProperties.put("vespa.matchphase.degradation.maxfiltercoverage", String.valueOf(maxFilterCoverage));
+ diversity.prepare(rankProperties);
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 0;
+ hash += 13 * Boolean.hashCode(ascending);
+ hash += 19 * diversity.hashCode();
+ if (attribute != null) hash += 11 * attribute.hashCode();
+ if (maxHits != null) hash += 17 * maxHits.hashCode();
+ hash += 23 * maxFilterCoverage.hashCode();
+ return hash;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if ( ! (o instanceof MatchPhase)) return false;
+
+ MatchPhase other = (MatchPhase)o;
+ if ( this.ascending != other.ascending) return false;
+ if ( ! Objects.equals(this.attribute, other.attribute)) return false;
+ if ( ! Objects.equals(this.maxHits, other.maxHits)) return false;
+ if ( ! Objects.equals(this.diversity, other.diversity)) return false;
+ if ( ! Objects.equals(this.maxFilterCoverage, other.maxFilterCoverage)) return false;
+ return true;
+ }
+
+ @Override
+ public MatchPhase clone() {
+ try {
+ MatchPhase clone = (MatchPhase)super.clone();
+ clone.diversity = diversity.clone();
+ return clone;
+ }
+ catch (CloneNotSupportedException e) {
+ throw new RuntimeException("Won't happen", e);
+ }
+ }
+
+}