diff options
author | Jon Bratseth <bratseth@verizonmedia.com> | 2019-06-09 12:15:43 +0200 |
---|---|---|
committer | Jon Bratseth <bratseth@verizonmedia.com> | 2019-06-09 12:15:43 +0200 |
commit | 20513f2cb1f9c65406c32dd717e738d394fc1d1b (patch) | |
tree | 8801ffcd7fb2f7f31f66f2ce4db99c6752b909ef /container-search/src | |
parent | 79cd883d5df45dc236e5cebf2c21b5487c791df6 (diff) |
Extract execution creation into ExecutionFactory
Diffstat (limited to 'container-search/src')
8 files changed, 141 insertions, 69 deletions
diff --git a/container-search/src/main/java/com/yahoo/prelude/IndexFacts.java b/container-search/src/main/java/com/yahoo/prelude/IndexFacts.java index 2fcd2466dd8..1fd8cce9889 100644 --- a/container-search/src/main/java/com/yahoo/prelude/IndexFacts.java +++ b/container-search/src/main/java/com/yahoo/prelude/IndexFacts.java @@ -253,11 +253,14 @@ public class IndexFacts { /** * Freeze this to prevent further changes. + * + * @return this for chaining */ - public void freeze() { + public IndexFacts freeze() { hasNGramIndices = hasNGramIndices(); // TODO: Freeze content! frozen = true; + return this; } /** Whether this contains any index which has isNGram()==true. This is free to ask on a frozen instance. */ 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 cb69f2abd07..8e654bf34b8 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 @@ -6,9 +6,6 @@ import com.yahoo.collections.Tuple2; import com.yahoo.component.ComponentSpecification; import com.yahoo.component.Vtag; import com.yahoo.component.chain.Chain; -import com.yahoo.component.chain.ChainsConfigurer; -import com.yahoo.component.chain.model.ChainsModel; -import com.yahoo.component.chain.model.ChainsModelBuilder; import com.yahoo.component.provider.ComponentRegistry; import com.yahoo.container.QrSearchersConfig; import com.yahoo.container.core.ChainsConfig; @@ -24,14 +21,12 @@ import com.yahoo.language.Linguistics; import com.yahoo.log.LogLevel; import com.yahoo.net.HostName; import com.yahoo.net.UriTools; -import com.yahoo.prelude.IndexFacts; -import com.yahoo.prelude.IndexModel; import com.yahoo.prelude.query.QueryException; import com.yahoo.prelude.query.parser.ParseException; -import com.yahoo.prelude.query.parser.SpecialTokenRegistry; import com.yahoo.processing.rendering.Renderer; import com.yahoo.processing.request.CompoundName; import com.yahoo.search.query.ranking.SoftTimeout; +import com.yahoo.search.searchchain.ExecutionFactory; import com.yahoo.slime.Inspector; import com.yahoo.slime.ObjectTraverser; import com.yahoo.vespa.config.SlimeUtils; @@ -46,7 +41,6 @@ import com.yahoo.search.query.profile.compiled.CompiledQueryProfileRegistry; import com.yahoo.search.query.profile.config.QueryProfileConfigurer; import com.yahoo.search.query.profile.config.QueryProfilesConfig; import com.yahoo.search.query.properties.DefaultProperties; -import com.yahoo.search.rendering.RendererRegistry; import com.yahoo.search.result.ErrorMessage; import com.yahoo.search.searchchain.Execution; import com.yahoo.search.searchchain.SearchChainRegistry; @@ -93,19 +87,9 @@ public class SearchHandler extends LoggingRequestHandler { private Value searchConnections; - private final SearchChainRegistry searchChainRegistry; - - private final RendererRegistry rendererRegistry; - - private final IndexFacts indexFacts; - - private final SpecialTokenRegistry specialTokens; - public static final String defaultSearchChainName = "default"; private static final String fallbackSearchChain = "vespa"; - private final Linguistics linguistics; - private final CompiledQueryProfileRegistry queryProfileRegistry; /** If present, responses from this will set the HTTP response header with this key to the host name of this */ @@ -113,6 +97,8 @@ public class SearchHandler extends LoggingRequestHandler { private final String selfHostname = HostName.getLocalhost(); + private final ExecutionFactory executionFactory; + private final class MeanConnections implements Callback { @Override @@ -127,31 +113,19 @@ public class SearchHandler extends LoggingRequestHandler { } @Inject - public SearchHandler(ChainsConfig chainsConfig, - IndexInfoConfig indexInfo, - QrSearchersConfig clusters, - SpecialtokensConfig specialtokens, - Statistics statistics, - Linguistics linguistics, + public SearchHandler(Statistics statistics, Metric metric, - ComponentRegistry<Renderer> renderers, Executor executor, AccessLog accessLog, QueryProfilesConfig queryProfileConfig, - ComponentRegistry<Searcher> searchers, - ContainerHttpConfig containerHttpConfig) { + ContainerHttpConfig containerHttpConfig, + ExecutionFactory executionFactory) { super(executor, accessLog, metric, true); log.log(LogLevel.DEBUG, "SearchHandler.init " + System.identityHashCode(this)); - searchChainRegistry = new SearchChainRegistry(searchers); - setupSearchChainRegistry(searchers, chainsConfig); - indexFacts = new IndexFacts(new IndexModel(indexInfo, clusters)); - indexFacts.freeze(); - specialTokens = new SpecialTokenRegistry(specialtokens); - rendererRegistry = new RendererRegistry(renderers.allComponents()); QueryProfileRegistry queryProfileRegistry = QueryProfileConfigurer.createFromConfig(queryProfileConfig); this.queryProfileRegistry = queryProfileRegistry.compile(); + this.executionFactory = executionFactory; - this.linguistics = linguistics; this.maxThreads = examineExecutor(executor); searchConnections = new Value(SEARCH_CONNECTIONS, statistics, @@ -164,16 +138,28 @@ public class SearchHandler extends LoggingRequestHandler { Optional.empty() : Optional.of( containerHttpConfig.hostResponseHeaderKey()); } - @Override - protected void destroy() { - super.destroy(); - rendererRegistry.deconstruct(); - } - - private void setupSearchChainRegistry(ComponentRegistry<Searcher> searchers, ChainsConfig chainsConfig) { - ChainsModel chainsModel = ChainsModelBuilder.buildFromConfig(chainsConfig); - ChainsConfigurer.prepareChainRegistry(searchChainRegistry, chainsModel, searchers); - searchChainRegistry.freeze(); + /** @deprecated use the other constructor */ + @Deprecated // TODO: Remove on Vespa 8 + public SearchHandler(ChainsConfig chainsConfig, + IndexInfoConfig indexInfo, + QrSearchersConfig clusters, + SpecialtokensConfig specialtokens, + Statistics statistics, + Linguistics linguistics, + Metric metric, + ComponentRegistry<Renderer> renderers, + Executor executor, + AccessLog accessLog, + QueryProfilesConfig queryProfileConfig, + ComponentRegistry<Searcher> searchers, + ContainerHttpConfig containerHttpConfig) { + this(statistics, + metric, + executor, + accessLog, + queryProfileConfig, + containerHttpConfig, + new ExecutionFactory(chainsConfig, indexInfo, clusters, searchers, specialtokens, linguistics, renderers)); } private static int examineExecutor(Executor executor) { @@ -278,7 +264,7 @@ public class SearchHandler extends LoggingRequestHandler { ErrorMessage.createInvalidQueryParameter("No search chain named '" + searchChainName + "' was found")); } else { String pathAndQuery = UriTools.rawRequest(request.getUri()); - result = search(pathAndQuery, query, searchChain, searchChainRegistry); + result = search(pathAndQuery, query, searchChain); } // Transform result to response @@ -301,7 +287,7 @@ public class SearchHandler extends LoggingRequestHandler { @NonNull private Renderer<Result> toRendererCopy(ComponentSpecification format) { - Renderer<Result> renderer = rendererRegistry.getRenderer(format); + Renderer<Result> renderer = executionFactory.rendererRegistry().getRenderer(format); renderer = perRenderingCopy(renderer); return renderer; } @@ -312,28 +298,27 @@ public class SearchHandler extends LoggingRequestHandler { chainName = defaultSearchChainName; } - Chain<Searcher> searchChain = searchChainRegistry.getChain(chainName); + Chain<Searcher> searchChain = executionFactory.searchChainRegistry().getChain(chainName); if (searchChain == null && explicitChainName == null) { // explicit chain not found should cause error chainName = fallbackSearchChain; - searchChain = searchChainRegistry.getChain(chainName); + searchChain = executionFactory.searchChainRegistry().getChain(chainName); } return new Tuple2<>(chainName, searchChain); } /** Used from container SDK, for internal use only */ - public Result searchAndFill(Query query, Chain<? extends Searcher> searchChain, SearchChainRegistry registry) { + public Result searchAndFill(Query query, Chain<? extends Searcher> searchChain) { Result errorResult = validateQuery(query); if (errorResult != null) return errorResult; - Renderer<Result> renderer = rendererRegistry.getRenderer(query.getPresentation().getRenderer()); + Renderer<Result> renderer = executionFactory.rendererRegistry().getRenderer(query.getPresentation().getRenderer()); // docsumClass null means "unset", so we set it (it might be null // here too in which case it will still be "unset" after we set it :-) if (query.getPresentation().getSummary() == null && renderer instanceof com.yahoo.search.rendering.Renderer) query.getPresentation().setSummary(((com.yahoo.search.rendering.Renderer) renderer).getDefaultSummaryClass()); - Execution execution = new Execution(searchChain, - new Execution.Context(registry, indexFacts, specialTokens, rendererRegistry, linguistics)); + Execution execution = executionFactory.newExecution(searchChain); query.getModel().setExecution(execution); execution.trace().setForceTimestamps(query.properties().getBoolean(FORCE_TIMESTAMPS, false)); if (query.properties().getBoolean(DETAILED_TIMING_LOGGING, false)) { @@ -362,7 +347,7 @@ public class SearchHandler extends LoggingRequestHandler { * For internal use only */ public Renderer<Result> getRendererCopy(ComponentSpecification spec) { - Renderer<Result> renderer = rendererRegistry.getRenderer(spec); + Renderer<Result> renderer = executionFactory.rendererRegistry().getRenderer(spec); return perRenderingCopy(renderer); } @@ -380,7 +365,7 @@ public class SearchHandler extends LoggingRequestHandler { } } - private Result search(String request, Query query, Chain<Searcher> searchChain, SearchChainRegistry registry) { + private Result search(String request, Query query, Chain<Searcher> searchChain) { if (query.getTraceLevel() >= 2) { query.trace("Invoking " + searchChain, false, 2); } @@ -393,7 +378,7 @@ public class SearchHandler extends LoggingRequestHandler { new IllegalStateException("searchConnections reference is null.")); } try { - return searchAndFill(query, searchChain, registry); + return searchAndFill(query, searchChain); } catch (ParseException e) { ErrorMessage error = ErrorMessage.createIllegalQuery("Could not parse query [" + request + "]: " + Exceptions.toMessageString(e)); @@ -502,8 +487,7 @@ public class SearchHandler extends LoggingRequestHandler { query.trace("Vespa version: " + Vtag.currentVersion.toString(), false, 4); } - public SearchChainRegistry getSearchChainRegistry() { - return searchChainRegistry; + public SearchChainRegistry getSearchChainRegistry() { return executionFactory.searchChainRegistry(); } static private String getMediaType(HttpRequest request) { diff --git a/container-search/src/main/java/com/yahoo/search/searchchain/ExecutionFactory.java b/container-search/src/main/java/com/yahoo/search/searchchain/ExecutionFactory.java new file mode 100644 index 00000000000..470e74bb974 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/searchchain/ExecutionFactory.java @@ -0,0 +1,79 @@ +// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.searchchain; + +import com.yahoo.component.AbstractComponent; +import com.yahoo.component.chain.Chain; +import com.yahoo.component.chain.ChainsConfigurer; +import com.yahoo.component.chain.model.ChainsModel; +import com.yahoo.component.chain.model.ChainsModelBuilder; +import com.yahoo.component.provider.ComponentRegistry; +import com.yahoo.container.QrSearchersConfig; +import com.yahoo.container.core.ChainsConfig; +import com.yahoo.language.Linguistics; +import com.yahoo.prelude.IndexFacts; +import com.yahoo.prelude.IndexModel; +import com.yahoo.prelude.query.parser.SpecialTokenRegistry; +import com.yahoo.processing.rendering.Renderer; +import com.yahoo.search.Searcher; +import com.yahoo.search.config.IndexInfoConfig; +import com.yahoo.search.rendering.RendererRegistry; +import com.yahoo.vespa.configdefinition.SpecialtokensConfig; + +/** + * Provides creation of fully configured query Execution instances. + * Have an instance of this injected if you need to execute queries which are not initiated from + * an external request. + * + * @author bratseth + */ +public class ExecutionFactory extends AbstractComponent { + + private final SearchChainRegistry searchChainRegistry; + private final IndexFacts indexFacts; + private final SpecialTokenRegistry specialTokens; + private final Linguistics linguistics; + private final RendererRegistry rendererRegistry; + + public ExecutionFactory(ChainsConfig chainsConfig, + IndexInfoConfig indexInfo, + QrSearchersConfig clusters, + ComponentRegistry<Searcher> searchers, + SpecialtokensConfig specialTokens, + Linguistics linguistics, + ComponentRegistry<Renderer> renderers) { + this.searchChainRegistry = createSearchChainRegistry(searchers, chainsConfig); + this.indexFacts = new IndexFacts(new IndexModel(indexInfo, clusters)).freeze(); + this.specialTokens = new SpecialTokenRegistry(specialTokens); + this.linguistics = linguistics; + this.rendererRegistry = new RendererRegistry(renderers.allComponents()); + } + + private SearchChainRegistry createSearchChainRegistry(ComponentRegistry<Searcher> searchers, ChainsConfig chainsConfig) { + SearchChainRegistry searchChainRegistry = new SearchChainRegistry(searchers); + ChainsModel chainsModel = ChainsModelBuilder.buildFromConfig(chainsConfig); + ChainsConfigurer.prepareChainRegistry(searchChainRegistry, chainsModel, searchers); + searchChainRegistry.freeze(); + return searchChainRegistry; + } + + /** + * Creates a new execution starting at a search chain. + * An execution instance should be used once to execute a (tree of) search chains. + */ + public Execution newExecution(Chain<? extends Searcher> searchChain) { + return new Execution(searchChain, + new Execution.Context(searchChainRegistry, indexFacts, specialTokens, rendererRegistry, linguistics)); + } + + /** Returns the search chain registry used by this */ + public SearchChainRegistry searchChainRegistry() { return searchChainRegistry; } + + /** Returns the renderers known to this */ + public RendererRegistry rendererRegistry() { return rendererRegistry; } + + @Override + public void deconstruct() { + rendererRegistry.deconstruct(); + } + +} diff --git a/container-search/src/test/java/com/yahoo/search/handler/test/JSONSearchHandlerTestCase.java b/container-search/src/test/java/com/yahoo/search/handler/test/JSONSearchHandlerTestCase.java index 87d92e1344a..02e2152d7c9 100644 --- a/container-search/src/test/java/com/yahoo/search/handler/test/JSONSearchHandlerTestCase.java +++ b/container-search/src/test/java/com/yahoo/search/handler/test/JSONSearchHandlerTestCase.java @@ -78,8 +78,8 @@ public class JSONSearchHandlerTestCase { File activeConfig = new File(tempDir); SearchChainConfigurerTestCase. createComponentsConfig(new File(activeConfig, "chains.cfg").getPath(), - new File(activeConfig, "handlers.cfg").getPath(), - new File(activeConfig, "components.cfg").getPath()); + new File(activeConfig, "handlers.cfg").getPath(), + new File(activeConfig, "components.cfg").getPath()); } private SearchHandler fetchSearchHandler(HandlersConfigurerTestWrapper configurer) { @@ -129,7 +129,7 @@ public class JSONSearchHandlerTestCase { assertNotSame("Have a new instance of the search handler", searchHandler, newSearchHandler); assertNotNull("Have the new search chain", fetchSearchHandler(configurer).getSearchChainRegistry().getChain("hello")); assertNull("Don't have the new search chain", fetchSearchHandler(configurer).getSearchChainRegistry().getChain("classLoadingError")); - try (RequestHandlerTestDriver newDriver = new RequestHandlerTestDriver(searchHandler)) { + try (RequestHandlerTestDriver newDriver = new RequestHandlerTestDriver(newSearchHandler)) { assertJsonResult(json, newDriver); } } diff --git a/container-search/src/test/java/com/yahoo/search/handler/test/SearchHandlerTestCase.java b/container-search/src/test/java/com/yahoo/search/handler/test/SearchHandlerTestCase.java index 20b18ba6723..c96af2ed4d1 100644 --- a/container-search/src/test/java/com/yahoo/search/handler/test/SearchHandlerTestCase.java +++ b/container-search/src/test/java/com/yahoo/search/handler/test/SearchHandlerTestCase.java @@ -36,6 +36,7 @@ import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; @@ -92,7 +93,7 @@ public class SearchHandlerTestCase { } @Test - public void testNullQuery() throws Exception { + public void testNullQuery() { assertEquals("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n" + "<result total-hit-count=\"0\">\n" + " <hit relevancy=\"1.0\">\n" + @@ -125,10 +126,10 @@ public class SearchHandlerTestCase { // ...and check the resulting config SearchHandler newSearchHandler = fetchSearchHandler(configurer); - assertTrue("Have a new instance of the search handler", searchHandler != newSearchHandler); + assertNotSame("Have a new instance of the search handler", searchHandler, newSearchHandler); assertNotNull("Have the new search chain", fetchSearchHandler(configurer).getSearchChainRegistry().getChain("hello")); assertNull("Don't have the new search chain", fetchSearchHandler(configurer).getSearchChainRegistry().getChain("classLoadingError")); - try (RequestHandlerTestDriver newDriver = new RequestHandlerTestDriver(searchHandler)) { + try (RequestHandlerTestDriver newDriver = new RequestHandlerTestDriver(newSearchHandler)) { assertJsonResult("http://localhost?query=abc", newDriver); } } diff --git a/container-search/src/test/java/com/yahoo/search/query/profile/config/test/typed/components.cfg b/container-search/src/test/java/com/yahoo/search/query/profile/config/test/typed/components.cfg index 1110d76f887..a047ae1cb73 100644 --- a/container-search/src/test/java/com/yahoo/search/query/profile/config/test/typed/components.cfg +++ b/container-search/src/test/java/com/yahoo/search/query/profile/config/test/typed/components.cfg @@ -9,3 +9,4 @@ components[3].id DefaultSearcher components[3].classId com.yahoo.search.query.profile.config.test.QueryProfileIntegrationTestCase$DefaultSearcher components[4].id com.yahoo.search.handler.SearchHandler components[5].id com.yahoo.container.core.config.HandlersConfigurerDi$RegistriesHack +components[6].id com.yahoo.search.searchchain.ExecutionFactory diff --git a/container-search/src/test/java/com/yahoo/search/query/profile/config/test/untyped/components.cfg b/container-search/src/test/java/com/yahoo/search/query/profile/config/test/untyped/components.cfg index 70f5452b74d..ef9d4490a77 100644 --- a/container-search/src/test/java/com/yahoo/search/query/profile/config/test/untyped/components.cfg +++ b/container-search/src/test/java/com/yahoo/search/query/profile/config/test/untyped/components.cfg @@ -1,4 +1,4 @@ -components[6] +components[7] components[0].id SettingSearcher components[0].classId com.yahoo.search.query.profile.config.test.QueryProfileIntegrationTestCase$SettingSearcher components[1].id ReceivingSearcher @@ -8,4 +8,5 @@ components[2].classId com.yahoo.search.query.profile.config.test.QueryProfileInt components[3].id DefaultSearcher components[3].classId com.yahoo.search.query.profile.config.test.QueryProfileIntegrationTestCase$DefaultSearcher components[4].id com.yahoo.search.handler.SearchHandler -components[5].id com.yahoo.container.core.config.HandlersConfigurerDi$RegistriesHack
\ No newline at end of file +components[5].id com.yahoo.container.core.config.HandlersConfigurerDi$RegistriesHack +components[6].id com.yahoo.search.searchchain.ExecutionFactory diff --git a/container-search/src/test/java/com/yahoo/search/searchchain/config/test/SearchChainConfigurerTestCase.java b/container-search/src/test/java/com/yahoo/search/searchchain/config/test/SearchChainConfigurerTestCase.java index 699e8619cd0..a57ed07017f 100644 --- a/container-search/src/test/java/com/yahoo/search/searchchain/config/test/SearchChainConfigurerTestCase.java +++ b/container-search/src/test/java/com/yahoo/search/searchchain/config/test/SearchChainConfigurerTestCase.java @@ -10,6 +10,7 @@ import com.yahoo.search.Result; import com.yahoo.search.Searcher; import com.yahoo.search.handler.SearchHandler; import com.yahoo.search.searchchain.Execution; +import com.yahoo.search.searchchain.ExecutionFactory; import com.yahoo.search.searchchain.SearchChain; import com.yahoo.search.searchchain.SearchChainRegistry; import com.yahoo.search.searchchain.SearcherRegistry; @@ -309,6 +310,7 @@ public class SearchChainConfigurerTestCase { /** * Copies the component ids from another config, e.g. 'handlers' to a 'components' array in a new components file, * to avoid a manually written 'components' file for tests where the bundle spec is given by the component id. + * * @param configFile Full path to the original config file, e.g. 'handlers' * @param componentsFile Full path to the new 'components' file * @param componentType The type of component, e.g. 'handler' @@ -324,7 +326,7 @@ public class SearchChainConfigurerTestCase { if (append) { Pattern p = Pattern.compile("^[a-z]+" + "\\[\\d+\\]\\.id (.+)"); BufferedReader reader = new BufferedReader(new InputStreamReader( - new FileInputStream(new File(componentsFile)), "UTF-8")); + new FileInputStream(new File(componentsFile)), "UTF-8")); while ((line = reader.readLine()) != null) { Matcher m = p.matcher(line); if (m.matches() && !m.group(1).equals(HandlersConfigurerDi.RegistriesHack.class.getName())) { @@ -344,10 +346,11 @@ public class SearchChainConfigurerTestCase { i++; } } - buf.append("components[").append(i).append("].id "). - append(HandlersConfigurerDi.RegistriesHack.class.getName()).append("\n"); - i++; reader.close(); + + buf.append("components[").append(i++).append("].id ").append(HandlersConfigurerDi.RegistriesHack.class.getName()).append("\n"); + if (componentType.equals("components")) + buf.append("components[").append(i++).append("].id ").append(ExecutionFactory.class.getName()).append("\n"); buf.insert(0, "components["+i+"]\n"); Writer writer = new OutputStreamWriter(new FileOutputStream(new File(componentsFile)), "UTF-8"); |