diff --git a/cineast-api/src/main/java/org/vitrivr/cineast/api/APIEndpoint.java b/cineast-api/src/main/java/org/vitrivr/cineast/api/APIEndpoint.java index 5f00442d1..1997caccd 100644 --- a/cineast-api/src/main/java/org/vitrivr/cineast/api/APIEndpoint.java +++ b/cineast-api/src/main/java/org/vitrivr/cineast/api/APIEndpoint.java @@ -38,6 +38,7 @@ import org.vitrivr.cineast.api.rest.handlers.actions.metadata.FindSegmentMetadataGetHandler; import org.vitrivr.cineast.api.rest.handlers.actions.segment.FindSegmentByIdPostHandler; import org.vitrivr.cineast.api.rest.handlers.actions.segment.FindSegmentSimilarPostHandler; +import org.vitrivr.cineast.api.rest.handlers.actions.segment.FindSegmentSimilarStagedPostHandler; import org.vitrivr.cineast.api.rest.handlers.actions.segment.FindSegmentsByIdGetHandler; import org.vitrivr.cineast.api.rest.handlers.actions.segment.FindSegmentsByObjectIdGetHandler; import org.vitrivr.cineast.api.rest.handlers.actions.session.EndExtractionHandler; @@ -291,21 +292,13 @@ public Javalin dispatchService(boolean secure) { this.webSocketApi = new WebsocketAPI(); service.ws(String.format("%s/websocket", namespace()), handler -> { - handler.onConnect(ctx -> { - webSocketApi.connected(ctx.session); - }); + handler.onConnect(ctx -> webSocketApi.connected(ctx.session)); - handler.onClose(ctx -> { - webSocketApi.closed(ctx.session, ctx.status(), ctx.reason()); - }); + handler.onClose(ctx -> webSocketApi.closed(ctx.session, ctx.status(), ctx.reason())); - handler.onError(ctx -> { - webSocketApi.onWebSocketException(ctx.session, ctx.error()); - }); + handler.onError(ctx -> webSocketApi.onWebSocketException(ctx.session, ctx.error())); - handler.onMessage(ctx -> { - webSocketApi.message(ctx.session, ctx.message()); - }); + handler.onMessage(ctx -> webSocketApi.message(ctx.session, ctx.message())); }); } @@ -413,6 +406,7 @@ private void registerRestOperations() { new FindSegmentsByIdGetHandler(), new FindSegmentsByObjectIdGetHandler(), new FindSegmentSimilarPostHandler(retrievalLogic), + new FindSegmentSimilarStagedPostHandler(retrievalLogic), new FindSegmentFeaturesGetHandler(), new FindFeaturesByCategoryGetHandler(), new FindFeaturesByEntityGetHandler(), @@ -439,9 +433,6 @@ private void registerRestOperations() { /** * If configured, this registers two special routes that serve the media objects as media content and additionally a thumbnails endpoint for them. - * - * @param service - * @param config */ private void registerServingRoutes(final Javalin service, final APIConfig config) { if (config.getServeContent()) { diff --git a/cineast-api/src/main/java/org/vitrivr/cineast/api/rest/handlers/actions/segment/FindSegmentSimilarPostHandler.java b/cineast-api/src/main/java/org/vitrivr/cineast/api/rest/handlers/actions/segment/FindSegmentSimilarPostHandler.java index 1f3270314..46e7f18e4 100644 --- a/cineast-api/src/main/java/org/vitrivr/cineast/api/rest/handlers/actions/segment/FindSegmentSimilarPostHandler.java +++ b/cineast-api/src/main/java/org/vitrivr/cineast/api/rest/handlers/actions/segment/FindSegmentSimilarPostHandler.java @@ -11,12 +11,10 @@ import org.vitrivr.cineast.api.messages.result.SimilarityQueryResultBatch; import org.vitrivr.cineast.api.rest.handlers.interfaces.ParsingPostRestHandler; import org.vitrivr.cineast.api.util.QueryUtil; -import org.vitrivr.cineast.core.config.QueryConfig; import org.vitrivr.cineast.core.config.ReadableQueryConfig; import org.vitrivr.cineast.core.data.Pair; import org.vitrivr.cineast.core.data.StringDoublePair; import org.vitrivr.cineast.core.data.query.containers.AbstractQueryTermContainer; -import org.vitrivr.cineast.standalone.config.Config; import org.vitrivr.cineast.standalone.config.ConstrainedQueryConfig; import org.vitrivr.cineast.standalone.util.ContinuousRetrievalLogic; @@ -31,6 +29,7 @@ public FindSegmentSimilarPostHandler(ContinuousRetrievalLogic continuousRetrieva @Override public SimilarityQueryResultBatch performPost(SimilarityQuery query, Context ctx) { + ConstrainedQueryConfig config = ConstrainedQueryConfig.getApplyingConfig(query.getQueryConfig()); HashMap> returnMap = new HashMap<>(); /* @@ -38,21 +37,12 @@ public SimilarityQueryResultBatch performPost(SimilarityQuery query, Context ctx */ HashMap> categoryMap = QueryUtil.groupQueryTermsByCategory(query.getTerms()); - QueryConfig config = query.getQueryConfig(); - ConstrainedQueryConfig qconf = new ConstrainedQueryConfig(config); - if (config == null) { - final int max = Math.min(qconf.getMaxResults().orElse(Config.sharedConfig().getRetriever().getMaxResults()), Config.sharedConfig().getRetriever().getMaxResults()); - qconf.setMaxResults(max); - final int resultsPerModule = Math.min(qconf.getRawResultsPerModule() == -1 ? Config.sharedConfig().getRetriever().getMaxResultsPerModule() : qconf.getResultsPerModule(), Config.sharedConfig().getRetriever().getMaxResultsPerModule()); - qconf.setResultsPerModule(resultsPerModule); - } - for (String category : categoryMap.keySet()) { - List> containerList = categoryMap.get(category).stream().map(x -> new Pair<>(x, (ReadableQueryConfig) qconf)).collect(Collectors.toList()); + List> containerList = categoryMap.get(category).stream().map(x -> new Pair<>(x, (ReadableQueryConfig) config)).collect(Collectors.toList()); returnMap.put(category, QueryUtil.retrieveCategory(continuousRetrievalLogic, containerList, category)); } - return new SimilarityQueryResultBatch(returnMap, qconf.getQueryId().toString()); + return new SimilarityQueryResultBatch(returnMap, config.getQueryId().toString()); } @Override diff --git a/cineast-api/src/main/java/org/vitrivr/cineast/api/rest/handlers/actions/segment/FindSegmentSimilarStagedPostHandler.java b/cineast-api/src/main/java/org/vitrivr/cineast/api/rest/handlers/actions/segment/FindSegmentSimilarStagedPostHandler.java new file mode 100644 index 000000000..e7fdb3f6e --- /dev/null +++ b/cineast-api/src/main/java/org/vitrivr/cineast/api/rest/handlers/actions/segment/FindSegmentSimilarStagedPostHandler.java @@ -0,0 +1,69 @@ +package org.vitrivr.cineast.api.rest.handlers.actions.segment; + +import io.javalin.http.Context; +import io.javalin.plugin.openapi.dsl.OpenApiBuilder; +import io.javalin.plugin.openapi.dsl.OpenApiDocumentation; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.vitrivr.cineast.api.messages.query.QueryStage; +import org.vitrivr.cineast.api.messages.query.QueryTerm; +import org.vitrivr.cineast.api.messages.query.StagedSimilarityQuery; +import org.vitrivr.cineast.api.messages.result.SimilarityQueryResultBatch; +import org.vitrivr.cineast.api.rest.handlers.interfaces.ParsingPostRestHandler; +import org.vitrivr.cineast.standalone.config.ConstrainedQueryConfig; +import org.vitrivr.cineast.standalone.util.ContinuousRetrievalLogic; + +public class FindSegmentSimilarStagedPostHandler implements ParsingPostRestHandler { + + public static final String ROUTE = "find/segments/similar/staged"; + private final ContinuousRetrievalLogic continuousRetrievalLogic; + + private static final Logger LOGGER = LogManager.getLogger(); + + public FindSegmentSimilarStagedPostHandler(ContinuousRetrievalLogic continuousRetrievalLogic) { + this.continuousRetrievalLogic = continuousRetrievalLogic; + } + + + @Override + public OpenApiDocumentation docs() { + return OpenApiBuilder.document() + .operation(op -> { + op.summary("Find similar segments based on the given staged query"); + op.description("Performs a similarity search based on the formulated query stages, executing each subsequent stage on the results of the previous stage"); + op.operationId("findSegmentSimilarStaged"); + op.addTagsItem("Segments"); + }) + .body(inClass()) + .json("200", outClass()); + } + + @Override + public SimilarityQueryResultBatch performPost(StagedSimilarityQuery query, Context ctx) { + ConstrainedQueryConfig config = ConstrainedQueryConfig.getApplyingConfig(query.getConfig()); + + // TODO: Could staged queries be pushed down to DB to optimize? + for (QueryStage stage : query.getStages()) { + for (QueryTerm term : stage.terms) { + // TODO + } + } + + return null; + } + + @Override + public Class inClass() { + return StagedSimilarityQuery.class; + } + + @Override + public Class outClass() { + return SimilarityQueryResultBatch.class; + } + + @Override + public String route() { + return ROUTE; + } +} diff --git a/cineast-api/src/main/java/org/vitrivr/cineast/api/util/QueryUtil.java b/cineast-api/src/main/java/org/vitrivr/cineast/api/util/QueryUtil.java index 633fa3606..d1fdd094e 100644 --- a/cineast-api/src/main/java/org/vitrivr/cineast/api/util/QueryUtil.java +++ b/cineast-api/src/main/java/org/vitrivr/cineast/api/util/QueryUtil.java @@ -76,6 +76,7 @@ public static List retrieveCategory( list.sort(StringDoublePair.COMPARATOR); + // FIXME: Using an arbitrary query config to limit results is prone to errors final int MAX_RESULTS = queryContainers.get(0).second.getMaxResults() .orElse(Config.sharedConfig().getRetriever().getMaxResults()); List resultList = list; diff --git a/cineast-runtime/src/main/java/org/vitrivr/cineast/standalone/config/ConstrainedQueryConfig.java b/cineast-runtime/src/main/java/org/vitrivr/cineast/standalone/config/ConstrainedQueryConfig.java index 2c088969b..efd276937 100644 --- a/cineast-runtime/src/main/java/org/vitrivr/cineast/standalone/config/ConstrainedQueryConfig.java +++ b/cineast-runtime/src/main/java/org/vitrivr/cineast/standalone/config/ConstrainedQueryConfig.java @@ -8,29 +8,40 @@ public class ConstrainedQueryConfig extends QueryConfig { - public ConstrainedQueryConfig(String queryId, List hints) { - super(queryId, hints); + public ConstrainedQueryConfig(String queryId, List hints) { + super(queryId, hints); + } + + public ConstrainedQueryConfig(ReadableQueryConfig qc) { + super(qc); + } + + public ConstrainedQueryConfig() { + super(null); + } + + @Override + public int getResultsPerModule() { + return Math.min(Config.sharedConfig().getRetriever().getMaxResultsPerModule(), super.getResultsPerModule()); + } + + @Override + public Optional getMaxResults() { + if (super.getMaxResults().isPresent()) { + return Optional.of(Math.min(Config.sharedConfig().getRetriever().getMaxResults(), super.getMaxResults().get())); } - - public ConstrainedQueryConfig(ReadableQueryConfig qc) { - super(qc); - } - - public ConstrainedQueryConfig() { - super(null); - } - - @Override - public int getResultsPerModule() { return Math.min(Config.sharedConfig().getRetriever().getMaxResultsPerModule(), super.getResultsPerModule()); } - - @Override - public Optional getMaxResults() { - if (super.getMaxResults().isPresent()) { - return Optional.of(Math.min(Config.sharedConfig().getRetriever().getMaxResults(), super.getMaxResults().get())); - } - return Optional.of(Config.sharedConfig().getRetriever().getMaxResults()); + return Optional.of(Config.sharedConfig().getRetriever().getMaxResults()); + } + + public static ConstrainedQueryConfig getApplyingConfig(QueryConfig config) { + ConstrainedQueryConfig queryConfig = new ConstrainedQueryConfig(config); + if (config == null) { + final int max = Math.min(queryConfig.getMaxResults().orElse(Config.sharedConfig().getRetriever().getMaxResults()), Config.sharedConfig().getRetriever().getMaxResults()); + queryConfig.setMaxResults(max); + final int resultsPerModule = Math.min(queryConfig.getRawResultsPerModule() == -1 ? Config.sharedConfig().getRetriever().getMaxResultsPerModule() : queryConfig.getResultsPerModule(), Config.sharedConfig().getRetriever().getMaxResultsPerModule()); + queryConfig.setResultsPerModule(resultsPerModule); } - - + return queryConfig; + } }