View Javadoc
1   /*
2    * Copyright 2012-2025 CodeLibs Project and the Others.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13   * either express or implied. See the License for the specific language
14   * governing permissions and limitations under the License.
15   */
16  package org.codelibs.fess.opensearch.query;
17  
18  import java.io.IOException;
19  import java.util.List;
20  import java.util.Map;
21  import java.util.Objects;
22  
23  import org.apache.lucene.search.Query;
24  import org.opensearch.core.ParseField;
25  import org.opensearch.core.common.io.stream.NamedWriteable;
26  import org.opensearch.core.common.io.stream.StreamOutput;
27  import org.opensearch.core.xcontent.ObjectParser;
28  import org.opensearch.core.xcontent.XContentBuilder;
29  import org.opensearch.core.xcontent.XContentParser;
30  import org.opensearch.index.query.AbstractQueryBuilder;
31  import org.opensearch.index.query.QueryBuilder;
32  import org.opensearch.index.query.QueryShardContext;
33  
34  /**
35   * A query builder for a stored LTR (Learning to Rank) query.
36   * This builder constructs a query that uses a pre-trained LTR model
37   * to re-rank search results based on a given set of features.
38   */
39  public class StoredLtrQueryBuilder extends AbstractQueryBuilder<StoredLtrQueryBuilder> implements NamedWriteable {
40      /** The name of the query. */
41      public static final String NAME = "sltr";
42  
43      /** The parse field for the model name. */
44      public static final ParseField MODEL_NAME = new ParseField("model");
45      /** The parse field for the featureset name. */
46      public static final ParseField FEATURESET_NAME = new ParseField("featureset");
47      /** The parse field for the store name. */
48      public static final ParseField STORE_NAME = new ParseField("store");
49      /** The parse field for the query parameters. */
50      public static final ParseField PARAMS = new ParseField("params");
51      /** The parse field for the active features. */
52      public static final ParseField ACTIVE_FEATURES = new ParseField("active_features");
53      private static final ObjectParser<StoredLtrQueryBuilder, Void> PARSER;
54  
55      static {
56          PARSER = new ObjectParser<>(NAME);
57          PARSER.declareString(StoredLtrQueryBuilder::modelName, MODEL_NAME);
58          PARSER.declareString(StoredLtrQueryBuilder::featureSetName, FEATURESET_NAME);
59          PARSER.declareString(StoredLtrQueryBuilder::storeName, STORE_NAME);
60          PARSER.declareField(StoredLtrQueryBuilder::params, XContentParser::map, PARAMS, ObjectParser.ValueType.OBJECT);
61          PARSER.declareStringArray(StoredLtrQueryBuilder::activeFeatures, ACTIVE_FEATURES);
62          PARSER.declareFloat(QueryBuilder::boost, AbstractQueryBuilder.BOOST_FIELD);
63          PARSER.declareString(QueryBuilder::queryName, AbstractQueryBuilder.NAME_FIELD);
64      }
65  
66      private String modelName;
67      private String featureSetName;
68      private String storeName;
69      private Map<String, Object> params;
70      private List<String> activeFeatures;
71  
72      /**
73       * Constructs a new stored LTR query builder.
74       */
75      public StoredLtrQueryBuilder() {
76          // do nothing
77      }
78  
79      @Override
80      public String getWriteableName() {
81          return NAME;
82      }
83  
84      @Override
85      protected void doWriteTo(final StreamOutput out) throws IOException {
86          out.writeOptionalString(modelName);
87          out.writeOptionalString(featureSetName);
88          out.writeMap(params);
89          out.writeOptionalStringArray(activeFeatures != null ? activeFeatures.toArray(new String[0]) : null);
90          out.writeOptionalString(storeName);
91      }
92  
93      @Override
94      protected void doXContent(final XContentBuilder builder, final Params params) throws IOException {
95          builder.startObject(NAME);
96          if (modelName != null) {
97              builder.field(MODEL_NAME.getPreferredName(), modelName);
98          }
99          if (featureSetName != null) {
100             builder.field(FEATURESET_NAME.getPreferredName(), featureSetName);
101         }
102         if (storeName != null) {
103             builder.field(STORE_NAME.getPreferredName(), storeName);
104         }
105         if (this.params != null && !this.params.isEmpty()) {
106             builder.field(PARAMS.getPreferredName(), this.params);
107         }
108         if (activeFeatures != null && !activeFeatures.isEmpty()) {
109             builder.field(ACTIVE_FEATURES.getPreferredName(), activeFeatures);
110         }
111         printBoostAndQueryName(builder);
112         builder.endObject();
113     }
114 
115     @Override
116     protected Query doToQuery(final QueryShardContext context) throws IOException {
117         throw new UnsupportedOperationException("Query processing is not supported.");
118     }
119 
120     @Override
121     protected boolean doEquals(final StoredLtrQueryBuilder other) {
122         return Objects.equals(modelName, other.modelName) && Objects.equals(featureSetName, other.featureSetName)
123                 && Objects.equals(storeName, other.storeName) && Objects.equals(params, other.params)
124                 && Objects.equals(activeFeatures, other.activeFeatures);
125     }
126 
127     @Override
128     protected int doHashCode() {
129         return Objects.hash(modelName, featureSetName, storeName, params, activeFeatures);
130     }
131 
132     /**
133      * Gets the name of the LTR model.
134      *
135      * @return The model name.
136      */
137     public String modelName() {
138         return modelName;
139     }
140 
141     /**
142      * Sets the name of the LTR model.
143      *
144      * @param modelName The model name.
145      * @return This query builder.
146      */
147     public StoredLtrQueryBuilder modelName(final String modelName) {
148         this.modelName = Objects.requireNonNull(modelName);
149         return this;
150     }
151 
152     /**
153      * Gets the name of the featureset.
154      *
155      * @return The featureset name.
156      */
157     public String featureSetName() {
158         return featureSetName;
159     }
160 
161     /**
162      * Sets the name of the featureset.
163      *
164      * @param featureSetName The featureset name.
165      * @return This query builder.
166      */
167     public StoredLtrQueryBuilder featureSetName(final String featureSetName) {
168         this.featureSetName = featureSetName;
169         return this;
170     }
171 
172     /**
173      * Gets the name of the feature store.
174      *
175      * @return The store name.
176      */
177     public String storeName() {
178         return storeName;
179     }
180 
181     /**
182      * Sets the name of the feature store.
183      *
184      * @param storeName The store name.
185      * @return This query builder.
186      */
187     public StoredLtrQueryBuilder storeName(final String storeName) {
188         this.storeName = storeName;
189         return this;
190     }
191 
192     /**
193      * Gets the parameters for the LTR query.
194      *
195      * @return A map of query parameters.
196      */
197     public Map<String, Object> params() {
198         return params;
199     }
200 
201     /**
202      * Sets the parameters for the LTR query.
203      *
204      * @param params A map of query parameters.
205      * @return This query builder.
206      */
207     public StoredLtrQueryBuilder params(final Map<String, Object> params) {
208         this.params = Objects.requireNonNull(params);
209         return this;
210     }
211 
212     /**
213      * Gets the list of active features.
214      *
215      * @return A list of active features.
216      */
217     public List<String> activeFeatures() {
218         return activeFeatures;
219     }
220 
221     /**
222      * Sets the list of active features.
223      *
224      * @param activeFeatures A list of active features.
225      * @return This query builder.
226      */
227     public StoredLtrQueryBuilder activeFeatures(final List<String> activeFeatures) {
228         this.activeFeatures = Objects.requireNonNull(activeFeatures);
229         return this;
230     }
231 }