6969import org .elasticsearch .inference .InferenceResults ;
7070import org .elasticsearch .inference .MinimalServiceSettings ;
7171import org .elasticsearch .inference .SimilarityMeasure ;
72+ import org .elasticsearch .inference .TaskType ;
7273import org .elasticsearch .search .fetch .StoredFieldsSpec ;
7374import org .elasticsearch .search .lookup .Source ;
7475import org .elasticsearch .search .vectors .KnnVectorQueryBuilder ;
@@ -166,6 +167,7 @@ public static BiConsumer<String, MappingParserContext> validateParserContext(Str
166167 public static class Builder extends FieldMapper .Builder {
167168 private final ModelRegistry modelRegistry ;
168169 private final boolean useLegacyFormat ;
170+ private final IndexVersion indexVersionCreated ;
169171
170172 private final Parameter <String > inferenceId = Parameter .stringParam (
171173 INFERENCE_ID_FIELD ,
@@ -203,15 +205,7 @@ public static class Builder extends FieldMapper.Builder {
203205 Objects ::toString
204206 ).acceptsNull ().setMergeValidator (SemanticTextFieldMapper ::canMergeModelSettings );
205207
206- private final Parameter <SemanticTextIndexOptions > indexOptions = new Parameter <>(
207- INDEX_OPTIONS_FIELD ,
208- true ,
209- () -> null ,
210- (n , c , o ) -> parseIndexOptionsFromMap (n , o , c .indexVersionCreated ()),
211- mapper -> ((SemanticTextFieldType ) mapper .fieldType ()).indexOptions ,
212- XContentBuilder ::field ,
213- Objects ::toString
214- ).acceptsNull ();
208+ private final Parameter <SemanticTextIndexOptions > indexOptions ;
215209
216210 @ SuppressWarnings ("unchecked" )
217211 private final Parameter <ChunkingSettings > chunkingSettings = new Parameter <>(
@@ -248,6 +242,18 @@ public Builder(
248242 super (name );
249243 this .modelRegistry = modelRegistry ;
250244 this .useLegacyFormat = InferenceMetadataFieldsMapper .isEnabled (indexSettings .getSettings ()) == false ;
245+ this .indexVersionCreated = indexSettings .getIndexVersionCreated ();
246+
247+ indexOptions = new Parameter <>(
248+ INDEX_OPTIONS_FIELD ,
249+ true ,
250+ () -> null ,
251+ (n , c , o ) -> parseIndexOptionsFromMap (n , o , c .indexVersionCreated ()),
252+ mapper -> ((SemanticTextFieldType ) mapper .fieldType ()).indexOptions ,
253+ XContentBuilder ::field ,
254+ Objects ::toString
255+ ).acceptsNull ().setSerializerCheck (this ::indexOptionsSerializerCheck );
256+
251257 this .inferenceFieldBuilder = c -> {
252258 // Resolve the model setting from the registry if it has not been set yet.
253259 var resolvedModelSettings = modelSettings .get () != null ? modelSettings .get () : getResolvedModelSettings (c , false );
@@ -263,6 +269,10 @@ public Builder(
263269 };
264270 }
265271
272+ private boolean indexOptionsSerializerCheck (boolean includeDefaults , boolean isConfigured , SemanticTextIndexOptions value ) {
273+ return includeDefaults || Objects .equals (defaultIndexOptions (indexVersionCreated , modelSettings .get ()), value ) == false ;
274+ }
275+
266276 public Builder setInferenceId (String id ) {
267277 this .inferenceId .setValue (id );
268278 return this ;
@@ -365,8 +375,13 @@ public SemanticTextFieldMapper build(MapperBuilderContext context) {
365375 validateServiceSettings (modelSettings .get (), resolvedModelSettings );
366376 }
367377
368- if (context .getMergeReason () != MapperService .MergeReason .MAPPING_RECOVERY && indexOptions .get () != null ) {
369- validateIndexOptions (indexOptions .get (), inferenceId .getValue (), resolvedModelSettings );
378+ SemanticTextIndexOptions builderIndexOptions = indexOptions .get ();
379+ if (context .getMergeReason () != MapperService .MergeReason .MAPPING_RECOVERY && builderIndexOptions != null ) {
380+ validateIndexOptions (builderIndexOptions , inferenceId .getValue (), resolvedModelSettings );
381+ }
382+ if (builderIndexOptions == null ) {
383+ // If no index options are set, use the default options based on the model settings
384+ builderIndexOptions = defaultIndexOptions (indexVersionCreated , resolvedModelSettings );
370385 }
371386
372387 final String fullName = context .buildFullName (leafName ());
@@ -383,9 +398,9 @@ public SemanticTextFieldMapper build(MapperBuilderContext context) {
383398 fullName ,
384399 inferenceId .getValue (),
385400 searchInferenceId .getValue (),
386- modelSettings . getValue () ,
401+ resolvedModelSettings ,
387402 chunkingSettings .getValue (),
388- indexOptions . getValue () ,
403+ builderIndexOptions ,
389404 inferenceField ,
390405 useLegacyFormat ,
391406 meta .getValue ()
@@ -434,7 +449,6 @@ private void validateIndexOptions(SemanticTextIndexOptions indexOptions, String
434449 }
435450
436451 if (indexOptions .type () == SemanticTextIndexOptions .SupportedIndexOptions .DENSE_VECTOR ) {
437-
438452 if (modelSettings .taskType () != TEXT_EMBEDDING ) {
439453 throw new IllegalArgumentException (
440454 "Invalid task type for index options, required [" + TEXT_EMBEDDING + "] but was [" + modelSettings .taskType () + "]"
@@ -1221,20 +1235,33 @@ static boolean indexVersionDefaultsToBbqHnsw(IndexVersion indexVersion) {
12211235 || indexVersion .between (SEMANTIC_TEXT_DEFAULTS_TO_BBQ_BACKPORT_8_X , IndexVersions .UPGRADE_TO_LUCENE_10_0_0 );
12221236 }
12231237
1238+ static SemanticTextIndexOptions defaultIndexOptions (IndexVersion indexVersionCreated , MinimalServiceSettings modelSettings ) {
1239+
1240+ if (modelSettings == null ) {
1241+ return null ;
1242+ }
1243+
1244+ SemanticTextIndexOptions defaultIndexOptions = null ;
1245+ if (modelSettings .taskType () == TaskType .TEXT_EMBEDDING ) {
1246+ DenseVectorFieldMapper .DenseVectorIndexOptions denseVectorIndexOptions = defaultDenseVectorIndexOptions (
1247+ indexVersionCreated ,
1248+ modelSettings
1249+ );
1250+ defaultIndexOptions = denseVectorIndexOptions == null
1251+ ? null
1252+ : new SemanticTextIndexOptions (SemanticTextIndexOptions .SupportedIndexOptions .DENSE_VECTOR , denseVectorIndexOptions );
1253+ }
1254+
1255+ return defaultIndexOptions ;
1256+ }
1257+
12241258 static DenseVectorFieldMapper .DenseVectorIndexOptions defaultBbqHnswDenseVectorIndexOptions () {
12251259 int m = Lucene99HnswVectorsFormat .DEFAULT_MAX_CONN ;
12261260 int efConstruction = Lucene99HnswVectorsFormat .DEFAULT_BEAM_WIDTH ;
12271261 DenseVectorFieldMapper .RescoreVector rescoreVector = new DenseVectorFieldMapper .RescoreVector (DEFAULT_RESCORE_OVERSAMPLE );
12281262 return new DenseVectorFieldMapper .BBQHnswIndexOptions (m , efConstruction , rescoreVector );
12291263 }
12301264
1231- static SemanticTextIndexOptions defaultBbqHnswSemanticTextIndexOptions () {
1232- return new SemanticTextIndexOptions (
1233- SemanticTextIndexOptions .SupportedIndexOptions .DENSE_VECTOR ,
1234- defaultBbqHnswDenseVectorIndexOptions ()
1235- );
1236- }
1237-
12381265 private static boolean canMergeModelSettings (MinimalServiceSettings previous , MinimalServiceSettings current , Conflicts conflicts ) {
12391266 if (previous != null && current != null && previous .canMergeWith (current )) {
12401267 return true ;
0 commit comments