diff --git a/server/src/main/java/org/elasticsearch/search/builder/SearchSourceBuilder.java b/server/src/main/java/org/elasticsearch/search/builder/SearchSourceBuilder.java index 35beb5dd002f6..3e7021624881a 100644 --- a/server/src/main/java/org/elasticsearch/search/builder/SearchSourceBuilder.java +++ b/server/src/main/java/org/elasticsearch/search/builder/SearchSourceBuilder.java @@ -1348,6 +1348,9 @@ private SearchSourceBuilder parseXContent( } } else if (token == XContentParser.Token.START_OBJECT) { if (RETRIEVER.match(currentFieldName, parser.getDeprecationHandler())) { + if (clusterSupportsFeature.test(RetrieverBuilder.NODE_FEATURE) == false) { + throw new ParsingException(parser.getTokenLocation(), "Unknown key for a START_OBJECT in [retriever]."); + } retrieverBuilder = RetrieverBuilder.parseTopLevelRetrieverBuilder( parser, new RetrieverParserContext( diff --git a/server/src/main/java/org/elasticsearch/search/retriever/KnnRetrieverBuilder.java b/server/src/main/java/org/elasticsearch/search/retriever/KnnRetrieverBuilder.java index 88159d2a75b8f..40e535f774dad 100644 --- a/server/src/main/java/org/elasticsearch/search/retriever/KnnRetrieverBuilder.java +++ b/server/src/main/java/org/elasticsearch/search/retriever/KnnRetrieverBuilder.java @@ -8,6 +8,7 @@ package org.elasticsearch.search.retriever; +import org.elasticsearch.common.ParsingException; import org.elasticsearch.features.NodeFeature; import org.elasticsearch.search.builder.SearchSourceBuilder; import org.elasticsearch.search.vectors.KnnSearchBuilder; @@ -76,7 +77,7 @@ public final class KnnRetrieverBuilder extends RetrieverBuilder> { + public static final NodeFeature NODE_FEATURE = new NodeFeature("retrievers"); + public static final ParseField PRE_FILTER_FIELD = new ParseField("filter"); protected static void declareBaseParserFields( diff --git a/server/src/main/java/org/elasticsearch/search/retriever/RetrieversFeatures.java b/server/src/main/java/org/elasticsearch/search/retriever/RetrieversFeatures.java index b16062e16bd8f..c55999d6d24ef 100644 --- a/server/src/main/java/org/elasticsearch/search/retriever/RetrieversFeatures.java +++ b/server/src/main/java/org/elasticsearch/search/retriever/RetrieversFeatures.java @@ -17,6 +17,6 @@ public class RetrieversFeatures implements FeatureSpecification { @Override public Set getFeatures() { - return Set.of(StandardRetrieverBuilder.NODE_FEATURE, KnnRetrieverBuilder.NODE_FEATURE); + return Set.of(RetrieverBuilder.NODE_FEATURE, StandardRetrieverBuilder.NODE_FEATURE, KnnRetrieverBuilder.NODE_FEATURE); } } diff --git a/server/src/main/java/org/elasticsearch/search/retriever/StandardRetrieverBuilder.java b/server/src/main/java/org/elasticsearch/search/retriever/StandardRetrieverBuilder.java index a42fc26f924d5..717f8d471e053 100644 --- a/server/src/main/java/org/elasticsearch/search/retriever/StandardRetrieverBuilder.java +++ b/server/src/main/java/org/elasticsearch/search/retriever/StandardRetrieverBuilder.java @@ -8,6 +8,7 @@ package org.elasticsearch.search.retriever; +import org.elasticsearch.common.ParsingException; import org.elasticsearch.features.NodeFeature; import org.elasticsearch.index.query.AbstractQueryBuilder; import org.elasticsearch.index.query.BoolQueryBuilder; @@ -86,7 +87,7 @@ public final class StandardRetrieverBuilder extends RetrieverBuilder ssb.parseXContent(parser, true, nf -> false)); - assertEquals("[standard] retriever is not a supported feature", iae.getMessage()); - ssb.parseXContent(parser, false, nf -> nf == StandardRetrieverBuilder.NODE_FEATURE); + ParsingException iae = expectThrows(ParsingException.class, () -> ssb.parseXContent(parser, true, nf -> false)); + assertEquals("Unknown key for a START_OBJECT in [retriever].", iae.getMessage()); + } + + try (XContentParser parser = createParser(JsonXContent.jsonXContent, "{\"retriever\":{\"standard\":{}}}")) { + SearchSourceBuilder ssb = new SearchSourceBuilder(); + ParsingException iae = expectThrows( + ParsingException.class, + () -> ssb.parseXContent(parser, true, nf -> nf == RetrieverBuilder.NODE_FEATURE) + ); + assertEquals("unknown retriever [standard]", iae.getMessage()); + } + + try (XContentParser parser = createParser(JsonXContent.jsonXContent, "{\"retriever\":{\"standard\":{}}}")) { + SearchSourceBuilder ssb = new SearchSourceBuilder(); + ssb.parseXContent(parser, true, nf -> nf == RetrieverBuilder.NODE_FEATURE || nf == StandardRetrieverBuilder.NODE_FEATURE); } try (XContentParser parser = createParser(JsonXContent.jsonXContent, "{\"retriever\":{\"knn\":{}}}")) { SearchSourceBuilder ssb = new SearchSourceBuilder(); - IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, () -> ssb.parseXContent(parser, true, nf -> false)); - assertEquals("[knn] retriever is not a supported feature", iae.getMessage()); - ssb.parseXContent(parser, false, nf -> nf == KnnRetrieverBuilder.NODE_FEATURE); + ParsingException iae = expectThrows( + ParsingException.class, + () -> ssb.parseXContent(parser, true, nf -> nf == RetrieverBuilder.NODE_FEATURE) + ); + assertEquals("unknown retriever [knn]", iae.getMessage()); + } + + try ( + XContentParser parser = createParser( + JsonXContent.jsonXContent, + "{\"retriever\":{\"knn\":{\"field\": \"test\", \"k\": 2, \"num_candidates\": 5, \"query_vector\": [1, 2, 3]}}}" + ) + ) { + SearchSourceBuilder ssb = new SearchSourceBuilder(); + ssb.parseXContent(parser, true, nf -> nf == RetrieverBuilder.NODE_FEATURE || nf == KnnRetrieverBuilder.NODE_FEATURE); } } diff --git a/x-pack/plugin/rank-rrf/src/main/java/org/elasticsearch/xpack/rank/rrf/RRFRetrieverBuilder.java b/x-pack/plugin/rank-rrf/src/main/java/org/elasticsearch/xpack/rank/rrf/RRFRetrieverBuilder.java index 00ac635edf018..f3ac67b756280 100644 --- a/x-pack/plugin/rank-rrf/src/main/java/org/elasticsearch/xpack/rank/rrf/RRFRetrieverBuilder.java +++ b/x-pack/plugin/rank-rrf/src/main/java/org/elasticsearch/xpack/rank/rrf/RRFRetrieverBuilder.java @@ -7,6 +7,7 @@ package org.elasticsearch.xpack.rank.rrf; +import org.elasticsearch.common.ParsingException; import org.elasticsearch.features.NodeFeature; import org.elasticsearch.license.LicenseUtils; import org.elasticsearch.search.builder.SearchSourceBuilder; @@ -50,7 +51,7 @@ public final class RRFRetrieverBuilder extends RetrieverBuilder ssb.parseXContent(parser, true, nf -> false)); - assertEquals("[rrf] retriever is not a supported feature", iae.getMessage()); - ssb.parseXContent(parser, false, nf -> nf == RRFRetrieverBuilder.NODE_FEATURE); + ParsingException iae = expectThrows( + ParsingException.class, + () -> ssb.parseXContent(parser, true, nf -> nf == RetrieverBuilder.NODE_FEATURE) + ); + assertEquals("unknown retriever [rrf]", iae.getMessage()); } }