From 166dac272f854d707be6b37cc1161fbf6f22a228 Mon Sep 17 00:00:00 2001 From: awildturtok <1553491+awildturtok@users.noreply.github.com> Date: Tue, 7 Mar 2023 11:25:11 +0100 Subject: [PATCH 1/6] move ConceptsProcessor SelectFilter to Searchable --- .../models/datasets/concepts/Searchable.java | 9 ++ .../models/jobs/UpdateFilterSearchJob.java | 25 ++--- .../conquery/models/query/FilterSearch.java | 6 +- .../resources/api/ConceptsProcessor.java | 102 +++++++----------- .../resources/api/FilterResource.java | 22 +--- .../tests/ConceptResolutionTest.java | 4 +- .../tests/FilterAutocompleteTest.java | 4 +- .../tests/FilterResolutionTest.java | 8 +- 8 files changed, 77 insertions(+), 103 deletions(-) diff --git a/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/Searchable.java b/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/Searchable.java index 30f34eb5be..4cfbbb1dbc 100644 --- a/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/Searchable.java +++ b/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/Searchable.java @@ -7,6 +7,8 @@ import com.bakdata.conquery.apiv1.frontend.FrontendValue; import com.bakdata.conquery.io.storage.NamespaceStorage; import com.bakdata.conquery.models.config.IndexConfig; +import com.bakdata.conquery.models.datasets.Dataset; +import com.bakdata.conquery.models.identifiable.ids.Id; import com.bakdata.conquery.models.query.FilterSearch; import com.bakdata.conquery.util.search.TrieSearch; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -17,6 +19,13 @@ * Searchable classes describe how a search should be constructed, and provide the values with getSearchValues. */ public interface Searchable { + + + //TODO instead extend Identifiable properly + public Id getId(); + + public Dataset getDataset(); + /** * All available {@link FrontendValue}s for searching in a {@link TrieSearch}. */ diff --git a/backend/src/main/java/com/bakdata/conquery/models/jobs/UpdateFilterSearchJob.java b/backend/src/main/java/com/bakdata/conquery/models/jobs/UpdateFilterSearchJob.java index f99663d8a5..69364a541f 100644 --- a/backend/src/main/java/com/bakdata/conquery/models/jobs/UpdateFilterSearchJob.java +++ b/backend/src/main/java/com/bakdata/conquery/models/jobs/UpdateFilterSearchJob.java @@ -40,7 +40,7 @@ public class UpdateFilterSearchJob extends Job { private final IndexConfig indexConfig; @NonNull - private final Object2LongMap> totals; + private final Object2LongMap totals; @Override public void execute() throws Exception { @@ -121,17 +121,18 @@ public void execute() throws Exception { // Precompute totals as that can be slow when doing it on-demand. totals.putAll( - allSelectFilters.parallelStream() - .collect(Collectors.toMap( - Functions.identity(), - filter -> filter.getSearchReferences().stream() - .map(searchCache::get) - .filter(Objects::nonNull) // Failed or disabled searches are null - .flatMap(TrieSearch::stream) - .mapToInt(FrontendValue::hashCode) - .distinct() - .count() - )) + synchronizedResult.keySet() + .parallelStream() + .collect(Collectors.toMap( + Functions.identity(), + filter -> filter.getSearchReferences().stream() + .map(searchCache::get) + .filter(Objects::nonNull) // Failed or disabled searches are null + .flatMap(TrieSearch::stream) + .mapToInt(FrontendValue::hashCode) + .distinct() + .count() + )) ); diff --git a/backend/src/main/java/com/bakdata/conquery/models/query/FilterSearch.java b/backend/src/main/java/com/bakdata/conquery/models/query/FilterSearch.java index c7be92d105..3175c02067 100644 --- a/backend/src/main/java/com/bakdata/conquery/models/query/FilterSearch.java +++ b/backend/src/main/java/com/bakdata/conquery/models/query/FilterSearch.java @@ -41,7 +41,7 @@ public class FilterSearch { */ @JsonIgnore private final Map> searchCache = new HashMap<>(); - private Object2LongMap> totals = Object2LongMaps.emptyMap(); + private Object2LongMap totals = Object2LongMaps.emptyMap(); /** * From a given {@link FrontendValue} extract all relevant keywords. @@ -62,14 +62,14 @@ public static List extractKeywords(FrontendValue value) { /** * For a {@link SelectFilter} collect all relevant {@link TrieSearch}. */ - public List> getSearchesFor(SelectFilter filter) { + public List> getSearchesFor(Searchable filter) { return filter.getSearchReferences().stream() .map(searchCache::get) .filter(Objects::nonNull) .collect(Collectors.toList()); } - public long getTotal(SelectFilter filter) { + public long getTotal(Searchable filter) { return totals.getOrDefault(filter, 0); } diff --git a/backend/src/main/java/com/bakdata/conquery/resources/api/ConceptsProcessor.java b/backend/src/main/java/com/bakdata/conquery/resources/api/ConceptsProcessor.java index 75df583c9b..8c1b81d4b2 100644 --- a/backend/src/main/java/com/bakdata/conquery/resources/api/ConceptsProcessor.java +++ b/backend/src/main/java/com/bakdata/conquery/resources/api/ConceptsProcessor.java @@ -29,33 +29,30 @@ import com.bakdata.conquery.models.datasets.PreviewConfig; import com.bakdata.conquery.models.datasets.concepts.Concept; import com.bakdata.conquery.models.datasets.concepts.FrontEndConceptBuilder; +import com.bakdata.conquery.models.datasets.concepts.Searchable; +import com.bakdata.conquery.models.datasets.concepts.filters.Filter; import com.bakdata.conquery.models.datasets.concepts.filters.specific.SelectFilter; import com.bakdata.conquery.models.datasets.concepts.tree.ConceptTreeChild; import com.bakdata.conquery.models.datasets.concepts.tree.TreeConcept; import com.bakdata.conquery.models.exceptions.ConceptConfigurationException; import com.bakdata.conquery.models.exceptions.ValidatorHelper; +import com.bakdata.conquery.models.identifiable.Identifiable; +import com.bakdata.conquery.models.identifiable.ids.Id; import com.bakdata.conquery.models.identifiable.ids.specific.ConceptElementId; import com.bakdata.conquery.models.identifiable.ids.specific.ConnectorId; import com.bakdata.conquery.models.identifiable.ids.specific.DatasetId; -import com.bakdata.conquery.models.identifiable.ids.specific.FilterId; import com.bakdata.conquery.models.worker.DatasetRegistry; import com.bakdata.conquery.models.worker.Namespace; import com.bakdata.conquery.util.CalculatedValue; import com.bakdata.conquery.util.search.Cursor; import com.bakdata.conquery.util.search.TrieSearch; -import com.fasterxml.jackson.annotation.JsonCreator; import com.google.common.base.Preconditions; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import com.google.common.collect.Iterators; -import lombok.AllArgsConstructor; -import lombok.Data; import lombok.Getter; import lombok.RequiredArgsConstructor; -import lombok.Setter; -import lombok.ToString; -import lombok.Value; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.tuple.Pair; @@ -78,46 +75,34 @@ public FrontendList load(Concept concept) { /** * Cache of all search results on SelectFilters. */ - private final LoadingCache, String>, List> + private final LoadingCache, List> searchResults = CacheBuilder.newBuilder().softValues().build(new CacheLoader<>() { @Override - public List load(Pair, String> filterAndSearch) { - String searchTerm = filterAndSearch.getValue(); - SelectFilter filter = filterAndSearch.getKey(); + public List load(Pair filterAndSearch) { + final String searchTerm = filterAndSearch.getValue(); + final Searchable filter = filterAndSearch.getKey(); log.trace("Calculating a new search cache for the term \"{}\" on filter[{}]", searchTerm, filter.getId()); return autocompleteTextFilter(filter, searchTerm); } - }); - - - /** - * Container class to pair number of available values and Cursor for those values. - */ - @Value - private static class CursorAndLength { - private final Cursor values; - private final long size; - } - + }); /** * Cache of raw listing of values on a filter. * We use Cursor here to reduce strain on memory and increase response time. */ - private final LoadingCache, CursorAndLength> listResults = CacheBuilder.newBuilder().softValues().build(new CacheLoader<>() { + private final LoadingCache listResults = CacheBuilder.newBuilder().softValues().build(new CacheLoader<>() { @Override - public CursorAndLength load(SelectFilter filter) { + public CursorAndLength load(Searchable filter) { log.debug("Creating cursor for `{}`", filter.getId()); return new CursorAndLength(listAllValues(filter), countAllValues(filter)); } }); - public FrontendRoot getRoot(NamespaceStorage storage, Subject subject) { final FrontendRoot root = FrontEndConceptBuilder.createRoot(storage, subject); @@ -146,7 +131,6 @@ public List> getDatasets(Subject subject) { .collect(Collectors.toList()); } - public FrontendPreviewConfig getEntityPreviewFrontendConfig(Dataset dataset) { final Namespace namespace = namespaces.get(dataset.getId()); final PreviewConfig previewConfig = namespace.getPreviewConfig(); @@ -172,7 +156,7 @@ public FrontendPreviewConfig getEntityPreviewFrontendConfig(Dataset dataset) { * Search for all search terms at once, with stricter scoring. * The user will upload a file and expect only well-corresponding resolutions. */ - public ResolvedConceptsResult resolveFilterValues(SelectFilter filter, List searchTerms) { + public ResolvedConceptsResult resolveFilterValues(Searchable filter, List searchTerms) { // search in the full text engine final Set openSearchTerms = new HashSet<>(searchTerms); @@ -182,7 +166,7 @@ public ResolvedConceptsResult resolveFilterValues(SelectFilter filter, List out = new ArrayList<>(); for (TrieSearch search : namespace.getFilterSearch().getSearchesFor(filter)) { - for (Iterator iterator = openSearchTerms.iterator(); iterator.hasNext(); ) { + for (final Iterator iterator = openSearchTerms.iterator(); iterator.hasNext(); ) { final String searchTerm = iterator.next(); final List results = search.findExact(List.of(searchTerm), Integer.MAX_VALUE); @@ -196,17 +180,14 @@ public ResolvedConceptsResult resolveFilterValues(SelectFilter filter, List id = ((Identifiable) filter).getId(); + - @Data - @RequiredArgsConstructor(onConstructor_ = {@JsonCreator}) - public static class AutoCompleteResult { - private final List values; - private final long total; + return new ResolvedConceptsResult(null, new ResolvedFilterResult(connectorId, id.toString(), out), openSearchTerms); } - public AutoCompleteResult autocompleteTextFilter(SelectFilter filter, Optional maybeText, OptionalInt pageNumberOpt, OptionalInt itemsPerPageOpt) { + public > AutoCompleteResult autocompleteTextFilter(T filter, Optional maybeText, OptionalInt pageNumberOpt, OptionalInt itemsPerPageOpt) { final int pageNumber = pageNumberOpt.orElse(0); final int itemsPerPage = itemsPerPageOpt.orElse(50); @@ -223,9 +204,9 @@ public AutoCompleteResult autocompleteTextFilter(SelectFilter filter, Optiona // If we have none or a blank query string we list all values. if (maybeText.isEmpty() || maybeText.get().isBlank()) { final CursorAndLength cursorAndLength = listResults.get(filter); - final Cursor cursor = cursorAndLength.getValues(); + final Cursor cursor = cursorAndLength.values(); - return new AutoCompleteResult(cursor.get(startIncl, endExcl), cursorAndLength.getSize()); + return new AutoCompleteResult(cursor.get(startIncl, endExcl), cursorAndLength.size()); } final List fullResult = searchResults.get(Pair.of(filter, maybeText.get())); @@ -237,13 +218,12 @@ public AutoCompleteResult autocompleteTextFilter(SelectFilter filter, Optiona return new AutoCompleteResult(fullResult.subList(startIncl, Math.min(fullResult.size(), endExcl)), fullResult.size()); } catch (ExecutionException e) { - log.warn("Failed to search for \"{}\".", maybeText, (Throwable) (log.isTraceEnabled() ? e : null)); + log.warn("Failed to search for \"{}\".", maybeText, log.isTraceEnabled() ? e : null); return new AutoCompleteResult(Collections.emptyList(), 0); } } - - private Cursor listAllValues(SelectFilter filter) { + private Cursor listAllValues(Searchable filter) { final Namespace namespace = namespaces.get(filter.getDataset().getId()); /* Don't worry, I am as confused as you are! @@ -263,7 +243,7 @@ private Cursor listAllValues(SelectFilter filter) { return new Cursor<>(Iterators.filter(iterators, seen::add)); } - private long countAllValues(SelectFilter filter) { + private long countAllValues(Searchable filter) { final Namespace namespace = namespaces.get(filter.getDataset().getId()); @@ -274,7 +254,7 @@ private long countAllValues(SelectFilter filter) { * Autocompletion for search terms. For values of {@link SelectFilter }. * Is used by the serach cache to load missing items */ - private List autocompleteTextFilter(SelectFilter filter, String text) { + private List autocompleteTextFilter(Searchable filter, String text) { final Namespace namespace = namespaces.get(filter.getDataset().getId()); // Note that FEValues is equals/hashcode only on value: @@ -302,7 +282,7 @@ private static List createSourceSearchResult(TrieSearch result = search.findItems(values, numberOfTopItems.orElse(Integer.MAX_VALUE)); + final List result = search.findItems(values, numberOfTopItems.orElse(Integer.MAX_VALUE)); if (numberOfTopItems.isEmpty() && result.size() == Integer.MAX_VALUE) { //TODO This looks odd, do we really expect QuickSearch to allocate that huge of a list for us? @@ -319,7 +299,7 @@ public ResolvedConceptsResult resolveConceptElements(TreeConcept concept, List(Collections::emptyMap)); + final ConceptTreeChild child = concept.findMostSpecificChild(conceptCode, new CalculatedValue<>(Collections::emptyMap)); if (child != null) { resolvedCodes.add(child.getId()); @@ -329,29 +309,25 @@ public ResolvedConceptsResult resolveConceptElements(TreeConcept concept, List value; + /** + * Container class to pair number of available values and Cursor for those values. + */ + private record CursorAndLength(Cursor values, long size) { + } + + public record AutoCompleteResult(List values, long total) { + } + + public record ResolvedFilterResult(ConnectorId tableId, String filterId, Collection value) { + //TODO FK filterId as Id causes issues with IdUtil createParser, should investigate this } - @Getter - @Setter - @AllArgsConstructor - @ToString - public static class ResolvedConceptsResult { - private Set> resolvedConcepts; - private ResolvedFilterResult resolvedFilter; - private Collection unknownCodes; + public record ResolvedConceptsResult(Set> resolvedConcepts, ResolvedFilterResult resolvedFilter, Collection unknownCodes) { } } diff --git a/backend/src/main/java/com/bakdata/conquery/resources/api/FilterResource.java b/backend/src/main/java/com/bakdata/conquery/resources/api/FilterResource.java index 89716d72c4..639e8de468 100644 --- a/backend/src/main/java/com/bakdata/conquery/resources/api/FilterResource.java +++ b/backend/src/main/java/com/bakdata/conquery/resources/api/FilterResource.java @@ -23,8 +23,6 @@ import com.bakdata.conquery.models.datasets.concepts.filters.specific.SelectFilter; import com.bakdata.conquery.resources.api.ConceptsProcessor.ResolvedConceptsResult; import com.bakdata.conquery.resources.hierarchies.HAuthorized; -import com.fasterxml.jackson.annotation.JsonCreator; -import lombok.Data; import lombok.NonNull; import lombok.RequiredArgsConstructor; import lombok.Setter; @@ -50,9 +48,10 @@ public ResolvedConceptsResult resolveFilterValues(FilterValues filterValues) { subject.isPermitted(filter.getDataset(), Ability.READ); subject.isPermitted(filter.getConnector().findConcept(), Ability.READ); - return processor.resolveFilterValues((SelectFilter) filter, filterValues.getValues()); + return processor.resolveFilterValues((SelectFilter) filter, filterValues.values()); } + //TODO migrate from filter to searchable @POST @Path("autocomplete") public ConceptsProcessor.AutoCompleteResult autocompleteTextFilter(@Valid FilterResource.AutocompleteRequest request) { @@ -65,27 +64,16 @@ public ConceptsProcessor.AutoCompleteResult autocompleteTextFilter(@Valid Filter try { - return processor.autocompleteTextFilter((SelectFilter) filter, request.getText(), request.getPage(), request.getPageSize()); + return processor.autocompleteTextFilter((SelectFilter) filter, request.text(), request.page(), request.pageSize()); } catch (IllegalArgumentException e) { throw new BadRequestException(e); } } - @Data - @RequiredArgsConstructor(onConstructor_ = {@JsonCreator}) - public static class FilterValues { - private final List values; + public record FilterValues(List values) { } - @Data - @RequiredArgsConstructor(onConstructor_ = {@JsonCreator}) - public static class AutocompleteRequest { - @NonNull - private final Optional text; - @NonNull - private final OptionalInt page; - @NonNull - private final OptionalInt pageSize; + public record AutocompleteRequest(@NonNull Optional text, @NonNull OptionalInt page, @NonNull OptionalInt pageSize) { } } diff --git a/backend/src/test/java/com/bakdata/conquery/integration/tests/ConceptResolutionTest.java b/backend/src/test/java/com/bakdata/conquery/integration/tests/ConceptResolutionTest.java index 289bf728e5..3b41f04627 100644 --- a/backend/src/test/java/com/bakdata/conquery/integration/tests/ConceptResolutionTest.java +++ b/backend/src/test/java/com/bakdata/conquery/integration/tests/ConceptResolutionTest.java @@ -76,8 +76,8 @@ public void execute(StandaloneSupport conquery) throws Exception { ResolvedConceptsResult resolved = response.readEntity(ResolvedConceptsResult.class); //check the resolved values assertThat(resolved).isNotNull(); - assertThat(resolved.getResolvedConcepts().stream().map(Id::toString)).containsExactlyInAnyOrder("ConceptResolutionTest.test_tree.test_child1"); - assertThat(resolved.getUnknownCodes()).containsExactlyInAnyOrder("unknown"); + assertThat(resolved.resolvedConcepts().stream().map(Id::toString)).containsExactlyInAnyOrder("ConceptResolutionTest.test_tree.test_child1"); + assertThat(resolved.unknownCodes()).containsExactlyInAnyOrder("unknown"); } } \ No newline at end of file diff --git a/backend/src/test/java/com/bakdata/conquery/integration/tests/FilterAutocompleteTest.java b/backend/src/test/java/com/bakdata/conquery/integration/tests/FilterAutocompleteTest.java index da59a8efee..a379e4b375 100644 --- a/backend/src/test/java/com/bakdata/conquery/integration/tests/FilterAutocompleteTest.java +++ b/backend/src/test/java/com/bakdata/conquery/integration/tests/FilterAutocompleteTest.java @@ -120,7 +120,7 @@ public void execute(StandaloneSupport conquery) throws Exception { ), MediaType.APPLICATION_JSON_TYPE)); final ConceptsProcessor.AutoCompleteResult resolvedFromCsv = fromCsvResponse.readEntity(ConceptsProcessor.AutoCompleteResult.class); - assertThat(resolvedFromCsv.getValues().stream().map(FrontendValue::getValue)).containsExactly("a", "aaa", "aab", "baaa"); + assertThat(resolvedFromCsv.values().stream().map(FrontendValue::getValue)).containsExactly("a", "aaa", "aab", "baaa"); } @@ -137,7 +137,7 @@ public void execute(StandaloneSupport conquery) throws Exception { final ConceptsProcessor.AutoCompleteResult resolvedFromValues = fromCsvResponse.readEntity(ConceptsProcessor.AutoCompleteResult.class); //check the resolved values - assertThat(resolvedFromValues.getValues().stream().map(FrontendValue::getValue)) + assertThat(resolvedFromValues.values().stream().map(FrontendValue::getValue)) .containsExactly("f", "fm"); } } diff --git a/backend/src/test/java/com/bakdata/conquery/integration/tests/FilterResolutionTest.java b/backend/src/test/java/com/bakdata/conquery/integration/tests/FilterResolutionTest.java index 5709a983e2..1a5c1e8427 100644 --- a/backend/src/test/java/com/bakdata/conquery/integration/tests/FilterResolutionTest.java +++ b/backend/src/test/java/com/bakdata/conquery/integration/tests/FilterResolutionTest.java @@ -116,8 +116,8 @@ public void execute(StandaloneSupport conquery) throws Exception { //check the resolved values // "aaa" is hit by "a" and "aaa" therefore should be first - assertThat(resolved.getResolvedFilter().getValue().stream().map(FrontendValue::getValue)).containsExactly("aaa", "a"); - assertThat(resolved.getUnknownCodes()).containsExactly("unknown"); + assertThat(resolved.resolvedFilter().value().stream().map(FrontendValue::getValue)).containsExactly("aaa", "a"); + assertThat(resolved.unknownCodes()).containsExactly("unknown"); } // from column values @@ -129,8 +129,8 @@ public void execute(StandaloneSupport conquery) throws Exception { ResolvedConceptsResult resolved = fromCsvResponse.readEntity(ResolvedConceptsResult.class); //check the resolved values - assertThat(resolved.getResolvedFilter().getValue().stream().map(FrontendValue::getValue)).contains("f"); - assertThat(resolved.getUnknownCodes()).containsExactly("unknown"); + assertThat(resolved.resolvedFilter().value().stream().map(FrontendValue::getValue)).contains("f"); + assertThat(resolved.unknownCodes()).containsExactly("unknown"); } } } \ No newline at end of file From 3e2e9d0309b7d46bc46dadfa5c15984b250bd09c Mon Sep 17 00:00:00 2001 From: awildturtok <1553491+awildturtok@users.noreply.github.com> Date: Thu, 9 Mar 2023 17:42:52 +0100 Subject: [PATCH 2/6] make Searchable properly identifiable, and rename filters to searchable in ConceptsProcessor --- .../conquery/apiv1/FilterTemplate.java | 2 +- .../conquery/models/datasets/Column.java | 2 +- .../models/datasets/concepts/Searchable.java | 7 +-- .../filters/specific/SelectFilter.java | 3 +- .../resources/api/ConceptsProcessor.java | 59 +++++++++---------- 5 files changed, 34 insertions(+), 39 deletions(-) diff --git a/backend/src/main/java/com/bakdata/conquery/apiv1/FilterTemplate.java b/backend/src/main/java/com/bakdata/conquery/apiv1/FilterTemplate.java index 492aaf895e..6a05f227f8 100644 --- a/backend/src/main/java/com/bakdata/conquery/apiv1/FilterTemplate.java +++ b/backend/src/main/java/com/bakdata/conquery/apiv1/FilterTemplate.java @@ -41,7 +41,7 @@ @ToString @Slf4j @CPSType(id = "CSV_TEMPLATE", base = SearchIndex.class) -public class FilterTemplate extends IdentifiableImpl implements Searchable, SearchIndex { +public class FilterTemplate extends IdentifiableImpl implements Searchable, SearchIndex { private static final long serialVersionUID = 1L; diff --git a/backend/src/main/java/com/bakdata/conquery/models/datasets/Column.java b/backend/src/main/java/com/bakdata/conquery/models/datasets/Column.java index fa6743eaa7..b46612e72f 100644 --- a/backend/src/main/java/com/bakdata/conquery/models/datasets/Column.java +++ b/backend/src/main/java/com/bakdata/conquery/models/datasets/Column.java @@ -36,7 +36,7 @@ @Setter @NoArgsConstructor @Slf4j -public class Column extends Labeled implements NamespacedIdentifiable, Searchable { +public class Column extends Labeled implements NamespacedIdentifiable, Searchable { public static final int UNKNOWN_POSITION = -1; diff --git a/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/Searchable.java b/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/Searchable.java index 4cfbbb1dbc..10b8090f1b 100644 --- a/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/Searchable.java +++ b/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/Searchable.java @@ -8,6 +8,7 @@ import com.bakdata.conquery.io.storage.NamespaceStorage; import com.bakdata.conquery.models.config.IndexConfig; import com.bakdata.conquery.models.datasets.Dataset; +import com.bakdata.conquery.models.identifiable.Identifiable; import com.bakdata.conquery.models.identifiable.ids.Id; import com.bakdata.conquery.models.query.FilterSearch; import com.bakdata.conquery.util.search.TrieSearch; @@ -18,11 +19,7 @@ *

* Searchable classes describe how a search should be constructed, and provide the values with getSearchValues. */ -public interface Searchable { - - - //TODO instead extend Identifiable properly - public Id getId(); +public interface Searchable>> extends Identifiable { public Dataset getDataset(); diff --git a/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/filters/specific/SelectFilter.java b/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/filters/specific/SelectFilter.java index 8ff61d98ea..531ec32c4b 100644 --- a/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/filters/specific/SelectFilter.java +++ b/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/filters/specific/SelectFilter.java @@ -17,6 +17,7 @@ import com.bakdata.conquery.models.datasets.concepts.filters.SingleColumnFilter; import com.bakdata.conquery.models.events.MajorTypeId; import com.bakdata.conquery.models.exceptions.ConceptConfigurationException; +import com.bakdata.conquery.models.identifiable.ids.specific.FilterId; import com.bakdata.conquery.models.query.FilterSearch; import com.bakdata.conquery.util.search.TrieSearch; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -35,7 +36,7 @@ @NoArgsConstructor @Slf4j @JsonIgnoreProperties({"searchType"}) -public abstract class SelectFilter extends SingleColumnFilter implements Searchable { +public abstract class SelectFilter extends SingleColumnFilter implements Searchable { /** * user given mapping from the values in the CSVs to shown labels diff --git a/backend/src/main/java/com/bakdata/conquery/resources/api/ConceptsProcessor.java b/backend/src/main/java/com/bakdata/conquery/resources/api/ConceptsProcessor.java index 8c1b81d4b2..257ce9d0b0 100644 --- a/backend/src/main/java/com/bakdata/conquery/resources/api/ConceptsProcessor.java +++ b/backend/src/main/java/com/bakdata/conquery/resources/api/ConceptsProcessor.java @@ -36,8 +36,6 @@ import com.bakdata.conquery.models.datasets.concepts.tree.TreeConcept; import com.bakdata.conquery.models.exceptions.ConceptConfigurationException; import com.bakdata.conquery.models.exceptions.ValidatorHelper; -import com.bakdata.conquery.models.identifiable.Identifiable; -import com.bakdata.conquery.models.identifiable.ids.Id; import com.bakdata.conquery.models.identifiable.ids.specific.ConceptElementId; import com.bakdata.conquery.models.identifiable.ids.specific.ConnectorId; import com.bakdata.conquery.models.identifiable.ids.specific.DatasetId; @@ -75,18 +73,18 @@ public FrontendList load(Concept concept) { /** * Cache of all search results on SelectFilters. */ - private final LoadingCache, List> + private final LoadingCache, String>, List> searchResults = CacheBuilder.newBuilder().softValues().build(new CacheLoader<>() { @Override - public List load(Pair filterAndSearch) { + public List load(Pair, String> filterAndSearch) { final String searchTerm = filterAndSearch.getValue(); - final Searchable filter = filterAndSearch.getKey(); + final Searchable searchable = filterAndSearch.getKey(); - log.trace("Calculating a new search cache for the term \"{}\" on filter[{}]", searchTerm, filter.getId()); + log.trace("Calculating a new search cache for the term \"{}\" on Searchable[{}]", searchTerm, searchable.getId()); - return autocompleteTextFilter(filter, searchTerm); + return autocompleteTextFilter(searchable, searchTerm); } }); @@ -94,11 +92,11 @@ public List load(Pair filterAndSearch) { * Cache of raw listing of values on a filter. * We use Cursor here to reduce strain on memory and increase response time. */ - private final LoadingCache listResults = CacheBuilder.newBuilder().softValues().build(new CacheLoader<>() { + private final LoadingCache, CursorAndLength> listResults = CacheBuilder.newBuilder().softValues().build(new CacheLoader<>() { @Override - public CursorAndLength load(Searchable filter) { - log.debug("Creating cursor for `{}`", filter.getId()); - return new CursorAndLength(listAllValues(filter), countAllValues(filter)); + public CursorAndLength load(Searchable searchable) { + log.debug("Creating cursor for `{}`", searchable.getId()); + return new CursorAndLength(listAllValues(searchable), countAllValues(searchable)); } }); @@ -156,16 +154,16 @@ public FrontendPreviewConfig getEntityPreviewFrontendConfig(Dataset dataset) { * Search for all search terms at once, with stricter scoring. * The user will upload a file and expect only well-corresponding resolutions. */ - public ResolvedConceptsResult resolveFilterValues(Searchable filter, List searchTerms) { + public ResolvedConceptsResult resolveFilterValues(Searchable searchable, List searchTerms) { // search in the full text engine final Set openSearchTerms = new HashSet<>(searchTerms); - final Namespace namespace = namespaces.get(filter.getDataset().getId()); + final Namespace namespace = namespaces.get(searchable.getDataset().getId()); final List out = new ArrayList<>(); - for (TrieSearch search : namespace.getFilterSearch().getSearchesFor(filter)) { + for (TrieSearch search : namespace.getFilterSearch().getSearchesFor(searchable)) { for (final Iterator iterator = openSearchTerms.iterator(); iterator.hasNext(); ) { final String searchTerm = iterator.next(); @@ -180,21 +178,20 @@ public ResolvedConceptsResult resolveFilterValues(Searchable filter, List id = ((Identifiable) filter).getId(); + // Not all Searchables are children of Connectors. + final ConnectorId connectorId = searchable instanceof Filter asFilter ? asFilter.getConnector().getId() : null; - - return new ResolvedConceptsResult(null, new ResolvedFilterResult(connectorId, id.toString(), out), openSearchTerms); + return new ResolvedConceptsResult(null, new ResolvedFilterResult(connectorId, searchable.getId().toString(), out), openSearchTerms); } - public > AutoCompleteResult autocompleteTextFilter(T filter, Optional maybeText, OptionalInt pageNumberOpt, OptionalInt itemsPerPageOpt) { + public AutoCompleteResult autocompleteTextFilter(Searchable searchable, Optional maybeText, OptionalInt pageNumberOpt, OptionalInt itemsPerPageOpt) { final int pageNumber = pageNumberOpt.orElse(0); final int itemsPerPage = itemsPerPageOpt.orElse(50); Preconditions.checkArgument(pageNumber >= 0, "Page number must be 0 or a positive integer."); Preconditions.checkArgument(itemsPerPage > 1, "Must at least have one item per page."); - log.trace("Searching for for `{}` in `{}`. (Page = {}, Items = {})", maybeText, filter.getId(), pageNumber, itemsPerPage); + log.trace("Searching for for `{}` in `{}`. (Page = {}, Items = {})", maybeText, searchable.getId(), pageNumber, itemsPerPage); final int startIncl = itemsPerPage * pageNumber; final int endExcl = startIncl + itemsPerPage; @@ -203,13 +200,13 @@ public > AutoCompleteResult autocompleteT // If we have none or a blank query string we list all values. if (maybeText.isEmpty() || maybeText.get().isBlank()) { - final CursorAndLength cursorAndLength = listResults.get(filter); + final CursorAndLength cursorAndLength = listResults.get(searchable); final Cursor cursor = cursorAndLength.values(); return new AutoCompleteResult(cursor.get(startIncl, endExcl), cursorAndLength.size()); } - final List fullResult = searchResults.get(Pair.of(filter, maybeText.get())); + final List fullResult = searchResults.get(Pair.of(searchable, maybeText.get())); if (startIncl >= fullResult.size()) { return new AutoCompleteResult(Collections.emptyList(), fullResult.size()); @@ -223,8 +220,8 @@ public > AutoCompleteResult autocompleteT } } - private Cursor listAllValues(Searchable filter) { - final Namespace namespace = namespaces.get(filter.getDataset().getId()); + private Cursor listAllValues(Searchable searchable) { + final Namespace namespace = namespaces.get(searchable.getDataset().getId()); /* Don't worry, I am as confused as you are! For some reason, flatMapped streams in conjunction with distinct will be evaluated full before further operation. @@ -235,7 +232,7 @@ private Cursor listAllValues(Searchable filter) { final Iterator iterators = - Iterators.concat(Iterators.transform(namespace.getFilterSearch().getSearchesFor(filter).iterator(), TrieSearch::iterator)); + Iterators.concat(Iterators.transform(namespace.getFilterSearch().getSearchesFor(searchable).iterator(), TrieSearch::iterator)); // Use Set to accomplish distinct values final Set seen = new HashSet<>(); @@ -243,19 +240,19 @@ private Cursor listAllValues(Searchable filter) { return new Cursor<>(Iterators.filter(iterators, seen::add)); } - private long countAllValues(Searchable filter) { - final Namespace namespace = namespaces.get(filter.getDataset().getId()); + private long countAllValues(Searchable searchable) { + final Namespace namespace = namespaces.get(searchable.getDataset().getId()); - return namespace.getFilterSearch().getTotal(filter); + return namespace.getFilterSearch().getTotal(searchable); } /** * Autocompletion for search terms. For values of {@link SelectFilter }. * Is used by the serach cache to load missing items */ - private List autocompleteTextFilter(Searchable filter, String text) { - final Namespace namespace = namespaces.get(filter.getDataset().getId()); + private List autocompleteTextFilter(Searchable searchable, String text) { + final Namespace namespace = namespaces.get(searchable.getDataset().getId()); // Note that FEValues is equals/hashcode only on value: // The different sources might contain duplicate FEValue#values which we want to avoid as @@ -263,7 +260,7 @@ private List autocompleteTextFilter(Searchable filter, String tex // Also note: currently we are still issuing large search requests, but much smaller allocations at once, and querying only when the past is not sufficient return namespace.getFilterSearch() - .getSearchesFor(filter) + .getSearchesFor(searchable) .stream() .map(search -> createSourceSearchResult(search, Collections.singletonList(text), OptionalInt.empty())) .flatMap(Collection::stream) From 340824c868e1c046c693b4f89355fe7062bbe2c9 Mon Sep 17 00:00:00 2001 From: awildturtok <1553491+awildturtok@users.noreply.github.com> Date: Thu, 9 Mar 2023 17:50:29 +0100 Subject: [PATCH 3/6] appeases the java type system demons --- .../com/bakdata/conquery/models/query/FilterSearch.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/src/main/java/com/bakdata/conquery/models/query/FilterSearch.java b/backend/src/main/java/com/bakdata/conquery/models/query/FilterSearch.java index 3175c02067..4be865eead 100644 --- a/backend/src/main/java/com/bakdata/conquery/models/query/FilterSearch.java +++ b/backend/src/main/java/com/bakdata/conquery/models/query/FilterSearch.java @@ -62,15 +62,15 @@ public static List extractKeywords(FrontendValue value) { /** * For a {@link SelectFilter} collect all relevant {@link TrieSearch}. */ - public List> getSearchesFor(Searchable filter) { - return filter.getSearchReferences().stream() + public List> getSearchesFor(Searchable searchable) { + return searchable.getSearchReferences().stream() .map(searchCache::get) .filter(Objects::nonNull) .collect(Collectors.toList()); } - public long getTotal(Searchable filter) { - return totals.getOrDefault(filter, 0); + public long getTotal(Searchable searchable) { + return totals.getOrDefault(searchable, 0); } From 332c34d2125ffbfac5521881d5f054900dd05e00 Mon Sep 17 00:00:00 2001 From: awildturtok <1553491+awildturtok@users.noreply.github.com> Date: Thu, 9 Mar 2023 18:05:54 +0100 Subject: [PATCH 4/6] appeases the java type system demons --- .../com/bakdata/conquery/models/datasets/Column.java | 2 +- .../conquery/models/datasets/concepts/Searchable.java | 2 +- .../concepts/filters/specific/SelectFilter.java | 4 ++-- .../conquery/models/jobs/UpdateFilterSearchJob.java | 10 +++++----- .../bakdata/conquery/models/query/FilterSearch.java | 6 +++--- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/backend/src/main/java/com/bakdata/conquery/models/datasets/Column.java b/backend/src/main/java/com/bakdata/conquery/models/datasets/Column.java index b46612e72f..c3f6c59b4e 100644 --- a/backend/src/main/java/com/bakdata/conquery/models/datasets/Column.java +++ b/backend/src/main/java/com/bakdata/conquery/models/datasets/Column.java @@ -170,7 +170,7 @@ public List> getSearches(IndexConfig config, Namespace } @Override - public List getSearchReferences() { + public List> getSearchReferences() { return List.of(this); } diff --git a/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/Searchable.java b/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/Searchable.java index 10b8090f1b..1047c74a4c 100644 --- a/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/Searchable.java +++ b/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/Searchable.java @@ -34,7 +34,7 @@ public interface Searchable>> * @implSpec The order of objects returned is used to also sort search results from different sources. */ @JsonIgnore - default List getSearchReferences() { + default List> getSearchReferences() { //Hopefully the only candidate will be Column return List.of(this); } diff --git a/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/filters/specific/SelectFilter.java b/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/filters/specific/SelectFilter.java index 531ec32c4b..e8f06ecc24 100644 --- a/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/filters/specific/SelectFilter.java +++ b/backend/src/main/java/com/bakdata/conquery/models/datasets/concepts/filters/specific/SelectFilter.java @@ -89,8 +89,8 @@ public boolean isNotUsingTemplateAndLabels() { private boolean generateSearchSuffixes = true; @Override - public List getSearchReferences() { - final List out = new ArrayList<>(); + public List> getSearchReferences() { + final List> out = new ArrayList<>(); if (getTemplate() != null) { out.add(getTemplate()); diff --git a/backend/src/main/java/com/bakdata/conquery/models/jobs/UpdateFilterSearchJob.java b/backend/src/main/java/com/bakdata/conquery/models/jobs/UpdateFilterSearchJob.java index 69364a541f..851e41757b 100644 --- a/backend/src/main/java/com/bakdata/conquery/models/jobs/UpdateFilterSearchJob.java +++ b/backend/src/main/java/com/bakdata/conquery/models/jobs/UpdateFilterSearchJob.java @@ -34,13 +34,13 @@ public class UpdateFilterSearchJob extends Job { private final NamespaceStorage storage; @NonNull - private final Map> searchCache; + private final Map, TrieSearch> searchCache; @NonNull private final IndexConfig indexConfig; @NonNull - private final Object2LongMap totals; + private final Object2LongMap> totals; @Override public void execute() throws Exception { @@ -58,7 +58,7 @@ public void execute() throws Exception { .collect(Collectors.toList()); - final Set collectedSearchables = + final Set> collectedSearchables = allSelectFilters.stream() .map(SelectFilter::getSearchReferences) .flatMap(Collection::stream) @@ -71,12 +71,12 @@ public void execute() throws Exception { // Most computations are cheap but data intensive: we fork here to use as many cores as possible. final ExecutorService service = Executors.newCachedThreadPool(); - final Map> synchronizedResult = Collections.synchronizedMap(searchCache); + final Map, TrieSearch> synchronizedResult = Collections.synchronizedMap(searchCache); log.debug("Found {} searchable Objects.", collectedSearchables.size()); - for (Searchable searchable : collectedSearchables) { + for (Searchable searchable : collectedSearchables) { service.submit(() -> { diff --git a/backend/src/main/java/com/bakdata/conquery/models/query/FilterSearch.java b/backend/src/main/java/com/bakdata/conquery/models/query/FilterSearch.java index 4be865eead..83d4836070 100644 --- a/backend/src/main/java/com/bakdata/conquery/models/query/FilterSearch.java +++ b/backend/src/main/java/com/bakdata/conquery/models/query/FilterSearch.java @@ -40,14 +40,14 @@ public class FilterSearch { * In the code below, the keys of this map will usually be called "reference". */ @JsonIgnore - private final Map> searchCache = new HashMap<>(); - private Object2LongMap totals = Object2LongMaps.emptyMap(); + private final Map, TrieSearch> searchCache = new HashMap<>(); + private Object2LongMap> totals = Object2LongMaps.emptyMap(); /** * From a given {@link FrontendValue} extract all relevant keywords. */ public static List extractKeywords(FrontendValue value) { - List keywords = new ArrayList<>(3); + final List keywords = new ArrayList<>(3); keywords.add(value.getLabel()); keywords.add(value.getValue()); From 9ee82d258998d127dd58cf93bf959d56e27b427c Mon Sep 17 00:00:00 2001 From: awildturtok <1553491+awildturtok@users.noreply.github.com> Date: Tue, 14 Mar 2023 15:20:58 +0100 Subject: [PATCH 5/6] cleanup ResolveConceptResult --- .../conquery/resources/api/ConceptsProcessor.java | 12 ++++++++---- .../conquery/resources/api/FilterResource.java | 3 +-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/backend/src/main/java/com/bakdata/conquery/resources/api/ConceptsProcessor.java b/backend/src/main/java/com/bakdata/conquery/resources/api/ConceptsProcessor.java index 257ce9d0b0..bb83822920 100644 --- a/backend/src/main/java/com/bakdata/conquery/resources/api/ConceptsProcessor.java +++ b/backend/src/main/java/com/bakdata/conquery/resources/api/ConceptsProcessor.java @@ -154,7 +154,7 @@ public FrontendPreviewConfig getEntityPreviewFrontendConfig(Dataset dataset) { * Search for all search terms at once, with stricter scoring. * The user will upload a file and expect only well-corresponding resolutions. */ - public ResolvedConceptsResult resolveFilterValues(Searchable searchable, List searchTerms) { + public ResolvedFilterValues resolveFilterValues(Searchable searchable, List searchTerms) { // search in the full text engine final Set openSearchTerms = new HashSet<>(searchTerms); @@ -181,7 +181,7 @@ public ResolvedConceptsResult resolveFilterValues(Searchable searchable, List // Not all Searchables are children of Connectors. final ConnectorId connectorId = searchable instanceof Filter asFilter ? asFilter.getConnector().getId() : null; - return new ResolvedConceptsResult(null, new ResolvedFilterResult(connectorId, searchable.getId().toString(), out), openSearchTerms); + return new ResolvedFilterValues(new ResolvedFilterResult(connectorId, searchable.getId().toString(), out), openSearchTerms); } public AutoCompleteResult autocompleteTextFilter(Searchable searchable, Optional maybeText, OptionalInt pageNumberOpt, OptionalInt itemsPerPageOpt) { @@ -309,7 +309,7 @@ public ResolvedConceptsResult resolveConceptElements(TreeConcept concept, List> resolvedConcepts, ResolvedFilterResult resolvedFilter, Collection unknownCodes) { + public record ResolvedFilterValues(ResolvedFilterResult resolvedFilter, Collection unknownCodes) { + + } + + public record ResolvedConceptsResult(Set> resolvedConcepts, Collection unknownCodes) { } } diff --git a/backend/src/main/java/com/bakdata/conquery/resources/api/FilterResource.java b/backend/src/main/java/com/bakdata/conquery/resources/api/FilterResource.java index 639e8de468..d3c77a85d5 100644 --- a/backend/src/main/java/com/bakdata/conquery/resources/api/FilterResource.java +++ b/backend/src/main/java/com/bakdata/conquery/resources/api/FilterResource.java @@ -21,7 +21,6 @@ import com.bakdata.conquery.models.auth.permissions.Ability; import com.bakdata.conquery.models.datasets.concepts.filters.Filter; import com.bakdata.conquery.models.datasets.concepts.filters.specific.SelectFilter; -import com.bakdata.conquery.resources.api.ConceptsProcessor.ResolvedConceptsResult; import com.bakdata.conquery.resources.hierarchies.HAuthorized; import lombok.NonNull; import lombok.RequiredArgsConstructor; @@ -44,7 +43,7 @@ public class FilterResource extends HAuthorized { @POST @Path("resolve") - public ResolvedConceptsResult resolveFilterValues(FilterValues filterValues) { + public ConceptsProcessor.ResolvedFilterValues resolveFilterValues(FilterValues filterValues) { subject.isPermitted(filter.getDataset(), Ability.READ); subject.isPermitted(filter.getConnector().findConcept(), Ability.READ); From 2828f6b1a2697427610e0b59eb21aeeacf00c095 Mon Sep 17 00:00:00 2001 From: awildturtok <1553491+awildturtok@users.noreply.github.com> Date: Tue, 14 Mar 2023 15:48:38 +0100 Subject: [PATCH 6/6] fixes splitting of type --- .../tests/FilterResolutionTest.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/backend/src/test/java/com/bakdata/conquery/integration/tests/FilterResolutionTest.java b/backend/src/test/java/com/bakdata/conquery/integration/tests/FilterResolutionTest.java index 1a5c1e8427..a5602a7cc0 100644 --- a/backend/src/test/java/com/bakdata/conquery/integration/tests/FilterResolutionTest.java +++ b/backend/src/test/java/com/bakdata/conquery/integration/tests/FilterResolutionTest.java @@ -27,7 +27,7 @@ import com.bakdata.conquery.models.identifiable.ids.specific.DatasetId; import com.bakdata.conquery.models.index.IndexService; import com.bakdata.conquery.resources.admin.rest.AdminDatasetResource; -import com.bakdata.conquery.resources.api.ConceptsProcessor.ResolvedConceptsResult; +import com.bakdata.conquery.resources.api.ConceptsProcessor; import com.bakdata.conquery.resources.api.FilterResource; import com.bakdata.conquery.resources.hierarchies.HierarchyHelper; import com.bakdata.conquery.util.support.StandaloneSupport; @@ -37,7 +37,7 @@ @Slf4j public class FilterResolutionTest extends IntegrationTest.Simple implements ProgrammaticIntegrationTest { - private String[] lines = new String[]{ + private final String[] lines = new String[]{ "HEADER", "a", "aab", @@ -48,28 +48,28 @@ public class FilterResolutionTest extends IntegrationTest.Simple implements Prog @Override public void execute(StandaloneSupport conquery) throws Exception { //read test sepcification - String + final String testJson = In.resource("/tests/query/MULTI_SELECT_DATE_RESTRICTION_OR_CONCEPT_QUERY/MULTI_SELECT_DATE_RESTRICTION_OR_CONCEPT_QUERY.test.json") .withUTF8() .readAll(); - DatasetId dataset = conquery.getDataset().getId(); + final DatasetId dataset = conquery.getDataset().getId(); - ConqueryTestSpec test = JsonIntegrationTest.readJson(dataset, testJson); + final ConqueryTestSpec test = JsonIntegrationTest.readJson(dataset, testJson); ValidatorHelper.failOnError(log, conquery.getValidator().validate(test)); - CSVConfig csvConf = conquery.getConfig().getCsv(); + final CSVConfig csvConf = conquery.getConfig().getCsv(); test.importRequiredData(conquery); conquery.waitUntilWorkDone(); - Concept concept = conquery.getNamespace().getStorage().getAllConcepts().iterator().next(); - Connector connector = concept.getConnectors().iterator().next(); - SelectFilter filter = (SelectFilter) connector.getFilters().iterator().next(); + final Concept concept = conquery.getNamespace().getStorage().getAllConcepts().iterator().next(); + final Connector connector = concept.getConnectors().iterator().next(); + final SelectFilter filter = (SelectFilter) connector.getFilters().iterator().next(); // Copy search csv from resources to tmp folder. final Path tmpCSv = Files.createTempFile("conquery_search", "csv"); @@ -112,7 +112,7 @@ public void execute(StandaloneSupport conquery) throws Exception { .request(MediaType.APPLICATION_JSON_TYPE) .post(Entity.entity(new FilterResource.FilterValues(List.of("a", "aaa", "unknown")), MediaType.APPLICATION_JSON_TYPE)); - ResolvedConceptsResult resolved = fromCsvResponse.readEntity(ResolvedConceptsResult.class); + final ConceptsProcessor.ResolvedFilterValues resolved = fromCsvResponse.readEntity(ConceptsProcessor.ResolvedFilterValues.class); //check the resolved values // "aaa" is hit by "a" and "aaa" therefore should be first @@ -126,7 +126,7 @@ public void execute(StandaloneSupport conquery) throws Exception { .request(MediaType.APPLICATION_JSON_TYPE) .post(Entity.entity(new FilterResource.FilterValues(List.of("f", "unknown")), MediaType.APPLICATION_JSON_TYPE)); - ResolvedConceptsResult resolved = fromCsvResponse.readEntity(ResolvedConceptsResult.class); + final ConceptsProcessor.ResolvedFilterValues resolved = fromCsvResponse.readEntity(ConceptsProcessor.ResolvedFilterValues.class); //check the resolved values assertThat(resolved.resolvedFilter().value().stream().map(FrontendValue::getValue)).contains("f");