generated from amazon-archives/__template_Custom
-
Notifications
You must be signed in to change notification settings - Fork 169
[GRPC] Extend transport-grpc module to support GRPC KNN queries #2817
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
e3e348f
[GRPC] Extend transport-grpc plugin to support GRPC KNN queries and u…
karenyrx 3676f2d
Merge branch 'main' into knnpr2
navneet1v 8962329
use @utility and refactor into smaller methods
karenyrx 98a17ed
Force bundle guava dependencies
karenyrx 017a779
Force bundle failure access only not guava, and upgrade guava to match
karenyrx 5d92f7e
Downgrade failure access back and dont force
karenyrx 59f7430
force deps for tests
karenyrx c19d576
Merge branch 'main' into knnpr2
0ctopus13prime b5bd432
use 32.1.3 original
karenyrx e996916
move from changlog to 3.2. release notes
karenyrx 590361c
Revert "move from changlog to 3.2. release notes"
karenyrx d11c5d7
Revert "Revert "move from changlog to 3.2. release notes""
karenyrx fbb43eb
force resolution for all, not just tests, and resolve changelog
karenyrx 501d359
filter out jacoco
karenyrx 86ec89d
exclude guava and failure access from transport-grpc
karenyrx 3b2ad7c
upgrade failureaccess and guava to match core, and make guava a test …
karenyrx bf81900
Merge branch 'main' into knnpr2
karenyrx 72c5832
fix unit test
karenyrx File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
32 changes: 32 additions & 0 deletions
32
...ava/org/opensearch/knn/grpc/proto/request/search/query/KNNQueryBuilderProtoConverter.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| /* | ||
| * Copyright OpenSearch Contributors | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
|
|
||
| package org.opensearch.knn.grpc.proto.request.search.query; | ||
|
|
||
| import org.opensearch.index.query.QueryBuilder; | ||
| import org.opensearch.transport.grpc.proto.request.search.query.QueryBuilderProtoConverter; | ||
| import org.opensearch.protobufs.QueryContainer; | ||
|
|
||
| /** | ||
| * Converter for KNN queries. | ||
| * This class implements the QueryBuilderProtoConverter interface to provide KNN query support | ||
| * for the gRPC transport plugin. | ||
| */ | ||
| public class KNNQueryBuilderProtoConverter implements QueryBuilderProtoConverter { | ||
|
|
||
| @Override | ||
| public QueryContainer.QueryContainerCase getHandledQueryCase() { | ||
| return QueryContainer.QueryContainerCase.KNN; | ||
| } | ||
|
|
||
| @Override | ||
| public QueryBuilder fromProto(QueryContainer queryContainer) { | ||
| if (queryContainer == null || queryContainer.getQueryContainerCase() != QueryContainer.QueryContainerCase.KNN) { | ||
| throw new IllegalArgumentException("QueryContainer does not contain a KNN query"); | ||
| } | ||
|
|
||
| return KNNQueryBuilderProtoUtils.fromProto(queryContainer.getKnn()); | ||
| } | ||
| } | ||
226 changes: 226 additions & 0 deletions
226
...in/java/org/opensearch/knn/grpc/proto/request/search/query/KNNQueryBuilderProtoUtils.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,226 @@ | ||
| /* | ||
| * Copyright OpenSearch Contributors | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
|
|
||
| package org.opensearch.knn.grpc.proto.request.search.query; | ||
|
|
||
| import lombok.experimental.UtilityClass; | ||
| import org.opensearch.core.xcontent.XContentParser; | ||
| import org.opensearch.index.query.QueryBuilder; | ||
| import org.opensearch.knn.index.query.KNNQueryBuilder; | ||
| import org.opensearch.knn.index.query.parser.KNNQueryBuilderParser; | ||
| import org.opensearch.knn.index.query.request.MethodParameter; | ||
| import org.opensearch.knn.index.query.rescore.RescoreContext; | ||
| import org.opensearch.transport.grpc.proto.request.search.query.QueryBuilderProtoConverterRegistry; | ||
| import org.opensearch.protobufs.KnnQuery; | ||
| import org.opensearch.protobufs.KnnQueryRescore; | ||
| import org.opensearch.protobufs.QueryContainer; | ||
|
|
||
| import java.util.HashMap; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
|
|
||
| /** | ||
| * Utility class for converting KNN Protocol Buffers to OpenSearch objects. | ||
| * This class provides methods to transform Protocol Buffer representations of KNN queries | ||
| * into their corresponding OpenSearch KNNQueryBuilder implementations for search operations. | ||
| */ | ||
| @UtilityClass | ||
| public class KNNQueryBuilderProtoUtils { | ||
|
|
||
| // Registry for query conversion | ||
| private static QueryBuilderProtoConverterRegistry REGISTRY = new QueryBuilderProtoConverterRegistry(); | ||
|
|
||
| /** | ||
| * Sets the registry for testing purposes. | ||
| * | ||
| * @param registry The registry to use | ||
| */ | ||
| void setRegistry(QueryBuilderProtoConverterRegistry registry) { | ||
| REGISTRY = registry; | ||
| } | ||
|
|
||
| /** | ||
| * Gets the current registry. | ||
| * | ||
| * @return The current registry | ||
| */ | ||
| QueryBuilderProtoConverterRegistry getRegistry() { | ||
| return REGISTRY; | ||
| } | ||
|
|
||
| /** | ||
| * Converts a Protocol Buffer KnnQuery to an OpenSearch KNNQueryBuilder. | ||
| * This method follows the exact same pattern as {@link KNNQueryBuilderParser#fromXContent(XContentParser)} | ||
| * to ensure parsing consistency and compatibility. | ||
| * | ||
| * @param knnQueryProto The Protocol Buffer KnnQuery to convert | ||
| * @return A configured KNNQueryBuilder instance | ||
| */ | ||
| public QueryBuilder fromProto(KnnQuery knnQueryProto) { | ||
| // Create builder using the internal parser pattern like XContent parsing | ||
| KNNQueryBuilder.Builder builder = KNNQueryBuilder.builder(); | ||
|
|
||
| // Set field name (equivalent to fieldName parsing in XContent) | ||
| builder.fieldName(knnQueryProto.getField()); | ||
|
|
||
| // Set vector (equivalent to VECTOR_FIELD parsing) | ||
| builder.vector(convertVector(knnQueryProto.getVectorList())); | ||
|
|
||
| // Set k if present (equivalent to K_FIELD parsing) | ||
| if (knnQueryProto.getK() > 0) { | ||
| builder.k(knnQueryProto.getK()); | ||
| } | ||
|
|
||
| // Set maxDistance if present (equivalent to MAX_DISTANCE_FIELD parsing) | ||
| else if (knnQueryProto.hasMaxDistance()) { | ||
| builder.maxDistance(knnQueryProto.getMaxDistance()); | ||
| } | ||
|
|
||
| // Set minScore if present (equivalent to MIN_SCORE_FIELD parsing) | ||
| else if (knnQueryProto.hasMinScore()) { | ||
| builder.minScore(knnQueryProto.getMinScore()); | ||
| } | ||
|
|
||
| // Set method parameters (equivalent to METHOD_PARAMS_FIELD parsing) | ||
| if (knnQueryProto.hasMethodParameters()) { | ||
| Map<String, ?> methodParameters = convertMethodParameters(knnQueryProto.getMethodParameters()); | ||
| builder.methodParameters(methodParameters); | ||
| } | ||
|
|
||
| // Set filter (equivalent to FILTER_FIELD parsing) | ||
| if (knnQueryProto.hasFilter()) { | ||
| QueryContainer filterQueryContainer = knnQueryProto.getFilter(); | ||
| builder.filter(REGISTRY.fromProto(filterQueryContainer)); | ||
| } | ||
|
|
||
| // Set rescore (equivalent to RESCORE_FIELD parsing) | ||
| if (knnQueryProto.hasRescore()) { | ||
| RescoreContext rescoreContext = convertRescoreContext(knnQueryProto.getRescore()); | ||
| builder.rescoreContext(rescoreContext); | ||
| } | ||
|
|
||
| // Set boost (equivalent to BOOST_FIELD parsing) | ||
| if (knnQueryProto.hasBoost()) { | ||
| builder.boost(knnQueryProto.getBoost()); | ||
| } | ||
|
|
||
| // Set query name (equivalent to NAME_FIELD parsing) | ||
| if (knnQueryProto.hasUnderscoreName()) { | ||
| builder.queryName(knnQueryProto.getUnderscoreName()); | ||
| } | ||
|
|
||
| // Set expandNested (equivalent to EXPAND_NESTED_FIELD parsing) | ||
| if (knnQueryProto.hasExpandNestedDocs()) { | ||
| builder.expandNested(knnQueryProto.getExpandNestedDocs()); | ||
| } | ||
|
|
||
| return builder.build(); | ||
| } | ||
|
|
||
| /** | ||
| * Converts a Protocol Buffer vector list to a float array. | ||
| * | ||
| * @param vectorList The Protocol Buffer vector list | ||
| * @return The converted float array | ||
| */ | ||
| private float[] convertVector(List<Float> vectorList) { | ||
| float[] vector = new float[vectorList.size()]; | ||
| for (int i = 0; i < vectorList.size(); i++) { | ||
| vector[i] = vectorList.get(i); | ||
| } | ||
| return vector; | ||
| } | ||
|
|
||
| /** | ||
| * Converts Protocol Buffer method parameters following the exact same pattern as | ||
| * {@link MethodParametersParser#fromXContent(XContentParser)} to ensure consistency. | ||
| * | ||
| * @param objectMap The Protocol Buffer ObjectMap to convert | ||
| * @return The converted method parameters Map | ||
| */ | ||
| private Map<String, ?> convertMethodParameters(org.opensearch.protobufs.ObjectMap objectMap) { | ||
| // First convert Protocol Buffer to raw Map (equivalent to parser.map()) | ||
| Map<String, Object> rawMethodParameters = new HashMap<>(); | ||
| for (Map.Entry<String, org.opensearch.protobufs.ObjectMap.Value> entry : objectMap.getFieldsMap().entrySet()) { | ||
| String key = entry.getKey(); | ||
| Object value = convertObjectMapValue(entry.getValue()); | ||
| if (value != null) { | ||
| rawMethodParameters.put(key, value); | ||
| } | ||
| } | ||
|
|
||
| // Then process through MethodParameter.parse() exactly like XContent parsing does | ||
| Map<String, Object> processedMethodParameters = new HashMap<>(); | ||
| for (Map.Entry<String, Object> entry : rawMethodParameters.entrySet()) { | ||
| String name = entry.getKey(); | ||
| Object value = entry.getValue(); | ||
|
|
||
| // Find the MethodParameter enum (same as XContent parsing) | ||
| MethodParameter parameter = MethodParameter.enumOf(name); | ||
| if (parameter == null) { | ||
| throw new IllegalArgumentException("unknown method parameter found [" + name + "]"); | ||
| } | ||
|
|
||
| try { | ||
| // Parse using MethodParameter.parse() - this handles type conversion properly | ||
| Object parsedValue = parameter.parse(value); | ||
| processedMethodParameters.put(name, parsedValue); | ||
| } catch (Exception exception) { | ||
| throw new IllegalArgumentException("Error parsing method parameter [" + name + "]: " + exception.getMessage()); | ||
| } | ||
| } | ||
|
|
||
| return processedMethodParameters.isEmpty() ? null : processedMethodParameters; | ||
| } | ||
|
|
||
| /** | ||
| * Converts a Protocol Buffer ObjectMap.Value to a Java Object. | ||
| * | ||
| * @param value The Protocol Buffer Value to convert | ||
| * @return The converted Java Object, or null if unsupported type | ||
| */ | ||
| private Object convertObjectMapValue(org.opensearch.protobufs.ObjectMap.Value value) { | ||
| switch (value.getValueCase()) { | ||
| case INT32: | ||
| return value.getInt32(); | ||
| case INT64: | ||
| return value.getInt64(); | ||
| case FLOAT: | ||
| return value.getFloat(); | ||
| case DOUBLE: | ||
| return value.getDouble(); | ||
| case STRING: | ||
| return value.getString(); | ||
| case BOOL: | ||
| return value.getBool(); | ||
| default: | ||
| // Skip unsupported types | ||
| return null; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Converts a Protocol Buffer KnnQueryRescore to a RescoreContext. | ||
| * | ||
| * @param rescoreProto The Protocol Buffer KnnQueryRescore to convert | ||
| * @return The converted RescoreContext | ||
| */ | ||
| private RescoreContext convertRescoreContext(KnnQueryRescore rescoreProto) { | ||
| switch (rescoreProto.getKnnQueryRescoreCase()) { | ||
| case ENABLE: | ||
| return rescoreProto.getEnable() ? RescoreContext.getDefault() : RescoreContext.EXPLICITLY_DISABLED_RESCORE_CONTEXT; | ||
|
|
||
| case CONTEXT: | ||
| org.opensearch.protobufs.RescoreContext contextProto = rescoreProto.getContext(); | ||
| return contextProto.hasOversampleFactor() | ||
| ? RescoreContext.builder().oversampleFactor(contextProto.getOversampleFactor()).build() | ||
| : RescoreContext.getDefault(); | ||
|
|
||
| default: | ||
| return RescoreContext.getDefault(); | ||
| } | ||
| } | ||
|
|
||
| } |
1 change: 1 addition & 0 deletions
1
...vices/org.opensearch.transport.grpc.proto.request.search.query.QueryBuilderProtoConverter
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| org.opensearch.knn.grpc.proto.request.search.query.KNNQueryBuilderProtoConverter |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.