@@ -88,45 +88,29 @@ public class SparseVectorFieldMapper extends FieldMapper {
8888
8989 public static final NodeFeature SPARSE_VECTOR_INDEX_OPTIONS_FEATURE = new NodeFeature ("sparse_vector.index_options_supported" );
9090
91+ private final IndexVersion indexVersion ;
92+
9193 private static SparseVectorFieldMapper toType (FieldMapper in ) {
9294 return (SparseVectorFieldMapper ) in ;
9395 }
9496
9597 public static class Builder extends FieldMapper .Builder {
98+ private final IndexVersion indexVersion ;
99+
96100 private final Parameter <Boolean > stored = Parameter .storeParam (m -> toType (m ).fieldType ().isStored (), false );
97101 private final Parameter <Map <String , String >> meta = Parameter .metaParam ();
98- private final Parameter <IndexOptions > indexOptions = new Parameter <>(
99- SPARSE_VECTOR_INDEX_OPTIONS ,
102+ private final Parameter <IndexOptions > indexOptions = new Parameter <>(SPARSE_VECTOR_INDEX_OPTIONS ,
100103 true ,
101104 () -> null ,
102105 (n , c , o ) -> parseIndexOptions (c , o ),
103106 m -> toType (m ).fieldType ().indexOptions ,
104- this ::serializeIndexOptions ,
105- // XContentBuilder::field,
107+ XContentBuilder ::field ,
106108 Objects ::toString
107- ).acceptsNull ();
108-
109- private void serializeIndexOptions (XContentBuilder builder , String name , IndexOptions value ) throws IOException {
110- if (value instanceof IndexOptions serializeIndexOptions ) {
111- if (IndexOptions .isDefaultOptions (serializeIndexOptions )) {
112- // do not emit anything if it's the default options
113- return ;
114- }
115- }
116-
117- builder .field (name , value );
118- }
119-
120- private final MappingParserContext mappingParserContext ;
109+ ).acceptsNull ().setSerializerCheck (this ::indexOptionsSerializerCheck );
121110
122- public Builder (String name ) {
111+ public Builder (String name , @ Nullable IndexVersion indexVersion ) {
123112 super (name );
124- mappingParserContext = null ;
125- }
126-
127- public Builder (String name , @ Nullable MappingParserContext mappingParserContext ) {
128- super (name );
129- this .mappingParserContext = mappingParserContext ;
113+ this .indexVersion = indexVersion ;
130114 }
131115
132116 public Builder setStored (boolean value ) {
@@ -142,18 +126,27 @@ protected Parameter<?>[] getParameters() {
142126 @ Override
143127 public SparseVectorFieldMapper build (MapperBuilderContext context ) {
144128 IndexOptions builderIndexOptions = indexOptions .getValue ();
145- if (builderIndexOptions == null
146- && mappingParserContext != null
147- && shouldHaveDefaultPruningConfig (mappingParserContext .indexVersionCreated ())) {
129+ if (builderIndexOptions == null && indexVersion != null && indexVersionSupportsDefaultPruningConfig (indexVersion )) {
148130 builderIndexOptions = new IndexOptions (true , new TokenPruningConfig ());
149131 }
150132
151133 return new SparseVectorFieldMapper (
152134 leafName (),
153- new SparseVectorFieldType (context .buildFullName (leafName ()), stored .getValue (), meta .getValue (), builderIndexOptions ),
154- builderParams (this , context )
135+ new SparseVectorFieldType (
136+ indexVersion ,
137+ context .buildFullName (leafName ()),
138+ stored .getValue (),
139+ meta .getValue (),
140+ builderIndexOptions
141+ ),
142+ builderParams (this , context ),
143+ indexVersion
155144 );
156145 }
146+
147+ private boolean indexOptionsSerializerCheck (boolean includeDefaults , boolean isConfigured , IndexOptions value ) {
148+ return includeDefaults || (value == null || IndexOptions .isDefaultOptions (value , indexVersion )) == false ;
149+ }
157150 }
158151
159152 public IndexOptions getIndexOptions () {
@@ -177,12 +170,8 @@ private static SparseVectorFieldMapper.IndexOptions parseIndexOptions(MappingPar
177170
178171 Map <String , Object > indexOptionsMap = XContentMapValues .nodeMapValue (propNode , SPARSE_VECTOR_INDEX_OPTIONS );
179172
180- XContentParser parser = new MapXContentParser (
181- NamedXContentRegistry .EMPTY ,
182- DeprecationHandler .IGNORE_DEPRECATIONS ,
183- indexOptionsMap ,
184- XContentType .JSON
185- );
173+ XContentParser parser =
174+ new MapXContentParser (NamedXContentRegistry .EMPTY , DeprecationHandler .IGNORE_DEPRECATIONS , indexOptionsMap , XContentType .JSON );
186175
187176 try {
188177 return INDEX_OPTIONS_PARSER .parse (parser , null );
@@ -198,24 +187,29 @@ private static SparseVectorFieldMapper.IndexOptions parseIndexOptions(MappingPar
198187 throw new IllegalArgumentException (ERROR_MESSAGE_8X );
199188 }
200189
201- return new Builder (n , c );
190+ return new Builder (n , c . indexVersionCreated () );
202191 }, notInMultiFields (CONTENT_TYPE ));
203192
204193 public static final class SparseVectorFieldType extends MappedFieldType {
205194 private final IndexOptions indexOptions ;
206195
207- public SparseVectorFieldType (String name , boolean isStored , Map <String , String > meta ) {
208- this (name , isStored , meta , null );
196+ public SparseVectorFieldType (IndexVersion indexVersion , String name , boolean isStored , Map <String , String > meta ) {
197+ this (indexVersion , name , isStored , meta , null );
209198 }
210199
211200 public SparseVectorFieldType (
201+ IndexVersion indexVersion ,
212202 String name ,
213203 boolean isStored ,
214204 Map <String , String > meta ,
215205 @ Nullable SparseVectorFieldMapper .IndexOptions indexOptions
216206 ) {
217207 super (name , true , isStored , false , TextSearchInfo .SIMPLE_MATCH_ONLY , meta );
218- this .indexOptions = indexOptions ;
208+ this .indexOptions = indexOptions != null
209+ ? indexOptions
210+ : SparseVectorFieldMapper .indexVersionSupportsDefaultPruningConfig (indexVersion )
211+ ? new IndexOptions (true , new TokenPruningConfig ())
212+ : null ;
219213 }
220214
221215 public IndexOptions getIndexOptions () {
@@ -269,35 +263,27 @@ public Query finalizeSparseVectorQuery(
269263 Boolean shouldPruneTokensFromQuery ,
270264 TokenPruningConfig tokenPruningConfigFromQuery
271265 ) throws IOException {
272- TokenPruningConfig pruningConfig = null ;
273-
274- if (shouldPruneTokensFromQuery != null ) {
275- // if this is not null, the query is overriding the index config
276- pruningConfig = shouldPruneTokensFromQuery ? tokenPruningConfigFromQuery : null ;
277- } else {
278- // check and see if we explicitly do not prune in the index_options
279- boolean explicitlyDoNotPrune = this .indexOptions != null
280- && this .indexOptions .prune != null
281- && this .indexOptions .prune == false ;
282-
283- if (explicitlyDoNotPrune == false ) {
284- // get the explicit pruning config from the index_options if available
285- pruningConfig = this .indexOptions != null ? this .indexOptions .pruningConfig : null ;
286-
287- // if we're still null, set the default based on the index version
288- // newer index versions default to true, while older is false
289- pruningConfig = pruningConfig == null ? getDefaultPruningConfig (context ) : pruningConfig ;
266+ Boolean shouldPruneTokens = shouldPruneTokensFromQuery ;
267+ TokenPruningConfig tokenPruningConfig = tokenPruningConfigFromQuery ;
268+
269+ if (indexOptions != null ) {
270+ if (shouldPruneTokens == null && indexOptions .prune != null ) {
271+ shouldPruneTokens = indexOptions .prune ;
290272 }
291- }
292273
293- return ( pruningConfig != null )
294- ? WeightedTokensUtils . queryBuilderWithPrunedTokens ( fieldName , pruningConfig , queryVectors , this , context )
295- : WeightedTokensUtils . queryBuilderWithAllTokens ( fieldName , queryVectors , this , context );
296- }
274+ if ( tokenPruningConfig == null && indexOptions . pruningConfig != null ) {
275+ tokenPruningConfig = indexOptions . pruningConfig ;
276+ }
277+ }
297278
298- private TokenPruningConfig getDefaultPruningConfig (SearchExecutionContext context ) {
299- IndexVersion indexVersion = context .indexVersionCreated ();
300- return (shouldHaveDefaultPruningConfig (indexVersion )) ? new TokenPruningConfig () : null ;
279+ return (shouldPruneTokens != null && shouldPruneTokens )
280+ ? WeightedTokensUtils .queryBuilderWithPrunedTokens (
281+ fieldName ,
282+ tokenPruningConfig == null ? new TokenPruningConfig () : tokenPruningConfig ,
283+ queryVectors ,
284+ this ,
285+ context
286+ ) : WeightedTokensUtils .queryBuilderWithAllTokens (fieldName , queryVectors , this , context );
301287 }
302288
303289 private static String indexedValueForSearch (Object value ) {
@@ -308,8 +294,14 @@ private static String indexedValueForSearch(Object value) {
308294 }
309295 }
310296
311- private SparseVectorFieldMapper (String simpleName , MappedFieldType mappedFieldType , BuilderParams builderParams ) {
297+ private SparseVectorFieldMapper (
298+ String simpleName ,
299+ MappedFieldType mappedFieldType ,
300+ BuilderParams builderParams ,
301+ IndexVersion indexVersion
302+ ) {
312303 super (simpleName , mappedFieldType , builderParams );
304+ this .indexVersion = indexVersion ;
313305 }
314306
315307 @ Override
@@ -327,7 +319,7 @@ public Map<String, NamedAnalyzer> indexAnalyzers() {
327319
328320 @ Override
329321 public FieldMapper .Builder getMergeBuilder () {
330- return new Builder (leafName (), null ).init (this );
322+ return new Builder (leafName (), indexVersion ).init (this );
331323 }
332324
333325 @ Override
@@ -352,8 +344,7 @@ public void parse(DocumentParserContext context) throws IOException {
352344
353345 if (context .parser ().currentToken () != Token .START_OBJECT ) {
354346 throw new IllegalArgumentException (
355- "[sparse_vector] fields must be json objects, expected a START_OBJECT but got: " + context .parser ().currentToken ()
356- );
347+ "[sparse_vector] fields must be json objects, expected a START_OBJECT but got: " + context .parser ().currentToken ());
357348 }
358349
359350 final boolean isWithinLeaf = context .path ().isWithinLeafObject ();
@@ -381,10 +372,8 @@ public void parse(DocumentParserContext context) throws IOException {
381372 }
382373 } else {
383374 throw new IllegalArgumentException (
384- "[sparse_vector] fields take hashes that map a feature to a strictly positive "
385- + "float, but got unexpected token "
386- + token
387- );
375+ "[sparse_vector] fields take hashes that map a feature to a strictly positive " + "float, but got unexpected token "
376+ + token );
388377 }
389378 }
390379 if (context .indexSettings ().getIndexVersionCreated ().onOrAfter (SPARSE_VECTOR_IN_FIELD_NAMES_INDEX_VERSION )) {
@@ -405,18 +394,12 @@ protected String contentType() {
405394 return CONTENT_TYPE ;
406395 }
407396
408- private static boolean shouldHaveDefaultPruningConfig (IndexVersion indexVersion ) {
409- if (indexVersion .onOrAfter (SPARSE_VECTOR_PRUNING_INDEX_OPTIONS_VERSION )) {
410- // default pruning for 9.1.0+ is true for this index
411- return true ;
412- }
413-
414- // default pruning for 8.19.0+ is true for this index
415- if (indexVersion .between (SPARSE_VECTOR_PRUNING_INDEX_OPTIONS_VERSION_8_X , IndexVersions .UPGRADE_TO_LUCENE_10_0_0 )) {
416- return true ;
417- }
418-
419- return false ;
397+ private static boolean indexVersionSupportsDefaultPruningConfig (IndexVersion indexVersion ) {
398+ // default pruning for 9.1.0+ or 8.19.0+ is true for this index
399+ return (
400+ indexVersion .onOrAfter (SPARSE_VECTOR_PRUNING_INDEX_OPTIONS_VERSION ) ||
401+ indexVersion .between (SPARSE_VECTOR_PRUNING_INDEX_OPTIONS_VERSION_8_X , IndexVersions .UPGRADE_TO_LUCENE_10_0_0 )
402+ );
420403 }
421404
422405 private static class SparseVectorValueFetcher implements ValueFetcher {
@@ -539,21 +522,19 @@ public static class IndexOptions implements ToXContent {
539522 IndexOptions (@ Nullable Boolean prune , @ Nullable TokenPruningConfig pruningConfig ) {
540523 if (pruningConfig != null && (prune == null || prune == false )) {
541524 throw new IllegalArgumentException (
542- "["
543- + SPARSE_VECTOR_INDEX_OPTIONS
544- + "] field ["
545- + PRUNING_CONFIG_FIELD_NAME .getPreferredName ()
546- + "] should only be set if ["
547- + PRUNE_FIELD_NAME .getPreferredName ()
548- + "] is set to true"
549- );
525+ "[" + SPARSE_VECTOR_INDEX_OPTIONS + "] field [" + PRUNING_CONFIG_FIELD_NAME .getPreferredName ()
526+ + "] should only be set if [" + PRUNE_FIELD_NAME .getPreferredName () + "] is set to true" );
550527 }
551528
552529 this .prune = prune ;
553530 this .pruningConfig = pruningConfig ;
554531 }
555532
556- public static boolean isDefaultOptions (IndexOptions indexOptions ) {
533+ public static boolean isDefaultOptions (IndexOptions indexOptions , IndexVersion indexVersion ) {
534+ if (indexVersionSupportsDefaultPruningConfig (indexVersion ) == false ) {
535+ return indexOptions == null ;
536+ }
537+
557538 if (indexOptions == null || indexOptions .prune == null || indexOptions .prune == false || indexOptions .pruningConfig == null ) {
558539 return false ;
559540 }
@@ -604,5 +585,4 @@ public final int hashCode() {
604585 return Objects .hash (prune , pruningConfig );
605586 }
606587 }
607-
608588}
0 commit comments