From c6fa090a55f301c714a579df5afbb5f3eb00c1aa Mon Sep 17 00:00:00 2001 From: Kay Roepke Date: Wed, 4 Dec 2024 14:06:29 +0100 Subject: [PATCH] inject the backend query type map for pluggable backend selection always also bind backends in the generic map binder, even for versioned backends in non-versioned backends, use the map binder directly so the engine can pick the correct backend based on the BackendQuery instance used for query normalization, ignore non-elasticsearch based queries for now, we will need to address normalizers later to make them type safe (or just live with the instanceof check) --- .../elasticsearch7/ViewsESBackendModule.java | 4 ++-- .../storage/opensearch2/ViewsOSBackendModule.java | 4 ++-- .../org/graylog/plugins/views/ViewsModule.java | 15 +++++++++++---- .../plugins/views/search/engine/QueryEngine.java | 8 +++++--- .../DecorateQueryStringsNormalizer.java | 4 ++++ 5 files changed, 24 insertions(+), 11 deletions(-) diff --git a/graylog-storage-elasticsearch7/src/main/java/org/graylog/storage/elasticsearch7/ViewsESBackendModule.java b/graylog-storage-elasticsearch7/src/main/java/org/graylog/storage/elasticsearch7/ViewsESBackendModule.java index db8dbf5de26a..83b7d6ee2693 100644 --- a/graylog-storage-elasticsearch7/src/main/java/org/graylog/storage/elasticsearch7/ViewsESBackendModule.java +++ b/graylog-storage-elasticsearch7/src/main/java/org/graylog/storage/elasticsearch7/ViewsESBackendModule.java @@ -24,6 +24,7 @@ import com.google.inject.multibindings.MapBinder; import org.graylog.plugins.views.ViewsModule; import org.graylog.plugins.views.search.SearchType; +import org.graylog.plugins.views.search.elasticsearch.ElasticsearchQueryString; import org.graylog.plugins.views.search.engine.GeneratedQueryContext; import org.graylog.plugins.views.search.engine.QueryBackend; import org.graylog.plugins.views.search.export.ExportBackend; @@ -86,8 +87,7 @@ public ViewsESBackendModule(SearchVersion supportedSearchVersion) { protected void configure() { install(new FactoryModuleBuilder().build(ESGeneratedQueryContext.Factory.class)); - bindForVersion(supportedSearchVersion, new TypeLiteral>() {}) - .to(ElasticsearchBackend.class); + registerVersionedQueryBackend(supportedSearchVersion, ElasticsearchQueryString.NAME, ElasticsearchBackend.class); registerESSearchTypeHandler(MessageList.NAME, ESMessageList.class); registerESSearchTypeHandler(EventList.NAME, ESEventList.class); diff --git a/graylog-storage-opensearch2/src/main/java/org/graylog/storage/opensearch2/ViewsOSBackendModule.java b/graylog-storage-opensearch2/src/main/java/org/graylog/storage/opensearch2/ViewsOSBackendModule.java index 01e1f8440e25..39f2a5715175 100644 --- a/graylog-storage-opensearch2/src/main/java/org/graylog/storage/opensearch2/ViewsOSBackendModule.java +++ b/graylog-storage-opensearch2/src/main/java/org/graylog/storage/opensearch2/ViewsOSBackendModule.java @@ -25,6 +25,7 @@ import com.google.inject.multibindings.OptionalBinder; import org.graylog.plugins.views.ViewsModule; import org.graylog.plugins.views.search.SearchType; +import org.graylog.plugins.views.search.elasticsearch.ElasticsearchQueryString; import org.graylog.plugins.views.search.engine.GeneratedQueryContext; import org.graylog.plugins.views.search.engine.QueryBackend; import org.graylog.plugins.views.search.export.ExportBackend; @@ -89,8 +90,7 @@ public ViewsOSBackendModule(SearchVersion supportedSearchVersion) { protected void configure() { install(new FactoryModuleBuilder().build(OSGeneratedQueryContext.Factory.class)); - bindForVersion(supportedSearchVersion, new TypeLiteral>() {}) - .to(OpenSearchBackend.class); + registerVersionedQueryBackend(supportedSearchVersion, ElasticsearchQueryString.NAME, OpenSearchBackend.class); registerOSSearchTypeHandler(MessageList.NAME, OSMessageList.class); registerOSSearchTypeHandler(EventList.NAME, OSEventListDelegate.class); diff --git a/graylog2-server/src/main/java/org/graylog/plugins/views/ViewsModule.java b/graylog2-server/src/main/java/org/graylog/plugins/views/ViewsModule.java index e0bfa8adad78..c6b82230f6ae 100644 --- a/graylog2-server/src/main/java/org/graylog/plugins/views/ViewsModule.java +++ b/graylog2-server/src/main/java/org/graylog/plugins/views/ViewsModule.java @@ -85,15 +85,22 @@ protected void registerPivotAggregationFunction(String name, String description, seriesSpecBinder().addBinding(name).toInstance(SeriesDescription.create(name, description)); } - protected MapBinder> queryBackendBinder(SearchVersion version) { + protected MapBinder> queryBackendBinder() { return MapBinder.newMapBinder(binder(), TypeLiteral.get(String.class), - new TypeLiteral>() {}); + new TypeLiteral<>() {}); } - protected ScopedBindingBuilder registerQueryBackend(SearchVersion version, String name, Class> implementation) { - return queryBackendBinder(version).addBinding(name).to(implementation); + /** + * Use this binder for versioned backends, it also registers the backend in the overall MapBinder in + * @param version + * @param name + * @param implementation + */ + protected void registerVersionedQueryBackend(SearchVersion version, String name, Class> implementation) { + bindForVersion(version, new TypeLiteral>() {}).to(implementation); + queryBackendBinder().addBinding(name).to(implementation); } protected void registerESQueryDecorator(Class esQueryDecorator) { diff --git a/graylog2-server/src/main/java/org/graylog/plugins/views/search/engine/QueryEngine.java b/graylog2-server/src/main/java/org/graylog/plugins/views/search/engine/QueryEngine.java index 4d4d2c095d94..90c24fec11a0 100644 --- a/graylog2-server/src/main/java/org/graylog/plugins/views/search/engine/QueryEngine.java +++ b/graylog2-server/src/main/java/org/graylog/plugins/views/search/engine/QueryEngine.java @@ -52,13 +52,13 @@ public class QueryEngine { // TODO proper thread pool with tunable settings private final Executor queryPool = Executors.newFixedThreadPool(4, new ThreadFactoryBuilder().setNameFormat("query-engine-%d").build()); - private final QueryBackend backend; + private final Map> backends; @Inject - public QueryEngine(QueryBackend backend, + public QueryEngine(Map> backends, Set queryMetadataDecorators, QueryParser queryParser) { - this.backend = backend; + this.backends = backends; this.queryMetadataDecorators = queryMetadataDecorators; this.queryParser = queryParser; } @@ -75,6 +75,7 @@ public QueryMetadata parse(Search search, Query query) { public ExplainResults explain(SearchJob searchJob, Set validationErrors, DateTimeZone timezone) { final Map queries = searchJob.getSearch().queries().stream() .collect(Collectors.toMap(Query::id, q -> { + var backend = backends.get(q.query().type()); final GeneratedQueryContext generatedQueryContext = backend.generate(q, Set.of(), timezone); return backend.explain(searchJob, q, generatedQueryContext); @@ -116,6 +117,7 @@ public SearchJob execute(SearchJob searchJob, Set validationErrors, } private QueryResult prepareAndRun(SearchJob searchJob, Query query, Set validationErrors, DateTimeZone timezone) { + final var backend = backends.get(query.query().type()); LOG.debug("[{}] Using {} to generate query", query.id(), backend); // with all the results done, we can execute the current query and eventually complete our own result // if any of this throws an exception, the handle in #execute will convert it to an error and return a "failed" result instead diff --git a/graylog2-server/src/main/java/org/graylog/plugins/views/search/engine/normalization/DecorateQueryStringsNormalizer.java b/graylog2-server/src/main/java/org/graylog/plugins/views/search/engine/normalization/DecorateQueryStringsNormalizer.java index bff3f21b7c75..db8e1260faa7 100644 --- a/graylog2-server/src/main/java/org/graylog/plugins/views/search/engine/normalization/DecorateQueryStringsNormalizer.java +++ b/graylog2-server/src/main/java/org/graylog/plugins/views/search/engine/normalization/DecorateQueryStringsNormalizer.java @@ -38,6 +38,10 @@ public DecorateQueryStringsNormalizer(QueryStringDecorators queryStringDecorator @Override public Query normalizeQuery(final Query query, final ParameterProvider parameterProvider) { + // this only makes sense for ElasticsearchQueryString instances, don't touch any other type + if (!(query.query() instanceof ElasticsearchQueryString)) { + return query; + } return query.toBuilder() .query(ElasticsearchQueryString.of(this.queryStringDecorators.decorate(query.query().queryString(), parameterProvider, query))) .filter(normalizeFilter(query.filter(), query, parameterProvider))