21
21
22
22
import org .apache .lucene .analysis .core .WhitespaceAnalyzer ;
23
23
import org .apache .lucene .document .StoredField ;
24
+ import org .apache .lucene .index .DirectoryReader ;
24
25
import org .apache .lucene .index .IndexOptions ;
25
26
import org .apache .lucene .index .IndexableField ;
27
+ import org .apache .lucene .index .LeafReaderContext ;
28
+ import org .apache .lucene .index .OrdinalMap ;
26
29
import org .apache .lucene .index .Term ;
30
+ import org .apache .lucene .search .DocValuesFieldExistsQuery ;
27
31
import org .apache .lucene .search .MultiTermQuery ;
28
32
import org .apache .lucene .search .PrefixQuery ;
29
33
import org .apache .lucene .search .Query ;
34
+ import org .apache .lucene .search .SortField ;
30
35
import org .apache .lucene .search .TermQuery ;
31
36
import org .apache .lucene .util .BytesRef ;
32
- import org .elasticsearch .Version ;
33
37
import org .elasticsearch .common .bytes .BytesReference ;
34
38
import org .elasticsearch .common .lucene .Lucene ;
35
39
import org .elasticsearch .common .settings .Settings ;
39
43
import org .elasticsearch .common .xcontent .XContentParser ;
40
44
import org .elasticsearch .common .xcontent .json .JsonXContent ;
41
45
import org .elasticsearch .common .xcontent .support .XContentMapValues ;
46
+ import org .elasticsearch .index .Index ;
47
+ import org .elasticsearch .index .IndexSettings ;
42
48
import org .elasticsearch .index .analysis .AnalyzerScope ;
43
49
import org .elasticsearch .index .analysis .NamedAnalyzer ;
50
+ import org .elasticsearch .index .fielddata .AtomicOrdinalsFieldData ;
51
+ import org .elasticsearch .index .fielddata .IndexFieldData ;
52
+ import org .elasticsearch .index .fielddata .IndexFieldDataCache ;
53
+ import org .elasticsearch .index .fielddata .IndexOrdinalsFieldData ;
54
+ import org .elasticsearch .index .fielddata .fieldcomparator .BytesRefFieldComparatorSource ;
55
+ import org .elasticsearch .index .fielddata .plain .AbstractAtomicOrdinalsFieldData ;
56
+ import org .elasticsearch .index .fielddata .plain .DocValuesIndexFieldData ;
57
+ import org .elasticsearch .index .fielddata .plain .SortedSetDVOrdinalsIndexFieldData ;
44
58
import org .elasticsearch .index .query .QueryShardContext ;
59
+ import org .elasticsearch .indices .breaker .CircuitBreakerService ;
60
+ import org .elasticsearch .search .MultiValueMode ;
45
61
46
62
import java .io .IOException ;
47
63
import java .util .Iterator ;
@@ -93,7 +109,7 @@ private static class Defaults {
93
109
static {
94
110
FIELD_TYPE .setTokenized (false );
95
111
FIELD_TYPE .setStored (false );
96
- FIELD_TYPE .setHasDocValues (false );
112
+ FIELD_TYPE .setHasDocValues (true );
97
113
FIELD_TYPE .setIndexOptions (IndexOptions .DOCS );
98
114
FIELD_TYPE .setOmitNorms (true );
99
115
FIELD_TYPE .freeze ();
@@ -127,14 +143,6 @@ public Builder indexOptions(IndexOptions indexOptions) {
127
143
return super .indexOptions (indexOptions );
128
144
}
129
145
130
- @ Override
131
- public Builder docValues (boolean docValues ) {
132
- if (docValues ) {
133
- throw new IllegalArgumentException ("[" + CONTENT_TYPE + "] fields do not support doc values" );
134
- }
135
- return super .docValues (docValues );
136
- }
137
-
138
146
public Builder depthLimit (int depthLimit ) {
139
147
if (depthLimit < 0 ) {
140
148
throw new IllegalArgumentException ("[depth_limit] must be positive, got " + depthLimit );
@@ -143,6 +151,11 @@ public Builder depthLimit(int depthLimit) {
143
151
return this ;
144
152
}
145
153
154
+ public Builder eagerGlobalOrdinals (boolean eagerGlobalOrdinals ) {
155
+ fieldType ().setEagerGlobalOrdinals (eagerGlobalOrdinals );
156
+ return builder ;
157
+ }
158
+
146
159
public Builder ignoreAbove (int ignoreAbove ) {
147
160
if (ignoreAbove < 0 ) {
148
161
throw new IllegalArgumentException ("[ignore_above] must be positive, got " + ignoreAbove );
@@ -166,11 +179,6 @@ public Builder copyTo(CopyTo copyTo) {
166
179
throw new UnsupportedOperationException ("[copy_to] is not supported for [" + CONTENT_TYPE + "] fields." );
167
180
}
168
181
169
- @ Override
170
- protected boolean defaultDocValues (Version indexCreated ) {
171
- return false ;
172
- }
173
-
174
182
@ Override
175
183
public JsonFieldMapper build (BuilderContext context ) {
176
184
setupFieldType (context );
@@ -194,6 +202,9 @@ public Mapper.Builder<?,?> parse(String name, Map<String, Object> node, ParserCo
194
202
if (propName .equals ("depth_limit" )) {
195
203
builder .depthLimit (XContentMapValues .nodeIntegerValue (propNode , -1 ));
196
204
iterator .remove ();
205
+ } else if (propName .equals ("eager_global_ordinals" )) {
206
+ builder .eagerGlobalOrdinals (XContentMapValues .nodeBooleanValue (propNode , "eager_global_ordinals" ));
207
+ iterator .remove ();
197
208
} else if (propName .equals ("ignore_above" )) {
198
209
builder .ignoreAbove (XContentMapValues .nodeIntegerValue (propNode , -1 ));
199
210
iterator .remove ();
@@ -221,7 +232,7 @@ public static final class KeyedJsonFieldType extends StringFieldType {
221
232
private final String key ;
222
233
private boolean splitQueriesOnWhitespace ;
223
234
224
- KeyedJsonFieldType (String key ) {
235
+ public KeyedJsonFieldType (String key ) {
225
236
setIndexAnalyzer (Lucene .KEYWORD_ANALYZER );
226
237
setSearchAnalyzer (Lucene .KEYWORD_ANALYZER );
227
238
this .key = key ;
@@ -323,6 +334,7 @@ public Query wildcardQuery(String value,
323
334
CONTENT_TYPE + "] fields." );
324
335
}
325
336
337
+ @ Override
326
338
public BytesRef indexedValueForSearch (Object value ) {
327
339
if (value == null ) {
328
340
return null ;
@@ -334,6 +346,108 @@ public BytesRef indexedValueForSearch(Object value) {
334
346
String keyedValue = JsonFieldParser .createKeyedValue (key , stringValue );
335
347
return new BytesRef (keyedValue );
336
348
}
349
+
350
+ @ Override
351
+ public IndexFieldData .Builder fielddataBuilder (String fullyQualifiedIndexName ) {
352
+ failIfNoDocValues ();
353
+ return new KeyedJsonIndexFieldData .Builder (key );
354
+ }
355
+ }
356
+
357
+ /**
358
+ * A field data implementation that gives access to the values associated with
359
+ * a particular JSON key.
360
+ *
361
+ * This class wraps the field data that is built directly on the keyed JSON field, and
362
+ * filters out values whose prefix doesn't match the requested key. Loading and caching
363
+ * is fully delegated to the wrapped field data, so that different {@link KeyedJsonIndexFieldData}
364
+ * for the same JSON field share the same global ordinals.
365
+ */
366
+ public static class KeyedJsonIndexFieldData implements IndexOrdinalsFieldData {
367
+ private final String key ;
368
+ private final IndexOrdinalsFieldData delegate ;
369
+
370
+ private KeyedJsonIndexFieldData (String key , IndexOrdinalsFieldData delegate ) {
371
+ this .delegate = delegate ;
372
+ this .key = key ;
373
+ }
374
+
375
+ public String getKey () {
376
+ return key ;
377
+ }
378
+
379
+ @ Override
380
+ public String getFieldName () {
381
+ return delegate .getFieldName ();
382
+ }
383
+
384
+ @ Override
385
+ public SortField sortField (Object missingValue ,
386
+ MultiValueMode sortMode ,
387
+ XFieldComparatorSource .Nested nested ,
388
+ boolean reverse ) {
389
+ XFieldComparatorSource source = new BytesRefFieldComparatorSource (this , missingValue , sortMode , nested );
390
+ return new SortField (getFieldName (), source , reverse );
391
+ }
392
+
393
+ @ Override
394
+ public void clear () {
395
+ delegate .clear ();
396
+ }
397
+
398
+ @ Override
399
+ public AtomicOrdinalsFieldData load (LeafReaderContext context ) {
400
+ AtomicOrdinalsFieldData fieldData = delegate .load (context );
401
+ return new KeyedJsonAtomicFieldData (key , fieldData );
402
+ }
403
+
404
+ @ Override
405
+ public AtomicOrdinalsFieldData loadDirect (LeafReaderContext context ) throws Exception {
406
+ AtomicOrdinalsFieldData fieldData = delegate .loadDirect (context );
407
+ return new KeyedJsonAtomicFieldData (key , fieldData );
408
+ }
409
+
410
+ @ Override
411
+ public IndexOrdinalsFieldData loadGlobal (DirectoryReader indexReader ) {
412
+ IndexOrdinalsFieldData fieldData = delegate .loadGlobal (indexReader );
413
+ return new KeyedJsonIndexFieldData (key , fieldData );
414
+ }
415
+
416
+ @ Override
417
+ public IndexOrdinalsFieldData localGlobalDirect (DirectoryReader indexReader ) throws Exception {
418
+ IndexOrdinalsFieldData fieldData = delegate .localGlobalDirect (indexReader );
419
+ return new KeyedJsonIndexFieldData (key , fieldData );
420
+ }
421
+
422
+ @ Override
423
+ public OrdinalMap getOrdinalMap () {
424
+ return delegate .getOrdinalMap ();
425
+ }
426
+
427
+ @ Override
428
+ public Index index () {
429
+ return delegate .index ();
430
+ }
431
+
432
+ public static class Builder implements IndexFieldData .Builder {
433
+ private final String key ;
434
+
435
+ Builder (String key ) {
436
+ this .key = key ;
437
+ }
438
+
439
+ @ Override
440
+ public IndexFieldData <?> build (IndexSettings indexSettings ,
441
+ MappedFieldType fieldType ,
442
+ IndexFieldDataCache cache ,
443
+ CircuitBreakerService breakerService ,
444
+ MapperService mapperService ) {
445
+ String fieldName = fieldType .name ();
446
+ IndexOrdinalsFieldData delegate = new SortedSetDVOrdinalsIndexFieldData (indexSettings ,
447
+ cache , fieldName , breakerService , AbstractAtomicOrdinalsFieldData .DEFAULT_SCRIPT_FUNCTION );
448
+ return new KeyedJsonIndexFieldData (key , delegate );
449
+ }
450
+ }
337
451
}
338
452
339
453
/**
@@ -396,7 +510,11 @@ public Object valueForDisplay(Object value) {
396
510
397
511
@ Override
398
512
public Query existsQuery (QueryShardContext context ) {
399
- return new TermQuery (new Term (FieldNamesFieldMapper .NAME , name ()));
513
+ if (hasDocValues ()) {
514
+ return new DocValuesFieldExistsQuery (name ());
515
+ } else {
516
+ return new TermQuery (new Term (FieldNamesFieldMapper .NAME , name ()));
517
+ }
400
518
}
401
519
402
520
@ Override
@@ -420,6 +538,12 @@ public Query wildcardQuery(String value,
420
538
throw new UnsupportedOperationException ("[wildcard] queries are not currently supported on [" +
421
539
CONTENT_TYPE + "] fields." );
422
540
}
541
+
542
+ @ Override
543
+ public IndexFieldData .Builder fielddataBuilder (String fullyQualifiedIndexName ) {
544
+ failIfNoDocValues ();
545
+ return new DocValuesIndexFieldData .Builder ();
546
+ }
423
547
}
424
548
425
549
private final JsonFieldParser fieldParser ;
@@ -438,7 +562,7 @@ private JsonFieldMapper(String simpleName,
438
562
this .depthLimit = depthLimit ;
439
563
this .ignoreAbove = ignoreAbove ;
440
564
this .fieldParser = new JsonFieldParser (fieldType .name (), keyedFieldName (),
441
- depthLimit , ignoreAbove , fieldType . nullValueAsString () );
565
+ fieldType , depthLimit , ignoreAbove );
442
566
}
443
567
444
568
@ Override
@@ -476,7 +600,9 @@ protected void parseCreateField(ParseContext context, List<IndexableField> field
476
600
return ;
477
601
}
478
602
479
- if (fieldType .indexOptions () == IndexOptions .NONE && !fieldType .stored ()) {
603
+ if (fieldType .indexOptions () == IndexOptions .NONE
604
+ && !fieldType .hasDocValues ()
605
+ && !fieldType .stored ()) {
480
606
context .parser ().skipChildren ();
481
607
return ;
482
608
}
@@ -490,22 +616,22 @@ protected void parseCreateField(ParseContext context, List<IndexableField> field
490
616
fields .add (new StoredField (fieldType .name (), storedValue ));
491
617
}
492
618
493
- if (fieldType ().indexOptions () != IndexOptions .NONE ) {
494
- XContentParser indexedFieldsParser = context .parser ();
619
+ XContentParser indexedFieldsParser = context .parser ();
495
620
496
- // If store is enabled, we've already consumed the content to produce the stored field. Here we
497
- // 'reset' the parser, so that we can traverse the content again.
498
- if (storedValue != null ) {
499
- indexedFieldsParser = JsonXContent .jsonXContent .createParser (context .parser ().getXContentRegistry (),
500
- context .parser ().getDeprecationHandler (),
501
- storedValue .bytes );
502
- indexedFieldsParser .nextToken ();
503
- }
504
-
505
- fields .addAll (fieldParser .parse (indexedFieldsParser ));
621
+ // If store is enabled, we've already consumed the content to produce the stored field. Here we
622
+ // 'reset' the parser, so that we can traverse the content again.
623
+ if (storedValue != null ) {
624
+ indexedFieldsParser = JsonXContent .jsonXContent .createParser (context .parser ().getXContentRegistry (),
625
+ context .parser ().getDeprecationHandler (),
626
+ storedValue .bytes );
627
+ indexedFieldsParser .nextToken ();
506
628
}
507
629
508
- createFieldNamesField (context , fields );
630
+ fields .addAll (fieldParser .parse (indexedFieldsParser ));
631
+
632
+ if (!fieldType .hasDocValues ()) {
633
+ createFieldNamesField (context , fields );
634
+ }
509
635
}
510
636
511
637
@ Override
0 commit comments