Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
- [Search Stats] Add search & star-tree search query failure count metrics ([#19210](https://github.com/opensearch-project/OpenSearch/issues/19210))
- [Star-tree] Support for multi-terms aggregation ([#18398](https://github.com/opensearch-project/OpenSearch/issues/18398))
- Add stream search feature flag and auto fallback logic ([#19373](https://github.com/opensearch-project/OpenSearch/pull/19373))
- Implement GRPC Exists, Regexp, and Wildcard queries ([#19392](https://github.com/opensearch-project/OpenSearch/pull/19392))
- Implement GRPC GeoBoundingBox, GeoDistance queries ([#19451](https://github.com/opensearch-project/OpenSearch/pull/19451))
- Implement GRPC Ids, Range, and Terms Set queries ([#19448](https://github.com/opensearch-project/OpenSearch/pull/19448))
- Implement GRPC Nested query ([#19453](https://github.com/opensearch-project/OpenSearch/pull/19453))

### Changed
- Refactor `if-else` chains to use `Java 17 pattern matching switch expressions`(([#18965](https://github.com/opensearch-project/OpenSearch/pull/18965))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/

package org.opensearch.transport.grpc.proto.request.search.query;

import org.opensearch.index.query.QueryBuilder;
import org.opensearch.protobufs.QueryContainer;
import org.opensearch.transport.grpc.spi.QueryBuilderProtoConverter;
import org.opensearch.transport.grpc.spi.QueryBuilderProtoConverterRegistry;

/**
* Converter for NestedQuery protobuf messages to OpenSearch QueryBuilder objects.
* Handles the conversion of nested query protobuf messages to OpenSearch NestedQueryBuilder.
*/
public class NestedQueryBuilderProtoConverter implements QueryBuilderProtoConverter {

/**
* Default constructor for NestedQueryBuilderProtoConverter.
*/
public NestedQueryBuilderProtoConverter() {}

private QueryBuilderProtoConverterRegistry registry;

@Override
public void setRegistry(QueryBuilderProtoConverterRegistry registry) {
this.registry = registry;
// The utility class no longer stores the registry statically, it's passed directly to fromProto
}

@Override
public QueryContainer.QueryContainerCase getHandledQueryCase() {
return QueryContainer.QueryContainerCase.NESTED;
}

@Override
public QueryBuilder fromProto(QueryContainer queryContainer) {
if (queryContainer == null || queryContainer.getQueryContainerCase() != QueryContainer.QueryContainerCase.NESTED) {
throw new IllegalArgumentException("QueryContainer must contain a NestedQuery");
}
return NestedQueryBuilderProtoUtils.fromProto(queryContainer.getNested(), registry);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/

package org.opensearch.transport.grpc.proto.request.search.query;

import org.apache.lucene.search.join.ScoreMode;
import org.opensearch.index.query.AbstractQueryBuilder;
import org.opensearch.index.query.InnerHitBuilder;
import org.opensearch.index.query.NestedQueryBuilder;
import org.opensearch.index.query.QueryBuilder;
import org.opensearch.protobufs.ChildScoreMode;
import org.opensearch.protobufs.NestedQuery;
import org.opensearch.protobufs.QueryContainer;
import org.opensearch.transport.grpc.proto.request.search.InnerHitsBuilderProtoUtils;
import org.opensearch.transport.grpc.spi.QueryBuilderProtoConverterRegistry;

/**
* Utility class for converting protobuf NestedQuery to OpenSearch NestedQueryBuilder.
* Handles the conversion of nested query protobuf messages to OpenSearch NestedQueryBuilder objects.
*/
class NestedQueryBuilderProtoUtils {

private NestedQueryBuilderProtoUtils() {
// Utility class, no instances
}

/**
* Converts a protobuf NestedQuery to an OpenSearch NestedQueryBuilder.
* Similar to {@link NestedQueryBuilder#fromXContent(org.opensearch.core.xcontent.XContentParser)}, this method
* parses the Protocol Buffer representation and creates a properly configured
* NestedQueryBuilder with the appropriate path, query, score mode, inner hits, boost, and query name.
*
* @param nestedQueryProto the protobuf NestedQuery to convert
* @param registry The registry to use for converting nested queries
* @return the converted OpenSearch NestedQueryBuilder
* @throws IllegalArgumentException if the protobuf query is invalid
*/
static NestedQueryBuilder fromProto(NestedQuery nestedQueryProto, QueryBuilderProtoConverterRegistry registry) {
if (nestedQueryProto == null) {
throw new IllegalArgumentException("NestedQuery cannot be null");
}

float boost = AbstractQueryBuilder.DEFAULT_BOOST;
ScoreMode scoreMode = ScoreMode.Avg;
String queryName = null;
QueryBuilder query = null;
InnerHitBuilder innerHitBuilder = null;
boolean ignoreUnmapped = NestedQueryBuilder.DEFAULT_IGNORE_UNMAPPED;

String path = nestedQueryProto.getPath();
if (path.isEmpty()) {
throw new IllegalArgumentException("Path is required for NestedQuery");
}

if (!nestedQueryProto.hasQuery()) {
throw new IllegalArgumentException("Query is required for NestedQuery");
}
try {
QueryContainer queryContainer = nestedQueryProto.getQuery();
query = registry.fromProto(queryContainer);
} catch (Exception e) {
throw new IllegalArgumentException("Failed to convert inner query for NestedQuery: " + e.getMessage(), e);
}

if (nestedQueryProto.hasScoreMode()) {
scoreMode = parseScoreMode(nestedQueryProto.getScoreMode());
}

if (nestedQueryProto.hasIgnoreUnmapped()) {
ignoreUnmapped = nestedQueryProto.getIgnoreUnmapped();
}

if (nestedQueryProto.hasBoost()) {
boost = nestedQueryProto.getBoost();
}

if (nestedQueryProto.hasXName()) {
queryName = nestedQueryProto.getXName();
}

if (nestedQueryProto.hasInnerHits()) {
try {
innerHitBuilder = InnerHitsBuilderProtoUtils.fromProto(nestedQueryProto.getInnerHits());
} catch (Exception e) {
throw new IllegalArgumentException("Failed to convert inner hits for NestedQuery: " + e.getMessage(), e);
}
}

NestedQueryBuilder queryBuilder = new NestedQueryBuilder(path, query, scoreMode, innerHitBuilder).ignoreUnmapped(ignoreUnmapped)
.queryName(queryName)
.boost(boost);

return queryBuilder;
}

/**
* Converts protobuf ChildScoreMode to Lucene ScoreMode.
*
* @param childScoreMode the protobuf ChildScoreMode
* @return the converted Lucene ScoreMode
*/
private static ScoreMode parseScoreMode(ChildScoreMode childScoreMode) {
switch (childScoreMode) {
case CHILD_SCORE_MODE_AVG:
return ScoreMode.Avg;
case CHILD_SCORE_MODE_MAX:
return ScoreMode.Max;
case CHILD_SCORE_MODE_MIN:
return ScoreMode.Min;
case CHILD_SCORE_MODE_NONE:
return ScoreMode.None;
case CHILD_SCORE_MODE_SUM:
return ScoreMode.Total;
default:
return ScoreMode.Avg; // Default value
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,11 @@ protected void registerBuiltInConverters() {
delegate.registerConverter(new ExistsQueryBuilderProtoConverter());
delegate.registerConverter(new RegexpQueryBuilderProtoConverter());
delegate.registerConverter(new WildcardQueryBuilderProtoConverter());
delegate.registerConverter(new NestedQueryBuilderProtoConverter());

// Set the registry on all converters so they can access each other
delegate.setRegistryOnAllConverters(this);

logger.info("Registered {} built-in query converters", delegate.size());
}

Expand Down
Loading
Loading