@@ -83,7 +83,8 @@ public final class LinearRetrieverBuilder extends CompoundRetrieverBuilder<Linea
8383 List <LinearRetrieverComponent > retrieverComponents = args [0 ] == null ? List .of () : (List <LinearRetrieverComponent >) args [0 ];
8484 List <String > fields = (List <String >) args [1 ];
8585 String query = (String ) args [2 ];
86- ScoreNormalizer normalizer = args [3 ] == null ? DEFAULT_NORMALIZER : ScoreNormalizer .valueOf ((String ) args [3 ]);
86+ String normalizerName = (String ) args [3 ];
87+ ScoreNormalizer normalizer = normalizerName == null ? null : ScoreNormalizer .valueOf (normalizerName );
8788 int rankWindowSize = args [4 ] == null ? RankBuilder .DEFAULT_RANK_WINDOW_SIZE : (int ) args [4 ];
8889
8990 int index = 0 ;
@@ -94,6 +95,7 @@ public final class LinearRetrieverBuilder extends CompoundRetrieverBuilder<Linea
9495 for (LinearRetrieverComponent component : retrieverComponents ) {
9596 innerRetrievers .add (RetrieverSource .from (component .retriever ));
9697 weights [index ] = component .weight ;
98+ normalizers [index ] = component .normalizer ;
9799 index ++;
98100 }
99101 return new LinearRetrieverBuilder (innerRetrievers , fields , query , normalizer , rankWindowSize , weights , normalizers );
@@ -224,6 +226,27 @@ public ActionRequestValidationException validate(
224226 );
225227 }
226228
229+ if (normalizer != null ) {
230+ for (ScoreNormalizer perRetrieverNormalizer : normalizers ) {
231+ boolean isExplicitSubNormalizer = perRetrieverNormalizer != null && !perRetrieverNormalizer .equals (DEFAULT_NORMALIZER );
232+ boolean isMismatch = isExplicitSubNormalizer && !perRetrieverNormalizer .equals (normalizer );
233+ if (isMismatch ) {
234+ validationException = addValidationError (
235+ String .format (
236+ Locale .ROOT ,
237+ "[%s] top-level [%s] is [%s] but a sub-retriever specifies [%s]" ,
238+ getName (),
239+ NORMALIZER_FIELD .getPreferredName (),
240+ normalizer .getName (),
241+ perRetrieverNormalizer .getName ()
242+ ),
243+ validationException
244+ );
245+ break ;
246+ }
247+ }
248+ }
249+
227250 return validationException ;
228251 }
229252
@@ -358,6 +381,14 @@ protected RetrieverBuilder doRewrite(QueryRewriteContext ctx) {
358381 rewritten = new StandardRetrieverBuilder (new MatchNoneQueryBuilder ());
359382 }
360383 }
384+ if (normalizer != null ) {
385+ ScoreNormalizer [] newNormalizers = new ScoreNormalizer [normalizers .length ];
386+ for (int i = 0 ; i < normalizers .length ; i ++) {
387+ newNormalizers [i ] = (normalizers [i ] == null || normalizers [i ].equals (DEFAULT_NORMALIZER ))
388+ ? normalizer : normalizers [i ];
389+ }
390+ return new LinearRetrieverBuilder (innerRetrievers , fields , query , null , rankWindowSize , weights , newNormalizers );
391+ }
361392
362393 return rewritten ;
363394 }
@@ -383,6 +414,9 @@ public void doToXContent(XContentBuilder builder, Params params) throws IOExcept
383414 builder .startObject ();
384415 builder .field (LinearRetrieverComponent .RETRIEVER_FIELD .getPreferredName (), entry .retriever ());
385416 builder .field (LinearRetrieverComponent .WEIGHT_FIELD .getPreferredName (), weights [index ]);
417+ if (normalizers [index ] != null && !normalizers [index ].equals (DEFAULT_NORMALIZER )) {
418+ builder .field (LinearRetrieverComponent .NORMALIZER_FIELD .getPreferredName (), normalizers [index ].getName ());
419+ }
386420 builder .endObject ();
387421 index ++;
388422 }
@@ -399,7 +433,7 @@ public void doToXContent(XContentBuilder builder, Params params) throws IOExcept
399433 if (query != null ) {
400434 builder .field (QUERY_FIELD .getPreferredName (), query );
401435 }
402- if (normalizer != null ) {
436+ if (normalizer != null && ! normalizer . equals ( DEFAULT_NORMALIZER ) ) {
403437 builder .field (NORMALIZER_FIELD .getPreferredName (), normalizer .getName ());
404438 }
405439
0 commit comments