@@ -77,38 +77,71 @@ public XContentBuilder toXContent(XContentBuilder builder, ToXContentObject.Para
7777 }
7878
7979 public static RRFRetrieverComponent fromXContent (XContentParser parser , RetrieverParserContext context ) throws IOException {
80- RetrieverBuilder innerRetriever = null ;
81- float weight = DEFAULT_WEIGHT ;
82-
8380 if (parser .currentToken () != XContentParser .Token .START_OBJECT ) {
84- throw new ParsingException (parser .getTokenLocation (), "[{}] expected object " , parser .currentToken ());
81+ throw new ParsingException (parser .getTokenLocation (), "expected object but found [{}]" , parser .currentToken ());
8582 }
8683
87- while ((parser .nextToken ()) != XContentParser .Token .END_OBJECT ) {
88- var name = parser .currentName ();
84+ // Peek at the first field to determine the format
85+ XContentParser .Token token = parser .nextToken ();
86+ if (token == XContentParser .Token .END_OBJECT ) {
87+ throw new ParsingException (parser .getTokenLocation (), "retriever component must contain a retriever" );
88+ }
89+ if (token != XContentParser .Token .FIELD_NAME ) {
90+ throw new ParsingException (parser .getTokenLocation (), "expected field name but found [{}]" , token );
91+ }
8992
90- if (name .equals (RETRIEVER_FIELD .getPreferredName ())) {
91- if (parser .nextToken () != XContentParser .Token .START_OBJECT ) {
92- throw new ParsingException (parser .getTokenLocation (), "[{}] expected object" , parser .currentToken ());
93- }
94- parser .nextToken ();
95-
96- name = parser .currentName ();
97- innerRetriever = parser .namedObject (RetrieverBuilder .class , name , context );
98- parser .nextToken ();
99- } else if (name .equals (WEIGHT_FIELD .getPreferredName ())) {
100- if (parser .nextToken () != XContentParser .Token .VALUE_NUMBER ) {
101- throw new ParsingException (parser .getTokenLocation (), "[{}] expected number" , parser .currentToken ());
93+ String firstFieldName = parser .currentName ();
94+
95+ // Check if this is a structured component (starts with "retriever" or "weight")
96+ if (RETRIEVER_FIELD .match (firstFieldName , parser .getDeprecationHandler ())
97+ || WEIGHT_FIELD .match (firstFieldName , parser .getDeprecationHandler ())) {
98+ // This is a structured component - parse manually
99+ RetrieverBuilder retriever = null ;
100+ Float weight = null ;
101+
102+ do {
103+ String fieldName = parser .currentName ();
104+ if (RETRIEVER_FIELD .match (fieldName , parser .getDeprecationHandler ())) {
105+ if (retriever != null ) {
106+ throw new ParsingException (parser .getTokenLocation (), "only one retriever can be specified" );
107+ }
108+ parser .nextToken ();
109+ parser .nextToken ();
110+ String retrieverType = parser .currentName ();
111+ retriever = parser .namedObject (RetrieverBuilder .class , retrieverType , context );
112+ context .trackRetrieverUsage (retriever .getName ());
113+ parser .nextToken ();
114+ } else if (WEIGHT_FIELD .match (fieldName , parser .getDeprecationHandler ())) {
115+ if (weight != null ) {
116+ throw new ParsingException (parser .getTokenLocation (), "[weight] field can only be specified once" );
117+ }
118+ parser .nextToken ();
119+ weight = parser .floatValue ();
120+ } else {
121+ if (retriever != null ) {
122+ throw new ParsingException (parser .getTokenLocation (), "only one retriever can be specified" );
123+ }
124+ throw new ParsingException (
125+ parser .getTokenLocation (),
126+ "unknown field [{}], expected [{}] or [{}]" ,
127+ fieldName ,
128+ RETRIEVER_FIELD .getPreferredName (),
129+ WEIGHT_FIELD .getPreferredName ()
130+ );
102131 }
132+ } while (parser .nextToken () == XContentParser .Token .FIELD_NAME );
133+
134+ if (retriever == null ) {
135+ throw new ParsingException (parser .getTokenLocation (), "retriever component must contain a retriever" );
136+ }
103137
104- weight = parser .floatValue ();
105- } else {
106- innerRetriever = parser .namedObject (RetrieverBuilder .class , name , context );
107- context .trackRetrieverUsage (innerRetriever .getName ());
108- parser .nextToken ();
109- break ;
138+ return new RRFRetrieverComponent (retriever , weight );
139+ } else {
140+ RetrieverBuilder retriever = parser .namedObject (RetrieverBuilder .class , firstFieldName , context );
141+ context .trackRetrieverUsage (retriever .getName ());
142+ while (parser .nextToken () != XContentParser .Token .END_OBJECT ) {
110143 }
144+ return new RRFRetrieverComponent (retriever , DEFAULT_WEIGHT );
111145 }
112- return new RRFRetrieverComponent (innerRetriever , weight );
113146 }
114147}
0 commit comments