diff options
-rw-r--r-- | container-search/src/main/java/com/yahoo/search/query/Ranking.java | 11 | ||||
-rw-r--r-- | container-search/src/main/java/com/yahoo/search/query/properties/QueryProperties.java | 19 | ||||
-rw-r--r-- | container-search/src/main/java/com/yahoo/search/query/ranking/Matching.java | 123 | ||||
-rw-r--r-- | container-search/src/main/java/com/yahoo/search/query/ranking/SoftTimeout.java (renamed from container-search/src/main/java/com/yahoo/search/query/SoftTimeout.java) | 4 | ||||
-rw-r--r-- | container-search/src/test/java/com/yahoo/search/query/MatchingTestCase.java | 54 |
5 files changed, 207 insertions, 4 deletions
diff --git a/container-search/src/main/java/com/yahoo/search/query/Ranking.java b/container-search/src/main/java/com/yahoo/search/query/Ranking.java index addd759cd29..17ec32b200a 100644 --- a/container-search/src/main/java/com/yahoo/search/query/Ranking.java +++ b/container-search/src/main/java/com/yahoo/search/query/Ranking.java @@ -8,8 +8,10 @@ import com.yahoo.search.Query; import com.yahoo.search.query.profile.types.FieldDescription; import com.yahoo.search.query.profile.types.QueryProfileType; import com.yahoo.search.query.ranking.MatchPhase; +import com.yahoo.search.query.ranking.Matching; import com.yahoo.search.query.ranking.RankFeatures; import com.yahoo.search.query.ranking.RankProperties; +import com.yahoo.search.query.ranking.SoftTimeout; import com.yahoo.search.result.ErrorMessage; /** @@ -38,6 +40,7 @@ public class Ranking implements Cloneable { public static final String MATCH_PHASE = "matchPhase"; public static final String DIVERSITY = "diversity"; public static final String SOFTTIMEOUT = "softtimeout"; + public static final String MATCHING = "matching"; public static final String FEATURES = "features"; public static final String PROPERTIES = "properties"; @@ -83,6 +86,8 @@ public class Ranking implements Cloneable { private MatchPhase matchPhase = new MatchPhase(); + private Matching matching = new Matching(); + private SoftTimeout softTimeout = new SoftTimeout(); public Ranking(Query parent) { @@ -172,6 +177,9 @@ public class Ranking implements Cloneable { /** Returns the match phase rank settings of this. This is never null. */ public MatchPhase getMatchPhase() { return matchPhase; } + /** Returns the matching settings of this. This is never null. */ + public Matching getMatching() { return matching; } + /** Returns the soft timeout settings of this. This is never null. */ public SoftTimeout getSoftTimeout() { return softTimeout; } @@ -185,6 +193,7 @@ public class Ranking implements Cloneable { clone.rankProperties = this.rankProperties.clone(); clone.rankFeatures = this.rankFeatures.clone(); clone.matchPhase = this.matchPhase.clone(); + clone.matching = this.matching.clone(); clone.softTimeout = this.softTimeout.clone(); return clone; } @@ -216,6 +225,7 @@ public class Ranking implements Cloneable { hash += 13 * rankProperties.hashCode(); hash += 17 * matchPhase.hashCode(); hash += 19 * softTimeout.hashCode(); + hash += 23 * matching.hashCode(); return Ranking.class.hashCode() + QueryHelper.combineHash(sorting,location,profile,hash); } @@ -240,6 +250,7 @@ public class Ranking implements Cloneable { public void prepare() { rankFeatures.prepare(rankProperties); matchPhase.prepare(rankProperties); + matching.prepare(rankProperties); softTimeout.prepare(rankProperties); prepareNow(freshness); } diff --git a/container-search/src/main/java/com/yahoo/search/query/properties/QueryProperties.java b/container-search/src/main/java/com/yahoo/search/query/properties/QueryProperties.java index 30154b223a5..dbbb9977e05 100644 --- a/container-search/src/main/java/com/yahoo/search/query/properties/QueryProperties.java +++ b/container-search/src/main/java/com/yahoo/search/query/properties/QueryProperties.java @@ -1,16 +1,16 @@ // 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.properties; -import com.yahoo.component.ComponentId; import com.yahoo.processing.request.CompoundName; import com.yahoo.search.Query; import com.yahoo.search.query.*; import com.yahoo.search.query.profile.compiled.CompiledQueryProfileRegistry; import com.yahoo.search.query.profile.types.FieldDescription; import com.yahoo.search.query.profile.types.QueryProfileType; -import com.yahoo.search.query.profile.types.QueryProfileTypeRegistry; import com.yahoo.search.query.ranking.Diversity; import com.yahoo.search.query.ranking.MatchPhase; +import com.yahoo.search.query.ranking.Matching; +import com.yahoo.search.query.ranking.SoftTimeout; import com.yahoo.tensor.Tensor; import java.util.Map; @@ -119,6 +119,14 @@ public class QueryProperties extends Properties { if (key.last().equals(SoftTimeout.FACTOR)) return soft.getFactor(); if (key.last().equals(SoftTimeout.TAILCOST)) return soft.getTailcost(); } + else if (key.size() == 3 && key.get(1).equals(Ranking.MATCHING)) { + Matching matching = ranking.getMatching(); + if (key.last().equals(Matching.TERMWISELIMIT)) return matching.getTermwiseLimit(); + if (key.last().equals(Matching.NUMTHREADSPERSEARCH)) return matching.getNumThreadsPerSearch(); + if (key.last().equals(Matching.NUMSEARCHPARTITIIONS)) return matching.getNumSearchPartitions(); + if (key.last().equals(Matching.MINHITSPERTHREAD)) return matching.getMinHitsPerThread(); + + } else if (key.size()>2) { // pass the portion after "ranking.features/properties" down if (key.get(1).equals(Ranking.FEATURES)) return ranking.getFeatures().getObject(key.rest().rest().toString()); @@ -228,6 +236,13 @@ public class QueryProperties extends Properties { if (key.last().equals(SoftTimeout.FACTOR)) soft.setFactor(asDouble(value, 0.50)); if (key.last().equals(SoftTimeout.TAILCOST)) soft.setTailcost(asDouble(value, 0.10)); } + else if (key.size() == 3 && key.get(1).equals(Ranking.MATCHING)) { + Matching matching = ranking.getMatching(); + if (key.last().equals(Matching.TERMWISELIMIT)) matching.setTermwiselimit(asDouble(value, 1.0)); + if (key.last().equals(Matching.NUMTHREADSPERSEARCH)) matching.setNumThreadsPerSearch(asInteger(value, 1)); + if (key.last().equals(Matching.NUMSEARCHPARTITIIONS)) matching.setNumSearchPartitions(asInteger(value, 1)); + if (key.last().equals(Matching.MINHITSPERTHREAD)) matching.setMinHitsPerThread(asInteger(value, 0)); + } else if (key.size()>2) { String restKey = key.rest().rest().toString(); if (key.get(1).equals(Ranking.FEATURES)) diff --git a/container-search/src/main/java/com/yahoo/search/query/ranking/Matching.java b/container-search/src/main/java/com/yahoo/search/query/ranking/Matching.java new file mode 100644 index 00000000000..514a0f36031 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/query/ranking/Matching.java @@ -0,0 +1,123 @@ +package com.yahoo.search.query.ranking; + +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; + +/** + * Holds the settings for the matching feature. + * + * @author balder + */ +public class Matching implements Cloneable { + /** The type representing the property arguments consumed by this */ + private static final QueryProfileType argumentType; + + public static final String TERMWISELIMIT = "termwiselimit"; + public static final String NUMTHREADSPERSEARCH = "numthreadspersearch"; + public static final String NUMSEARCHPARTITIIONS = "numsearchpartitions"; + public static final String MINHITSPERTHREAD = "minhitsperthread"; + + + static { + argumentType =new QueryProfileType(Ranking.MATCHING); + argumentType.setStrict(true); + argumentType.setBuiltin(true); + argumentType.addField(new FieldDescription(TERMWISELIMIT, "double")); + argumentType.addField(new FieldDescription(NUMTHREADSPERSEARCH, "integer")); + argumentType.addField(new FieldDescription(NUMSEARCHPARTITIIONS, "integer")); + argumentType.addField(new FieldDescription(MINHITSPERTHREAD, "integer")); + argumentType.freeze(); + } + public static QueryProfileType getArgumentType() { return argumentType; } + + public Double termwiseLimit = null; + private Integer numThreadsPerSearch = null; + private Integer numSearchPartitions = null; + private Integer minHitsPerThread = null; + + public Integer getNumSearchPartitions() { + return numSearchPartitions; + } + + public void setNumSearchPartitions(int numSearchPartitions) { + this.numSearchPartitions = numSearchPartitions; + } + + public Integer getMinHitsPerThread() { + return minHitsPerThread; + } + + public void setMinHitsPerThread(int minHitsPerThread) { + this.minHitsPerThread = minHitsPerThread; + } + + public void setTermwiselimit(double value) { + if ((value < 0.0) || (value > 1.0)) { + throw new IllegalArgumentException("termwiselimit must be in the range [0.0, 1.0]. It is " + value); + } + termwiseLimit = value; + } + + public Double getTermwiseLimit() { return termwiseLimit; } + + public void setNumThreadsPerSearch(int value) { + numThreadsPerSearch = value; + } + public Integer getNumThreadsPerSearch() { return numThreadsPerSearch; } + + + /** Internal operation - DO NOT USE */ + public void prepare(RankProperties rankProperties) { + + if (termwiseLimit != null) { + rankProperties.put("vespa.matching.termwise_limit", String.valueOf(termwiseLimit)); + } + if (numThreadsPerSearch != null) { + rankProperties.put("vespa.matching.numthreadspersearch", String.valueOf(numThreadsPerSearch)); + } + if (numSearchPartitions != null) { + rankProperties.put("vespa.matching.numsearchpartitions", String.valueOf(numSearchPartitions)); + } + if (minHitsPerThread != null) { + rankProperties.put("vespa.matching.minhitsperthread", String.valueOf(minHitsPerThread)); + } + } + + @Override + public Matching clone() { + try { + return (Matching) super.clone(); + } + catch (CloneNotSupportedException e) { + throw new RuntimeException("Won't happen", e); + } + } + + @Override + public int hashCode() { + int hash = 0; + if (termwiseLimit != null) hash += 11 * termwiseLimit.hashCode(); + if (numThreadsPerSearch != null) hash += 13 * numThreadsPerSearch.hashCode(); + if (numSearchPartitions != null) hash += 17 * numSearchPartitions.hashCode(); + if (minHitsPerThread != null) hash += 19 * minHitsPerThread.hashCode(); + return hash; + } + + @Override + public boolean equals(Object o) { + if (o == this) return true; + if ( ! (o instanceof Matching)) return false; + + Matching other = (Matching) o; + if ( ! Objects.equals(this.termwiseLimit, other.termwiseLimit)) return false; + if ( ! Objects.equals(this.numThreadsPerSearch, other.numThreadsPerSearch)) return false; + if ( ! Objects.equals(this.numSearchPartitions, other.numSearchPartitions)) return false; + if ( ! Objects.equals(this.minHitsPerThread, other.minHitsPerThread)) return false; + return true; + } + +} + diff --git a/container-search/src/main/java/com/yahoo/search/query/SoftTimeout.java b/container-search/src/main/java/com/yahoo/search/query/ranking/SoftTimeout.java index 2db1235f72c..950cb861da6 100644 --- a/container-search/src/main/java/com/yahoo/search/query/SoftTimeout.java +++ b/container-search/src/main/java/com/yahoo/search/query/ranking/SoftTimeout.java @@ -1,8 +1,8 @@ -package com.yahoo.search.query; +package com.yahoo.search.query.ranking; +import com.yahoo.search.query.Ranking; import com.yahoo.search.query.profile.types.FieldDescription; import com.yahoo.search.query.profile.types.QueryProfileType; -import com.yahoo.search.query.ranking.RankProperties; import java.util.Objects; diff --git a/container-search/src/test/java/com/yahoo/search/query/MatchingTestCase.java b/container-search/src/test/java/com/yahoo/search/query/MatchingTestCase.java new file mode 100644 index 00000000000..49e632b00bd --- /dev/null +++ b/container-search/src/test/java/com/yahoo/search/query/MatchingTestCase.java @@ -0,0 +1,54 @@ +package com.yahoo.search.query; + +import com.yahoo.prelude.query.QueryException; +import com.yahoo.search.Query; +import org.junit.Test; + +import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; + +/** + * @author baldersheim + */ +public class MatchingTestCase { + @Test + public void testDefaultsInQuery() { + Query query=new Query("?query=test"); + assertNull(query.getRanking().getMatching().getTermwiseLimit()); + assertNull(query.getRanking().getMatching().getNumThreadsPerSearch()); + assertNull(query.getRanking().getMatching().getNumSearchPartitions()); + assertNull(query.getRanking().getMatching().getMinHitsPerThread()); + + } + + @Test + public void testQueryOverride() { + Query query=new Query("?query=test&ranking.matching.termwiselimit=0.7&ranking.matching.numthreadspersearch=17&ranking.matching.numsearchpartitions=13&ranking.matching.minhitsperthread=3"); + assertEquals(Double.valueOf(0.7), query.getRanking().getMatching().getTermwiseLimit()); + assertEquals(Integer.valueOf(17), query.getRanking().getMatching().getNumThreadsPerSearch()); + assertEquals(Integer.valueOf(13), query.getRanking().getMatching().getNumSearchPartitions()); + assertEquals(Integer.valueOf(3), query.getRanking().getMatching().getMinHitsPerThread()); + + query.prepare(); + assertEquals("0.7", query.getRanking().getProperties().get("vespa.matching.termwise_limit").get(0)); + assertEquals("17", query.getRanking().getProperties().get("vespa.matching.numthreadspersearch").get(0)); + assertEquals("13", query.getRanking().getProperties().get("vespa.matching.numsearchpartitions").get(0)); + assertEquals("3", query.getRanking().getProperties().get("vespa.matching.minhitsperthread").get(0)); + } + + private void verifyException(String key, String value) { + try { + new Query("?query=test&ranking.matching."+key+"="+value); + assertFalse(true); + } catch (QueryException e) { + assertEquals("Invalid request parameter", e.getMessage()); + assertEquals("Could not set 'ranking.matching." + key + "' to '" + value +"'", e.getCause().getMessage()); + assertEquals(key + " must be in the range [0.0, 1.0]. It is " + value, e.getCause().getCause().getMessage()); + } + } + @Test + public void testLimits() { + verifyException("termwiselimit", "-0.1"); + verifyException("termwiselimit", "1.1"); + } +} |