aboutsummaryrefslogtreecommitdiffstats
path: root/container-search/src/main/java/com/yahoo/search/searchers
diff options
context:
space:
mode:
authorJon Bratseth <bratseth@verizonmedia.com>2020-03-11 14:12:24 +0100
committerJon Bratseth <bratseth@verizonmedia.com>2020-03-11 14:12:24 +0100
commit9066658d74a995ae960b0bee919f0a698bb720b8 (patch)
tree7a828ca0fc85579c3922f76636c6f58a68701677 /container-search/src/main/java/com/yahoo/search/searchers
parent3da641f5e5295f0f67ebf062618464327c2d7f40 (diff)
Validate before prepare to avoid depending on the properties API
Diffstat (limited to 'container-search/src/main/java/com/yahoo/search/searchers')
-rw-r--r--container-search/src/main/java/com/yahoo/search/searchers/ValidateNearestNeighborSearcher.java92
1 files changed, 19 insertions, 73 deletions
diff --git a/container-search/src/main/java/com/yahoo/search/searchers/ValidateNearestNeighborSearcher.java b/container-search/src/main/java/com/yahoo/search/searchers/ValidateNearestNeighborSearcher.java
index 0f7f163dce0..76b8c1ef8a2 100644
--- a/container-search/src/main/java/com/yahoo/search/searchers/ValidateNearestNeighborSearcher.java
+++ b/container-search/src/main/java/com/yahoo/search/searchers/ValidateNearestNeighborSearcher.java
@@ -6,24 +6,18 @@ import com.google.common.annotations.Beta;
import com.yahoo.prelude.query.Item;
import com.yahoo.prelude.query.NearestNeighborItem;
-import com.yahoo.prelude.query.QueryCanonicalizer;
import com.yahoo.prelude.query.ToolBox;
-import com.yahoo.processing.request.CompoundName;
import com.yahoo.search.Query;
import com.yahoo.search.Result;
import com.yahoo.search.Searcher;
-import com.yahoo.search.query.profile.QueryProfileProperties;
-import com.yahoo.search.query.profile.compiled.CompiledQueryProfile;
-import com.yahoo.search.query.profile.types.FieldDescription;
-import com.yahoo.search.query.profile.types.QueryProfileFieldType;
-import com.yahoo.search.query.profile.types.QueryProfileType;
+import com.yahoo.search.grouping.vespa.GroupingExecutor;
import com.yahoo.search.query.ranking.RankProperties;
import com.yahoo.search.result.ErrorMessage;
import com.yahoo.search.searchchain.Execution;
import com.yahoo.tensor.Tensor;
import com.yahoo.tensor.TensorType;
import com.yahoo.vespa.config.search.AttributesConfig;
-import com.yahoo.yolean.chain.After;
+import com.yahoo.yolean.chain.Before;
import java.util.HashMap;
import java.util.List;
@@ -36,9 +30,7 @@ import java.util.Optional;
* @author arnej
*/
@Beta
-// This depends on tensors in query.getRanking which are moved to rank.properties during query.prepare()
-// Query.prepare is done at the same time as canonicalization (by GroupingExecutor), so use that constraint.
-@After(QueryCanonicalizer.queryCanonicalization)
+@Before(GroupingExecutor.COMPONENT_NAME) // Must happen before query.prepare()
public class ValidateNearestNeighborSearcher extends Searcher {
private Map<String, TensorType> validAttributes = new HashMap<>();
@@ -104,76 +96,30 @@ public class ValidateNearestNeighborSearcher extends Searcher {
/** Returns an error message if this is invalid, or null if it is valid */
private String validate(NearestNeighborItem item) {
- int target = item.getTargetNumHits();
- if (target < 1) return item + " has invalid targetNumHits";
-
- List<Object> rankPropValList = rankProperties.asMap().get(item.getQueryTensorName());
- if (rankPropValList == null) return item + " query tensor not found";
- if (rankPropValList.size() != 1) return item + " query tensor does not have a single value";
-
- Object rankPropValue = rankPropValList.get(0);
- if (! (rankPropValue instanceof Tensor)) {
- return item + " expected a query tensor but got " +
- (rankPropValue == null ? "null" : rankPropValue.getClass()) +
- resolvedTypeInfo();
- }
+ if (item.getTargetNumHits() < 1)
+ return item + " has invalid targetNumHits " + item.getTargetNumHits() + ": Must be >= 1";
- String field = item.getIndexName();
- if ( ! validAttributes.containsKey(field)) return item + " field is not an attribute";
+ String queryFeatureName = "query(" + item.getQueryTensorName() + ")";
+ Optional<Tensor> queryTensor = query.getRanking().getFeatures().getTensor(queryFeatureName);
+ if (queryTensor.isEmpty())
+ return item + " requires a tensor rank feature " + queryFeatureName + " but this is not present";
+
+ if ( ! validAttributes.containsKey(item.getIndexName()))
+ return item + " field is not an attribute";
+ TensorType fieldType = validAttributes.get(item.getIndexName());
+ if (fieldType == null) return item + " field is not a tensor";
+ if ( ! isDenseVector(fieldType))
+ return item + " tensor type " + fieldType + " is not a dense vector";
+
+ if ( ! isCompatible(fieldType, queryTensor.get().type()))
+ return item + " field type " + fieldType + " does not match query type " + queryTensor.get().type();
- TensorType fTensorType = validAttributes.get(field);
- TensorType qTensorType = ((Tensor)rankPropValue).type();
- if (fTensorType == null) return item + " field is not a tensor";
- if ( ! isCompatible(fTensorType, qTensorType)) {
- return item + " field type " + fTensorType + " does not match query tensor type " + qTensorType;
- }
- if (! isDenseVector(fTensorType)) return item + " tensor type " + fTensorType+" is not a dense vector";
return null;
}
@Override
public void onExit() {}
- // TODO: Remove
- private String resolvedTypeInfo() {
- StringBuilder b = new StringBuilder();
- QueryProfileProperties properties = query.properties().getInstance(QueryProfileProperties.class);
- if (properties == null) return b.toString();
- CompiledQueryProfile profile = properties.getQueryProfile();
- b.append(", profile: ").append(profile);
-
- CompoundName name = new CompoundName("ranking.features.query(q_vec)");
-
- if ( ! profile.getTypes().isEmpty()) {
- QueryProfileType type = null;
- for (int i = 0; i < name.size(); i++) {
- if (type == null) // We're on the first iteration, or no type is explicitly specified
- type = profile.getType(name.first(i), new HashMap<>());
- if (type == null) continue;
- String localName = name.get(i);
- FieldDescription fieldDescription = type.getField(localName);
- if (fieldDescription == null && type.isStrict())
- throw new IllegalArgumentException("'" + localName + "' is not declared in " + type + ", and the type is strict");
-
- // TODO: In addition to strictness, check legality along the way
-
- if (fieldDescription != null) {
- if (i == name.size() - 1) { // at the end of the path, check the assignment type
- b.append(", field description: ").append(fieldDescription);
- } else if (fieldDescription.getType() instanceof QueryProfileFieldType) {
- // If a type is specified, use that instead of the type implied by the name
- type = ((QueryProfileFieldType) fieldDescription.getType()).getQueryProfileType();
- }
- }
-
- }
- }
- else {
- b.append(", profile types is empty");
- }
- return b.toString();
- }
-
}
}