57
57
import org .apache .lucene .util .automaton .Automaton ;
58
58
import org .apache .lucene .util .automaton .Operations ;
59
59
import org .elasticsearch .Version ;
60
- import org .elasticsearch .common .collect .Iterators ;
61
60
import org .elasticsearch .common .lucene .Lucene ;
62
61
import org .elasticsearch .common .lucene .search .AutomatonQueries ;
63
62
import org .elasticsearch .common .lucene .search .MultiPhrasePrefixQuery ;
80
79
import java .util .Arrays ;
81
80
import java .util .Collections ;
82
81
import java .util .HashMap ;
83
- import java .util .Iterator ;
84
82
import java .util .List ;
85
83
import java .util .Map ;
86
84
import java .util .Objects ;
@@ -92,6 +90,7 @@ public class TextFieldMapper extends FieldMapper {
92
90
93
91
public static final String CONTENT_TYPE = "text" ;
94
92
private static final String FAST_PHRASE_SUFFIX = "._index_phrase" ;
93
+ private static final String FAST_PREFIX_SUFFIX = "._index_prefix" ;
95
94
96
95
public static class Defaults {
97
96
public static final double FIELDDATA_MIN_FREQUENCY = 0 ;
@@ -330,7 +329,7 @@ private TextFieldType buildFieldType(FieldType fieldType, ContentPath contentPat
330
329
return ft ;
331
330
}
332
331
333
- private PrefixFieldMapper buildPrefixMapper (ContentPath contentPath , FieldType fieldType , TextFieldType tft ) {
332
+ private SubFieldInfo buildPrefixInfo (ContentPath contentPath , FieldType fieldType , TextFieldType tft ) {
334
333
if (indexPrefixes .get () == null ) {
335
334
return null ;
336
335
}
@@ -358,16 +357,15 @@ private PrefixFieldMapper buildPrefixMapper(ContentPath contentPath, FieldType f
358
357
if (fieldType .storeTermVectorOffsets ()) {
359
358
pft .setStoreTermVectorOffsets (true );
360
359
}
361
- PrefixFieldType prefixFieldType = new PrefixFieldType (tft , fullName + "._index_prefix" , indexPrefixes .get ());
362
- tft .setPrefixFieldType (prefixFieldType );
363
- return new PrefixFieldMapper (pft , prefixFieldType , new PrefixWrappedAnalyzer (
360
+ tft .setIndexPrefixes (indexPrefixes .get ().minChars , indexPrefixes .get ().maxChars );
361
+ return new SubFieldInfo (fullName + "._index_prefix" , pft , new PrefixWrappedAnalyzer (
364
362
analyzers .getIndexAnalyzer ().analyzer (),
365
363
analyzers .positionIncrementGap .get (),
366
- prefixFieldType .minChars ,
367
- prefixFieldType .maxChars ));
364
+ indexPrefixes . get () .minChars ,
365
+ indexPrefixes . get () .maxChars ));
368
366
}
369
367
370
- private PhraseFieldMapper buildPhraseMapper (FieldType fieldType , TextFieldType parent ) {
368
+ private SubFieldInfo buildPhraseInfo (FieldType fieldType , TextFieldType parent ) {
371
369
if (indexPhrases .get () == false ) {
372
370
return null ;
373
371
}
@@ -381,24 +379,24 @@ private PhraseFieldMapper buildPhraseMapper(FieldType fieldType, TextFieldType p
381
379
parent .setIndexPhrases ();
382
380
PhraseWrappedAnalyzer a
383
381
= new PhraseWrappedAnalyzer (analyzers .getIndexAnalyzer ().analyzer (), analyzers .positionIncrementGap .get ());
384
- return new PhraseFieldMapper ( phraseFieldType , new PhraseFieldType ( parent ) , a );
382
+ return new SubFieldInfo ( parent . name () + FAST_PHRASE_SUFFIX , phraseFieldType , a );
385
383
}
386
384
387
385
public Map <String , NamedAnalyzer > indexAnalyzers (String name ,
388
- PhraseFieldMapper phraseFieldMapper ,
389
- PrefixFieldMapper prefixFieldMapper ) {
386
+ SubFieldInfo phraseFieldInfo ,
387
+ SubFieldInfo prefixFieldInfo ) {
390
388
Map <String , NamedAnalyzer > analyzers = new HashMap <>();
391
389
NamedAnalyzer main = this .analyzers .getIndexAnalyzer ();
392
390
analyzers .put (name , main );
393
- if (phraseFieldMapper != null ) {
391
+ if (phraseFieldInfo != null ) {
394
392
analyzers .put (
395
- phraseFieldMapper . name () ,
396
- new NamedAnalyzer (main .name () + "_phrase" , AnalyzerScope .INDEX , phraseFieldMapper .analyzer ));
393
+ phraseFieldInfo . field ,
394
+ new NamedAnalyzer (main .name () + "_phrase" , AnalyzerScope .INDEX , phraseFieldInfo .analyzer ));
397
395
}
398
- if (prefixFieldMapper != null ) {
396
+ if (prefixFieldInfo != null ) {
399
397
analyzers .put (
400
- prefixFieldMapper . name () ,
401
- new NamedAnalyzer (main .name () + "_prefix" , AnalyzerScope .INDEX , prefixFieldMapper .analyzer ));
398
+ prefixFieldInfo . field ,
399
+ new NamedAnalyzer (main .name () + "_prefix" , AnalyzerScope .INDEX , prefixFieldInfo .analyzer ));
402
400
}
403
401
return analyzers ;
404
402
}
@@ -407,12 +405,18 @@ public Map<String, NamedAnalyzer> indexAnalyzers(String name,
407
405
public TextFieldMapper build (ContentPath contentPath ) {
408
406
FieldType fieldType = TextParams .buildFieldType (index , store , indexOptions , norms , termVectors );
409
407
TextFieldType tft = buildFieldType (fieldType , contentPath );
410
- PhraseFieldMapper phraseFieldMapper = buildPhraseMapper (fieldType , tft );
411
- PrefixFieldMapper prefixFieldMapper = buildPrefixMapper (contentPath , fieldType , tft );
408
+ SubFieldInfo phraseFieldInfo = buildPhraseInfo (fieldType , tft );
409
+ SubFieldInfo prefixFieldInfo = buildPrefixInfo (contentPath , fieldType , tft );
410
+ MultiFields multiFields = multiFieldsBuilder .build (this , contentPath );
411
+ for (Mapper mapper : multiFields ) {
412
+ if (mapper .name ().endsWith (FAST_PHRASE_SUFFIX ) || mapper .name ().endsWith (FAST_PREFIX_SUFFIX )) {
413
+ throw new MapperParsingException ("Cannot use reserved field name [" + mapper .name () + "]" );
414
+ }
415
+ }
412
416
return new TextFieldMapper (name , fieldType , tft ,
413
- indexAnalyzers (tft .name (), phraseFieldMapper , prefixFieldMapper ),
414
- prefixFieldMapper , phraseFieldMapper ,
415
- multiFieldsBuilder . build ( this , contentPath ) , copyTo .build (), this );
417
+ indexAnalyzers (tft .name (), phraseFieldInfo , prefixFieldInfo ),
418
+ prefixFieldInfo , phraseFieldInfo ,
419
+ multiFields , copyTo .build (), this );
416
420
}
417
421
}
418
422
@@ -478,55 +482,22 @@ protected TokenStreamComponents wrapComponents(String fieldName, TokenStreamComp
478
482
}
479
483
}
480
484
481
- static final class PhraseFieldType extends StringFieldType {
482
-
483
- final TextFieldType parent ;
484
-
485
- PhraseFieldType (TextFieldType parent ) {
486
- super (parent .name () + FAST_PHRASE_SUFFIX , true , false , false , parent .getTextSearchInfo (), Collections .emptyMap ());
487
- this .parent = parent ;
488
- }
489
-
490
- @ Override
491
- public String typeName () {
492
- return "phrase" ;
493
- }
494
-
495
- @ Override
496
- public ValueFetcher valueFetcher (QueryShardContext context , SearchLookup searchLookup , String format ) {
497
- // Because this internal field is modelled as a multi-field, SourceValueFetcher will look up its
498
- // parent field in _source. So we don't need to use the parent field name here.
499
- return SourceValueFetcher .toString (name (), context , format );
500
- }
501
-
502
- @ Override
503
- public Query existsQuery (QueryShardContext context ) {
504
- throw new UnsupportedOperationException ();
505
- }
506
- }
507
-
508
- static final class PrefixFieldType extends StringFieldType {
485
+ private static final class PrefixFieldType extends StringFieldType {
509
486
510
487
final int minChars ;
511
488
final int maxChars ;
512
489
final TextFieldType parentField ;
513
490
514
- PrefixFieldType (TextFieldType parentField , String name , PrefixConfig config ) {
515
- this (parentField , name , config .minChars , config .maxChars );
516
- }
517
-
518
- PrefixFieldType (TextFieldType parentField , String name , int minChars , int maxChars ) {
519
- super (name , true , false , false , parentField .getTextSearchInfo (), Collections .emptyMap ());
491
+ PrefixFieldType (TextFieldType parentField , int minChars , int maxChars ) {
492
+ super (parentField .name () + FAST_PREFIX_SUFFIX , true , false , false , parentField .getTextSearchInfo (), Collections .emptyMap ());
520
493
this .minChars = minChars ;
521
494
this .maxChars = maxChars ;
522
495
this .parentField = parentField ;
523
496
}
524
497
525
498
@ Override
526
499
public ValueFetcher valueFetcher (QueryShardContext context , SearchLookup searchLookup , String format ) {
527
- // Because this internal field is modelled as a multi-field, SourceValueFetcher will look up its
528
- // parent field in _source. So we don't need to use the parent field name here.
529
- return SourceValueFetcher .toString (name (), context , format );
500
+ throw new UnsupportedOperationException ();
530
501
}
531
502
532
503
boolean accept (int length ) {
@@ -590,67 +561,18 @@ public Query existsQuery(QueryShardContext context) {
590
561
}
591
562
}
592
563
593
- private static final class PhraseFieldMapper extends FieldMapper {
564
+ private static final class SubFieldInfo {
594
565
595
566
private final Analyzer analyzer ;
596
567
private final FieldType fieldType ;
568
+ private final String field ;
597
569
598
- PhraseFieldMapper (FieldType fieldType , PhraseFieldType mappedFieldType , PhraseWrappedAnalyzer analyzer ) {
599
- super (mappedFieldType .name (), mappedFieldType , MultiFields .empty (), CopyTo .empty ());
570
+ SubFieldInfo (String field , FieldType fieldType , Analyzer analyzer ) {
600
571
this .fieldType = fieldType ;
601
572
this .analyzer = analyzer ;
573
+ this .field = field ;
602
574
}
603
575
604
- @ Override
605
- protected void parseCreateField (ParseContext context ) {
606
- throw new UnsupportedOperationException ();
607
- }
608
-
609
- @ Override
610
- public Builder getMergeBuilder () {
611
- return null ;
612
- }
613
-
614
- @ Override
615
- protected String contentType () {
616
- return "phrase" ;
617
- }
618
- }
619
-
620
- private static final class PrefixFieldMapper extends FieldMapper {
621
-
622
- private final Analyzer analyzer ;
623
- private final FieldType fieldType ;
624
-
625
- protected PrefixFieldMapper (FieldType fieldType , PrefixFieldType mappedFieldType , Analyzer analyzer ) {
626
- super (mappedFieldType .name (), mappedFieldType , MultiFields .empty (), CopyTo .empty ());
627
- this .analyzer = analyzer ;
628
- this .fieldType = fieldType ;
629
- }
630
-
631
- void addField (ParseContext context , String value ) {
632
- context .doc ().add (new Field (fieldType ().name (), value , fieldType ));
633
- }
634
-
635
- @ Override
636
- protected void parseCreateField (ParseContext context ) {
637
- throw new UnsupportedOperationException ();
638
- }
639
-
640
- @ Override
641
- public Builder getMergeBuilder () {
642
- return null ;
643
- }
644
-
645
- @ Override
646
- protected String contentType () {
647
- return "prefix" ;
648
- }
649
-
650
- @ Override
651
- public String toString () {
652
- return fieldType ().toString ();
653
- }
654
576
}
655
577
656
578
public static class TextFieldType extends StringFieldType {
@@ -702,8 +624,8 @@ int fielddataMinSegmentSize() {
702
624
return filter .minSegmentSize ;
703
625
}
704
626
705
- void setPrefixFieldType ( PrefixFieldType prefixFieldType ) {
706
- this .prefixFieldType = prefixFieldType ;
627
+ void setIndexPrefixes ( int minChars , int maxChars ) {
628
+ this .prefixFieldType = new PrefixFieldType ( this , minChars , maxChars ) ;
707
629
}
708
630
709
631
void setIndexPhrases () {
@@ -862,14 +784,14 @@ public IndexFieldData.Builder fielddataBuilder(String fullyQualifiedIndexName, S
862
784
863
785
private final Builder builder ;
864
786
private final FieldType fieldType ;
865
- private final PrefixFieldMapper prefixFieldMapper ;
866
- private final PhraseFieldMapper phraseFieldMapper ;
787
+ private final SubFieldInfo prefixFieldInfo ;
788
+ private final SubFieldInfo phraseFieldInfo ;
867
789
868
790
protected TextFieldMapper (String simpleName , FieldType fieldType ,
869
791
TextFieldType mappedFieldType ,
870
792
Map <String , NamedAnalyzer > indexAnalyzers ,
871
- PrefixFieldMapper prefixFieldMapper ,
872
- PhraseFieldMapper phraseFieldMapper ,
793
+ SubFieldInfo prefixFieldInfo ,
794
+ SubFieldInfo phraseFieldInfo ,
873
795
MultiFields multiFields , CopyTo copyTo , Builder builder ) {
874
796
super (simpleName , mappedFieldType , indexAnalyzers , multiFields , copyTo );
875
797
assert mappedFieldType .getTextSearchInfo ().isTokenized ();
@@ -878,8 +800,8 @@ protected TextFieldMapper(String simpleName, FieldType fieldType,
878
800
throw new IllegalArgumentException ("Cannot enable fielddata on a [text] field that is not indexed: [" + name () + "]" );
879
801
}
880
802
this .fieldType = fieldType ;
881
- this .prefixFieldMapper = prefixFieldMapper ;
882
- this .phraseFieldMapper = phraseFieldMapper ;
803
+ this .prefixFieldInfo = prefixFieldInfo ;
804
+ this .phraseFieldInfo = phraseFieldInfo ;
883
805
this .builder = builder ;
884
806
}
885
807
@@ -907,30 +829,15 @@ protected void parseCreateField(ParseContext context) throws IOException {
907
829
if (fieldType .omitNorms ()) {
908
830
createFieldNamesField (context );
909
831
}
910
- if (prefixFieldMapper != null ) {
911
- prefixFieldMapper . addField ( context , value );
832
+ if (prefixFieldInfo != null ) {
833
+ context . doc (). add ( new Field ( prefixFieldInfo . field , value , prefixFieldInfo . fieldType ) );
912
834
}
913
- if (phraseFieldMapper != null ) {
914
- context .doc ().add (new Field (phraseFieldMapper . fieldType (). name () , value , phraseFieldMapper .fieldType ));
835
+ if (phraseFieldInfo != null ) {
836
+ context .doc ().add (new Field (phraseFieldInfo . field , value , phraseFieldInfo .fieldType ));
915
837
}
916
838
}
917
839
}
918
840
919
- @ Override
920
- public Iterator <Mapper > iterator () {
921
- List <Mapper > subIterators = new ArrayList <>();
922
- if (prefixFieldMapper != null ) {
923
- subIterators .add (prefixFieldMapper );
924
- }
925
- if (phraseFieldMapper != null ) {
926
- subIterators .add (phraseFieldMapper );
927
- }
928
- if (subIterators .size () == 0 ) {
929
- return super .iterator ();
930
- }
931
- return Iterators .concat (super .iterator (), subIterators .iterator ());
932
- }
933
-
934
841
@ Override
935
842
protected String contentType () {
936
843
return CONTENT_TYPE ;
@@ -1014,10 +921,11 @@ public static Query createPhrasePrefixQuery(TokenStream stream, String field, in
1014
921
}
1015
922
1016
923
if (terms .length == 1 ) {
1017
- Term [] newTerms = Arrays .stream (terms [0 ])
924
+ SynonymQuery .Builder sb = new SynonymQuery .Builder (prefixField );
925
+ Arrays .stream (terms [0 ])
1018
926
.map (term -> new Term (prefixField , term .bytes ()))
1019
- .toArray ( Term []:: new );
1020
- return new SynonymQuery ( newTerms );
927
+ .forEach ( sb :: addTerm );
928
+ return sb . build ( );
1021
929
}
1022
930
1023
931
SpanNearQuery .Builder spanQuery = new SpanNearQuery .Builder (field , true );
0 commit comments