diff options
Diffstat (limited to 'container-search/src/main/java')
19 files changed, 218 insertions, 67 deletions
diff --git a/container-search/src/main/java/com/yahoo/prelude/query/parser/StructuredParser.java b/container-search/src/main/java/com/yahoo/prelude/query/parser/StructuredParser.java index 54a6e5b6e90..f993c7a9e02 100644 --- a/container-search/src/main/java/com/yahoo/prelude/query/parser/StructuredParser.java +++ b/container-search/src/main/java/com/yahoo/prelude/query/parser/StructuredParser.java @@ -333,6 +333,7 @@ abstract class StructuredParser extends AbstractParser { if (tokens.currentIs(NUMBER)) { rangeEnd = (negative ? "-" : "") + tokens.next().toString() + decimalPart(); } + if (rangeStart.isBlank() && rangeEnd.isBlank()) return null; String range = "[" + rangeStart + ";" + rangeEnd; diff --git a/container-search/src/main/java/com/yahoo/search/Query.java b/container-search/src/main/java/com/yahoo/search/Query.java index 48885e4b3da..3a2bccf017e 100644 --- a/container-search/src/main/java/com/yahoo/search/Query.java +++ b/container-search/src/main/java/com/yahoo/search/Query.java @@ -438,7 +438,7 @@ public class Query extends com.yahoo.processing.Request implements Cloneable { for (FieldDescription field : arguments.fields().values()) { if (field.getType() == FieldType.genericQueryProfileType) { // Generic map - CompoundName fullName = prefix.append(field.getName()); + CompoundName fullName = prefix.append(field.getCompoundName()); for (Map.Entry<String, Object> entry : originalProperties.listProperties(fullName, context).entrySet()) { properties().set(fullName.append(entry.getKey()), entry.getValue(), context); } @@ -447,7 +447,7 @@ public class Query extends com.yahoo.processing.Request implements Cloneable { setFrom(prefix, originalProperties, ((QueryProfileFieldType)field.getType()).getQueryProfileType(), context); } else { - CompoundName fullName = prefix.append(field.getName()); + CompoundName fullName = prefix.append(field.getCompoundName()); Object value = originalProperties.get(fullName, context); if (value != null) { properties().set(fullName, value, context); diff --git a/container-search/src/main/java/com/yahoo/search/dispatch/searchcluster/Group.java b/container-search/src/main/java/com/yahoo/search/dispatch/searchcluster/Group.java index af9834e282a..d30abd1d047 100644 --- a/container-search/src/main/java/com/yahoo/search/dispatch/searchcluster/Group.java +++ b/container-search/src/main/java/com/yahoo/search/dispatch/searchcluster/Group.java @@ -74,7 +74,7 @@ public class Group { long average = activeDocs / numWorkingNodes; long skew = nodes.stream().filter(node -> node.isWorking() == Boolean.TRUE).mapToLong(node -> Math.abs(node.getActiveDocuments() - average)).sum(); boolean balanced = skew <= activeDocs * maxContentSkew; - if (!isBalanced.get() || balanced != isBalanced.get()) { + if (balanced != isBalanced.get()) { if (!isSparse()) log.info("Content in " + this + ", with " + numWorkingNodes + "/" + nodes.size() + " working nodes, is " + (balanced ? "" : "not ") + "well balanced. Current deviation: " + skew * 100 / activeDocs + diff --git a/container-search/src/main/java/com/yahoo/search/grouping/GroupingQueryParser.java b/container-search/src/main/java/com/yahoo/search/grouping/GroupingQueryParser.java index 36a8b7812ba..54194221958 100644 --- a/container-search/src/main/java/com/yahoo/search/grouping/GroupingQueryParser.java +++ b/container-search/src/main/java/com/yahoo/search/grouping/GroupingQueryParser.java @@ -50,25 +50,14 @@ public class GroupingQueryParser extends Searcher { @Override public Result search(Query query, Execution execution) { try { - if (query.getHttpRequest().getProperty(GROUPING_GLOBAL_MAX_GROUPS.toString()) != null) { - throw new IllegalInputException(GROUPING_GLOBAL_MAX_GROUPS + " must be specified in a query profile."); - } + validate(query); String reqParam = query.properties().getString(PARAM_REQUEST); if (reqParam == null) return execution.search(query); List<Continuation> continuations = getContinuations(query.properties().getString(PARAM_CONTINUE)); - TimeZone zone = getTimeZone(query.properties().getString(PARAM_TIMEZONE, "utc")); - for (GroupingOperation op : GroupingOperation.fromStringAsList(reqParam)) { - GroupingRequest grpRequest = GroupingRequest.newInstance(query); - grpRequest.setRootOperation(op); - grpRequest.setTimeZone(zone); - grpRequest.continuations().addAll(continuations); - intProperty(query, PARAM_DEFAULT_MAX_GROUPS).ifPresent(grpRequest::setDefaultMaxGroups); - intProperty(query, PARAM_DEFAULT_MAX_HITS).ifPresent(grpRequest::setDefaultMaxHits); - longProperty(query, GROUPING_GLOBAL_MAX_GROUPS).ifPresent(grpRequest::setGlobalMaxGroups); - doubleProperty(query, PARAM_DEFAULT_PRECISION_FACTOR).ifPresent(grpRequest::setDefaultPrecisionFactor); - } + for (GroupingOperation operation : GroupingOperation.fromStringAsList(reqParam)) + createGroupingRequestIn(query, operation, continuations); return execution.search(query); } catch (IllegalArgumentException e) { @@ -76,6 +65,22 @@ public class GroupingQueryParser extends Searcher { } } + public static void validate(Query query) { + if (query.getHttpRequest().getProperty(GROUPING_GLOBAL_MAX_GROUPS.toString()) != null) + throw new IllegalInputException(GROUPING_GLOBAL_MAX_GROUPS + " must be specified in a query profile."); + } + + public static void createGroupingRequestIn(Query query, GroupingOperation operation, List<Continuation> continuations) { + GroupingRequest request = GroupingRequest.newInstance(query); + request.setRootOperation(operation); + request.setTimeZone(getTimeZone(query.properties().getString(PARAM_TIMEZONE, "utc"))); + request.continuations().addAll(continuations); + intProperty(query, PARAM_DEFAULT_MAX_GROUPS).ifPresent(request::setDefaultMaxGroups); + intProperty(query, PARAM_DEFAULT_MAX_HITS).ifPresent(request::setDefaultMaxHits); + longProperty(query, GROUPING_GLOBAL_MAX_GROUPS).ifPresent(request::setGlobalMaxGroups); + doubleProperty(query, PARAM_DEFAULT_PRECISION_FACTOR).ifPresent(request::setDefaultPrecisionFactor); + } + private List<Continuation> getContinuations(String param) { if (param == null) { return Collections.emptyList(); @@ -87,7 +92,7 @@ public class GroupingQueryParser extends Searcher { return ret; } - private TimeZone getTimeZone(String name) { + private static TimeZone getTimeZone(String name) { ZoneCache cache = zoneCache.get(); if (cache == null) { cache = new ZoneCache(); diff --git a/container-search/src/main/java/com/yahoo/search/grouping/vespa/RequestBuilder.java b/container-search/src/main/java/com/yahoo/search/grouping/vespa/RequestBuilder.java index e43067ade62..2280ea01263 100644 --- a/container-search/src/main/java/com/yahoo/search/grouping/vespa/RequestBuilder.java +++ b/container-search/src/main/java/com/yahoo/search/grouping/vespa/RequestBuilder.java @@ -406,8 +406,9 @@ class RequestBuilder { } private void validateGlobalMax() { - this.totalGroupsAndSummaries = -1; if (globalMaxGroups < 0) return; + + this.totalGroupsAndSummaries = -1; int totalGroupsAndSummaries = 0; for (Grouping grp : requestList) { int levelMultiplier = 1; diff --git a/container-search/src/main/java/com/yahoo/search/handler/Json2SingleLevelMap.java b/container-search/src/main/java/com/yahoo/search/handler/Json2SingleLevelMap.java index 5b8c99506c5..bf0272f4f66 100644 --- a/container-search/src/main/java/com/yahoo/search/handler/Json2SingleLevelMap.java +++ b/container-search/src/main/java/com/yahoo/search/handler/Json2SingleLevelMap.java @@ -22,7 +22,7 @@ import java.util.Map; * @author baldersheim */ class Json2SingleLevelMap { - private static final ObjectMapper jsonMapper = new ObjectMapper(); + private static final ObjectMapper jsonMapper = new ObjectMapper().configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true); private final byte [] buf; private final JsonParser parser; Json2SingleLevelMap(InputStream data) { diff --git a/container-search/src/main/java/com/yahoo/search/handler/SearchHandler.java b/container-search/src/main/java/com/yahoo/search/handler/SearchHandler.java index 76702a1d4e0..3da3f57cb21 100644 --- a/container-search/src/main/java/com/yahoo/search/handler/SearchHandler.java +++ b/container-search/src/main/java/com/yahoo/search/handler/SearchHandler.java @@ -41,7 +41,6 @@ import com.yahoo.search.searchchain.ExecutionFactory; import com.yahoo.search.searchchain.SearchChainRegistry; import com.yahoo.search.statistics.ElapsedTime; import com.yahoo.slime.Inspector; -import com.yahoo.slime.ObjectTraverser; import com.yahoo.yolean.Exceptions; import com.yahoo.yolean.trace.TraceNode; diff --git a/container-search/src/main/java/com/yahoo/search/handler/observability/SearchStatusExtension.java b/container-search/src/main/java/com/yahoo/search/handler/observability/SearchStatusExtension.java new file mode 100644 index 00000000000..836bb1b8354 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/handler/observability/SearchStatusExtension.java @@ -0,0 +1,32 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.handler.observability; + +import com.fasterxml.jackson.databind.JsonNode; +import com.yahoo.container.handler.observability.ApplicationStatusHandler; +import com.yahoo.jdisc.handler.RequestHandler; +import com.yahoo.search.handler.SearchHandler; +import com.yahoo.search.searchchain.SearchChainRegistry; + +import java.util.Map; + +/** + * @author bjorncs + */ +public class SearchStatusExtension implements ApplicationStatusHandler.Extension { + + @Override + public Map<String, ? extends JsonNode> produceExtraFields(ApplicationStatusHandler statusHandler) { + return Map.of("searchChains", renderSearchChains(statusHandler)); + } + + private static JsonNode renderSearchChains(ApplicationStatusHandler statusHandler) { + for (RequestHandler h : statusHandler.requestHandlers()) { + if (h instanceof SearchHandler) { + SearchChainRegistry scReg = ((SearchHandler) h).getSearchChainRegistry(); + return ApplicationStatusHandler.renderChains(scReg); + } + } + return statusHandler.jsonMapper().createObjectNode(); + } + +} diff --git a/container-search/src/main/java/com/yahoo/search/handler/observability/package-info.java b/container-search/src/main/java/com/yahoo/search/handler/observability/package-info.java new file mode 100644 index 00000000000..baf24b4a94d --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/handler/observability/package-info.java @@ -0,0 +1,8 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +/** + * @author bjorncs + */ +@ExportPackage +package com.yahoo.search.handler.observability; + +import com.yahoo.osgi.annotation.ExportPackage;
\ No newline at end of file diff --git a/container-search/src/main/java/com/yahoo/search/query/profile/ChainedMap.java b/container-search/src/main/java/com/yahoo/search/query/profile/ChainedMap.java new file mode 100644 index 00000000000..3ec9a3c41b8 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/query/profile/ChainedMap.java @@ -0,0 +1,107 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.query.profile; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * A read-only map which forwards lookups to a primary map, and then a secondary for + * keys not existing in the primary. + * + * @author bratseth + */ +class ChainedMap<K, V> implements Map<K, V> { + + private final Map<K, V> primary, secondary; + + ChainedMap(Map<K, V> primary, Map<K, V> secondary) { + this.primary = primary; + this.secondary = secondary; + } + + @Override + public int size() { + return (primary.size() >= secondary.size()) + ? countUnique(primary, secondary) + : countUnique(secondary, primary); + } + + private int countUnique(Map<K, V> large, Map<K,V> small) { + int size = large.size(); + for (K key : small.keySet()) { + if ( ! large.containsKey(key)) size++; + } + return size; + } + + @Override + public boolean isEmpty() { + return primary.isEmpty() && secondary.isEmpty(); + } + + @Override + public boolean containsKey(Object key) { + return primary.containsKey(key) || secondary.containsKey(key); + } + + @Override + public boolean containsValue(Object value) { + return primary.containsValue(value) || secondary.containsValue(value); + } + + @Override + public V get(Object key) { + V value = primary.get(key); + return value != null ? value : secondary.get(key); + } + + @Override + public V put(K key, V value) { + throw new UnsupportedOperationException(); + } + + @Override + public V remove(Object key) { + throw new UnsupportedOperationException(); + } + + @Override + public void putAll(Map<? extends K, ? extends V> m) { + throw new UnsupportedOperationException(); + } + + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + @Override + public Set<K> keySet() { + var keys = new HashSet<>(secondary.keySet()); + keys.addAll(primary.keySet()); + return keys; + } + + @Override + public Collection<V> values() { + throw new UnsupportedOperationException(); + } + + @Override + public Set<Entry<K, V>> entrySet() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean equals(Object o) { + throw new UnsupportedOperationException(); + } + + @Override + public int hashCode() { + throw new UnsupportedOperationException(); + } + +} diff --git a/container-search/src/main/java/com/yahoo/search/query/profile/QueryProfileProperties.java b/container-search/src/main/java/com/yahoo/search/query/profile/QueryProfileProperties.java index 7f5df94d020..224f75e7034 100644 --- a/container-search/src/main/java/com/yahoo/search/query/profile/QueryProfileProperties.java +++ b/container-search/src/main/java/com/yahoo/search/query/profile/QueryProfileProperties.java @@ -300,13 +300,7 @@ public class QueryProfileProperties extends Properties { if (zoneInfo == ZoneInfo.defaultInfo()) return context; if (context == null || context.isEmpty()) return zoneContext; if (context == zoneContext) return context; - if (context.containsKey(ENVIRONMENT) && context.containsKey(REGION) && context.containsKey(INSTANCE)) return context; - - Map<String, String> contextWithZoneInfo = new HashMap<>(context); - contextWithZoneInfo.putIfAbsent(ENVIRONMENT, zoneInfo.zone().environment().name()); - contextWithZoneInfo.putIfAbsent(REGION, zoneInfo.zone().region()); - contextWithZoneInfo.putIfAbsent(INSTANCE, zoneInfo.application().instance()); - return Collections.unmodifiableMap(contextWithZoneInfo); + return new ChainedMap(context, zoneContext); } private boolean reachableTypesAreComplete(CompoundName prefix, CompiledQueryProfile profile, StringBuilder firstMissingName, Map<String,String> context) { diff --git a/container-search/src/main/java/com/yahoo/search/query/profile/config/QueryProfileConfigurer.java b/container-search/src/main/java/com/yahoo/search/query/profile/config/QueryProfileConfigurer.java index 31278af9579..5b30e3c383d 100644 --- a/container-search/src/main/java/com/yahoo/search/query/profile/config/QueryProfileConfigurer.java +++ b/container-search/src/main/java/com/yahoo/search/query/profile/config/QueryProfileConfigurer.java @@ -21,6 +21,7 @@ import java.util.Set; */ public class QueryProfileConfigurer { + @SuppressWarnings("deprecation") public static QueryProfileRegistry createFromConfigId(String configId) { return createFromConfig(ConfigGetter.getConfig(QueryProfilesConfig.class, configId)); } diff --git a/container-search/src/main/java/com/yahoo/search/query/ranking/RankFeatures.java b/container-search/src/main/java/com/yahoo/search/query/ranking/RankFeatures.java index 5fed5f13c64..51be79f8c2e 100644 --- a/container-search/src/main/java/com/yahoo/search/query/ranking/RankFeatures.java +++ b/container-search/src/main/java/com/yahoo/search/query/ranking/RankFeatures.java @@ -75,7 +75,9 @@ public class RankFeatures implements Cloneable { Object feature = features.get(name); if (feature == null) return OptionalDouble.empty(); if (feature instanceof Double) return OptionalDouble.of((Double)feature); - throw new IllegalArgumentException("Expected a double value of '" + name + "' but has " + feature); + throw new IllegalArgumentException("Expected '" + name + "' to be a double, but it is " + + (feature instanceof Tensor ? "the tensor " + ((Tensor)feature).toAbbreviatedString() : + "the string '" + feature + "'")); } /** @@ -88,7 +90,7 @@ public class RankFeatures implements Cloneable { if (feature == null) return Optional.empty(); if (feature instanceof Tensor) return Optional.of((Tensor)feature); if (feature instanceof Double) return Optional.of(Tensor.from((Double)feature)); - throw new IllegalArgumentException("Expected a tensor value of '" + name + "' but has " + feature); + throw new IllegalArgumentException("Expected '" + name + "' to be a tensor, but it is the string '" + feature + "'"); } /** @@ -100,9 +102,9 @@ public class RankFeatures implements Cloneable { Object feature = features.get(name); if (feature == null) return Optional.empty(); if (feature instanceof String) return Optional.of((String)feature); - // TODO: Use toShortString for tensors below - throw new IllegalArgumentException("Expected a string value of '" + name + "' but has " + - (feature instanceof Tensor ? ((Tensor)feature).toString() : feature)); + throw new IllegalArgumentException("Expected '" + name + "' to be a string, but it is " + + (feature instanceof Tensor ? "the tensor " + ((Tensor)feature).toAbbreviatedString() : + "the double " + feature)); } diff --git a/container-search/src/main/java/com/yahoo/search/querytransform/WeakAndReplacementSearcher.java b/container-search/src/main/java/com/yahoo/search/querytransform/WeakAndReplacementSearcher.java index b47b54bc362..898e348db92 100644 --- a/container-search/src/main/java/com/yahoo/search/querytransform/WeakAndReplacementSearcher.java +++ b/container-search/src/main/java/com/yahoo/search/querytransform/WeakAndReplacementSearcher.java @@ -1,7 +1,10 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.search.querytransform; -import com.yahoo.prelude.query.*; +import com.yahoo.prelude.query.CompositeItem; +import com.yahoo.prelude.query.Item; +import com.yahoo.prelude.query.OrItem; +import com.yahoo.prelude.query.WeakAndItem; import com.yahoo.processing.request.CompoundName; import com.yahoo.search.Query; import com.yahoo.search.Result; @@ -15,7 +18,8 @@ import com.yahoo.search.searchchain.Execution; * @author karowan */ public class WeakAndReplacementSearcher extends Searcher { - private static final CompoundName WEAKAND_REPLACE = new CompoundName("weakAnd.replace"); + static final CompoundName WEAKAND_REPLACE = new CompoundName("weakAnd.replace"); + static final CompoundName WAND_HITS = new CompoundName("wand.hits"); @Override public Result search(Query query, Execution execution) { if (!query.properties().getBoolean(WEAKAND_REPLACE)) { @@ -31,7 +35,7 @@ public class WeakAndReplacementSearcher extends Searcher { */ private void replaceOrItems(Query query) { Item root = query.getModel().getQueryTree().getRoot(); - int hits = query.properties().getInteger("wand.hits", WeakAndItem.defaultN); + int hits = query.properties().getInteger(WAND_HITS, WeakAndItem.defaultN); query.getModel().getQueryTree().setRoot(replaceOrItems(root, hits)); if (root != query.getModel().getQueryTree().getRoot()) query.trace("Replaced OR by WeakAnd", true, 2); @@ -45,10 +49,9 @@ public class WeakAndReplacementSearcher extends Searcher { * @return the original item or a WeakAndItem replacement of an OrItem */ private Item replaceOrItems(Item item, int hits) { - if (!(item instanceof CompositeItem)) { + if (!(item instanceof CompositeItem compositeItem)) { return item; } - CompositeItem compositeItem = (CompositeItem) item; if (compositeItem instanceof OrItem) { WeakAndItem newItem = new WeakAndItem(hits); newItem.setWeight(compositeItem.getWeight()); diff --git a/container-search/src/main/java/com/yahoo/search/searchchain/model/VespaSearchers.java b/container-search/src/main/java/com/yahoo/search/searchchain/model/VespaSearchers.java index 85b8a563a9e..110f69c19ca 100644 --- a/container-search/src/main/java/com/yahoo/search/searchchain/model/VespaSearchers.java +++ b/container-search/src/main/java/com/yahoo/search/searchchain/model/VespaSearchers.java @@ -78,7 +78,7 @@ public class VespaSearchers { for (Class c : searchers) { searcherModels.add( new ChainedComponentModel( - BundleInstantiationSpecification.getInternalSearcherSpecificationFromStrings(c.getName(), null), + BundleInstantiationSpecification.fromSearchAndDocproc(c.getName()), Dependencies.emptyDependencies())); } return searcherModels; diff --git a/container-search/src/main/java/com/yahoo/search/searchchain/model/federation/FederationSearcherModel.java b/container-search/src/main/java/com/yahoo/search/searchchain/model/federation/FederationSearcherModel.java index ea8275760dc..8acac776ae8 100644 --- a/container-search/src/main/java/com/yahoo/search/searchchain/model/federation/FederationSearcherModel.java +++ b/container-search/src/main/java/com/yahoo/search/searchchain/model/federation/FederationSearcherModel.java @@ -24,9 +24,11 @@ public class FederationSearcherModel extends ChainedComponentModel { public final List<TargetSpec> targets; public final boolean inheritDefaultSources; - public FederationSearcherModel(ComponentSpecification componentId, Dependencies dependencies, - List<TargetSpec> targets, boolean inheritDefaultSources) { - super(BundleInstantiationSpecification.getInternalSearcherSpecification(componentId, federationSearcherComponentSpecification), + public FederationSearcherModel(ComponentSpecification componentId, + Dependencies dependencies, + List<TargetSpec> targets, + boolean inheritDefaultSources) { + super(BundleInstantiationSpecification.fromSearchAndDocproc(componentId, federationSearcherComponentSpecification), dependencies); this.inheritDefaultSources = inheritDefaultSources; this.targets = ImmutableList.copyOf(targets); diff --git a/container-search/src/main/java/com/yahoo/search/searchchain/model/federation/LocalProviderSpec.java b/container-search/src/main/java/com/yahoo/search/searchchain/model/federation/LocalProviderSpec.java index 3c2767430c7..c4e5f26a3eb 100644 --- a/container-search/src/main/java/com/yahoo/search/searchchain/model/federation/LocalProviderSpec.java +++ b/container-search/src/main/java/com/yahoo/search/searchchain/model/federation/LocalProviderSpec.java @@ -63,9 +63,7 @@ public class LocalProviderSpec { for (Class<? extends Searcher> c : searchers) { searcherModels.add( new ChainedComponentModel( - BundleInstantiationSpecification.getInternalSearcherSpecificationFromStrings( - c.getName(), - null), + BundleInstantiationSpecification.fromSearchAndDocproc(c.getName()), Dependencies.emptyDependencies())); } diff --git a/container-search/src/main/java/com/yahoo/search/yql/MinimalQueryInserter.java b/container-search/src/main/java/com/yahoo/search/yql/MinimalQueryInserter.java index 48c48748563..e844bac21e8 100644 --- a/container-search/src/main/java/com/yahoo/search/yql/MinimalQueryInserter.java +++ b/container-search/src/main/java/com/yahoo/search/yql/MinimalQueryInserter.java @@ -10,7 +10,7 @@ import com.yahoo.search.Query; import com.yahoo.search.Result; import com.yahoo.search.Searcher; import com.yahoo.processing.request.CompoundName; -import com.yahoo.search.grouping.GroupingRequest; +import com.yahoo.search.grouping.GroupingQueryParser; import com.yahoo.search.query.QueryTree; import com.yahoo.search.query.parser.Parsable; import com.yahoo.search.query.parser.ParserEnvironment; @@ -116,11 +116,11 @@ public class MinimalQueryInserter extends Searcher { } query.getModel().getQueryTree().setRoot(newTree.getRoot()); query.getPresentation().getSummaryFields().addAll(parser.getYqlSummaryFields()); - for (VespaGroupingStep step : parser.getGroupingSteps()) { - GroupingRequest.newInstance(query) - .setRootOperation(step.getOperation()) - .continuations().addAll(step.continuations()); - } + + GroupingQueryParser.validate(query); + for (VespaGroupingStep step : parser.getGroupingSteps()) + GroupingQueryParser.createGroupingRequestIn(query, step.getOperation(), step.continuations()); + if (parser.getYqlSources().size() == 0) { query.getModel().getSources().clear(); } else { diff --git a/container-search/src/main/java/com/yahoo/search/yql/YqlParser.java b/container-search/src/main/java/com/yahoo/search/yql/YqlParser.java index a149ae9323a..384be7798fa 100644 --- a/container-search/src/main/java/com/yahoo/search/yql/YqlParser.java +++ b/container-search/src/main/java/com/yahoo/search/yql/YqlParser.java @@ -106,7 +106,7 @@ public class YqlParser implements Parser { public static final String ASCENDING_HITS_ORDER = "ascending"; private enum SegmentWhen { - NEVER, POSSIBLY, ALWAYS; + NEVER, POSSIBLY, ALWAYS } private static class IndexNameExpander { @@ -290,7 +290,7 @@ public class YqlParser implements Parser { Preconditions.checkArgument(filterPart.getArguments().length == 2, "Expected 2 arguments to filter, got %s.", filterPart.getArguments().length); - populateYqlSources(filterPart.<OperatorNode<?>> getArgument(0)); + populateYqlSources(filterPart.getArgument(0)); OperatorNode<ExpressionOperator> filterExpression = filterPart.getArgument(1); Item root = convertExpression(filterExpression); connectItems(); @@ -617,6 +617,8 @@ public class YqlParser implements Parser { // All terms below sameElement are relative to this. IndexNameExpander prev = swapIndexCreator(new PrefixExpander(field)); for (OperatorNode<ExpressionOperator> term : ast.<List<OperatorNode<ExpressionOperator>>> getArgument(1)) { + // TODO getIndex that is called once every term is rather expensive as it does sanity checking + // that is not necessary. This is an issue when having many elements sameElement.addItem(convertExpression(term)); } swapIndexCreator(prev); @@ -838,7 +840,7 @@ public class YqlParser implements Parser { OperatorNode<?> ast = toScan; while (ast.getOperator() == SequenceOperator.PIPE) { OperatorNode<ExpressionOperator> groupingAst = ast.<List<OperatorNode<ExpressionOperator>>> getArgument(2).get(0); - GroupingOperation groupingOperation = GroupingOperation.fromString(groupingAst.<String> getArgument(0)); + GroupingOperation groupingOperation = GroupingOperation.fromString(groupingAst.getArgument(0)); VespaGroupingStep groupingStep = new VespaGroupingStep(groupingOperation); List<Object> continuations = getAnnotation(groupingAst, "continuations", List.class, Collections.emptyList(), "grouping continuations"); @@ -854,8 +856,7 @@ public class YqlParser implements Parser { } private String dereference(Object constantOrVarref) { - if (constantOrVarref instanceof OperatorNode) { - OperatorNode<?> varref = (OperatorNode<?>)constantOrVarref; + if (constantOrVarref instanceof OperatorNode<?> varref) { Preconditions.checkState(userQuery != null, "properties must be available when trying to fetch user input"); return userQuery.properties().getString(varref.getArgument(0, String.class)); @@ -871,7 +872,7 @@ public class YqlParser implements Parser { List<FieldOrder> sortingInit = new ArrayList<>(); List<OperatorNode<?>> sortArguments = ast.getArgument(1); for (OperatorNode<?> op : sortArguments) { - OperatorNode<ExpressionOperator> fieldNode = op.<OperatorNode<ExpressionOperator>> getArgument(0); + OperatorNode<ExpressionOperator> fieldNode = op.getArgument(0); String field = fetchFieldRead(fieldNode); String locale = getAnnotation(fieldNode, SORTING_LOCALE, String.class, null, "locale used by sorting function"); @@ -963,7 +964,7 @@ public class YqlParser implements Parser { Preconditions.checkArgument(ast.getArguments().length == 2, "Expected 2 arguments to PROJECT, got %s.", ast.getArguments().length); - populateYqlSummaryFields(ast.<List<OperatorNode<ProjectOperator>>> getArgument(1)); + populateYqlSummaryFields(ast.getArgument(1)); return ast.getArgument(0); } @@ -1127,7 +1128,6 @@ public class YqlParser implements Parser { return convertVarArgs(spec, 0, new OrItem()); } - @SuppressWarnings("deprecation") private CompositeItem buildWeakAnd(OperatorNode<ExpressionOperator> spec) { WeakAndItem weakAnd = new WeakAndItem(); Integer targetNumHits = getAnnotation(spec, TARGET_HITS, @@ -1175,7 +1175,7 @@ public class YqlParser implements Parser { if (userQuery != null && indexFactsSession.getIndex(field).isAttribute()) { userQuery.trace("Field '" + field + "' is an attribute, 'contains' will only match exactly (unless fuzzy is used)", 2); } - return instantiateLeafItem(field, ast.<OperatorNode<ExpressionOperator>> getArgument(1)); + return instantiateLeafItem(field, ast.getArgument(1)); } private Item buildRegExpSearch(OperatorNode<ExpressionOperator> ast) { @@ -1468,7 +1468,7 @@ public class YqlParser implements Parser { wordItem = new WordItem(wordData, fromQuery); break; case POSSIBLY: - if (shouldSegment(field, ast, fromQuery) && ! grammar.equals(USER_INPUT_RAW)) { + if (shouldSegment(field, fromQuery) && ! grammar.equals(USER_INPUT_RAW)) { wordItem = segment(field, ast, wordData, fromQuery, parent, language); } else { wordItem = new WordItem(wordData, fromQuery); @@ -1489,7 +1489,7 @@ public class YqlParser implements Parser { return (Item) leafStyleSettings(ast, wordItem); } - private boolean shouldSegment(String field, OperatorNode<ExpressionOperator> ast, boolean fromQuery) { + private boolean shouldSegment(String field, boolean fromQuery) { return fromQuery && ! indexFactsSession.getIndex(indexNameExpander.expand(field)).isAttribute(); } @@ -1584,8 +1584,7 @@ public class YqlParser implements Parser { leaf.setWeight(weight); } } - if (out instanceof IntItem) { - IntItem number = (IntItem) out; + if (out instanceof IntItem number) { Integer hitLimit = getCappedRangeSearchParameter(ast); if (hitLimit != null) { number.setHitLimit(hitLimit); @@ -1822,7 +1821,7 @@ public class YqlParser implements Parser { Object value = ast.getAnnotation(key); for (Iterator<OperatorNode<?>> i = annotationStack.iterator(); value == null && considerParents && i.hasNext();) { - OperatorNode node = i.next(); + OperatorNode<?> node = i.next(); if (node.getOperator() == ExpressionOperator.VARREF) { Preconditions.checkState(userQuery != null, "properties must be available when trying to fetch user input"); @@ -1886,8 +1885,7 @@ public class YqlParser implements Parser { @Override public boolean visit(Item item) { - if (item instanceof WordItem) { - WordItem w = (WordItem) item; + if (item instanceof WordItem w) { if (usePositionData != null) { w.setPositionData(usePositionData); } |