19
19
import org .xbib .elasticsearch .common .langdetect .LanguageDetectionException ;
20
20
21
21
import java .io .IOException ;
22
- import java .nio .charset .Charset ;
22
+ import java .nio .charset .StandardCharsets ;
23
+ import java .util .Collections ;
23
24
import java .util .Iterator ;
25
+ import java .util .LinkedHashMap ;
24
26
import java .util .List ;
25
27
import java .util .Map ;
26
28
@@ -48,6 +50,8 @@ public static class Builder extends FieldMapper.Builder<Builder, StringFieldMapp
48
50
49
51
protected int positionIncrementGap = -1 ;
50
52
53
+ protected LanguageTo languageTo = LanguageTo .builder ().build ();
54
+
51
55
protected Settings .Builder settingsBuilder = Settings .settingsBuilder ();
52
56
53
57
public Builder (String name ) {
@@ -139,6 +143,11 @@ public Builder profile(String profile) {
139
143
return this ;
140
144
}
141
145
146
+ public Builder languageTo (LanguageTo languageTo ) {
147
+ this .languageTo = languageTo ;
148
+ return this ;
149
+ }
150
+
142
151
@ Override
143
152
public LangdetectMapper build (BuilderContext context ) {
144
153
if (positionIncrementGap != -1 ) {
@@ -159,7 +168,8 @@ public LangdetectMapper build(BuilderContext context) {
159
168
setupFieldType (context );
160
169
LangdetectService service = new LangdetectService (settingsBuilder .build ());
161
170
return new LangdetectMapper (name , fieldType , defaultFieldType , 100 , -1 ,
162
- context .indexSettings (), multiFieldsBuilder .build (this , context ), copyTo , service );
171
+ context .indexSettings (), multiFieldsBuilder .build (this , context ), copyTo ,
172
+ languageTo , service );
163
173
}
164
174
}
165
175
@@ -175,21 +185,19 @@ public static class TypeParser implements Mapper.TypeParser {
175
185
String fieldName = entry .getKey ();
176
186
Object fieldNode = entry .getValue ();
177
187
switch (fieldName ) {
178
- case "analyzer" : {
188
+ case "analyzer" :
179
189
// "_keyword" - we do ignore this, it's our internal analyzer
180
190
iterator .remove ();
181
191
break ;
182
- }
183
- case "search_quote_analyzer" : {
192
+ case "search_quote_analyzer" :
184
193
NamedAnalyzer analyzer = parserContext .analysisService ().analyzer (fieldNode .toString ());
185
194
if (analyzer == null ) {
186
195
throw new MapperParsingException ("Analyzer [" + fieldNode .toString () + "] not found for field [" + name + "]" );
187
196
}
188
197
builder .searchQuotedAnalyzer (analyzer );
189
198
iterator .remove ();
190
199
break ;
191
- }
192
- case "position_increment_gap" : {
200
+ case "position_increment_gap" :
193
201
int newPositionIncrementGap = XContentMapValues .nodeIntegerValue (fieldNode , -1 );
194
202
if (newPositionIncrementGap < 0 ) {
195
203
throw new MapperParsingException ("position_increment_gap less than 0 aren't allowed." );
@@ -206,78 +214,72 @@ public static class TypeParser implements Mapper.TypeParser {
206
214
}
207
215
iterator .remove ();
208
216
break ;
209
- }
210
- case "store" : {
217
+ case "store" :
211
218
builder .store (parseStore (fieldName , fieldNode .toString ()));
212
219
iterator .remove ();
213
220
break ;
214
- }
215
- case "number_of_trials" : {
221
+ case "number_of_trials" :
216
222
builder .ntrials (XContentMapValues .nodeIntegerValue (fieldNode ));
217
223
iterator .remove ();
218
224
break ;
219
- }
220
- case "alpha" : {
225
+ case "alpha" :
221
226
builder .alpha (XContentMapValues .nodeDoubleValue (fieldNode ));
222
227
iterator .remove ();
223
228
break ;
224
- }
225
- case "alpha_width" : {
229
+ case "alpha_width" :
226
230
builder .alphaWidth (XContentMapValues .nodeDoubleValue (fieldNode ));
227
231
iterator .remove ();
228
232
break ;
229
- }
230
- case "iteration_limit" : {
233
+ case "iteration_limit" :
231
234
builder .iterationLimit (XContentMapValues .nodeIntegerValue (fieldNode ));
232
235
iterator .remove ();
233
236
break ;
234
- }
235
- case "prob_threshold" : {
237
+ case "prob_threshold" :
236
238
builder .probThreshold (XContentMapValues .nodeDoubleValue (fieldNode ));
237
239
iterator .remove ();
238
240
break ;
239
- }
240
- case "conv_threshold" : {
241
+ case "conv_threshold" :
241
242
builder .convThreshold (XContentMapValues .nodeDoubleValue (fieldNode ));
242
243
iterator .remove ();
243
244
break ;
244
- }
245
- case "base_freq" : {
245
+ case "base_freq" :
246
246
builder .baseFreq (XContentMapValues .nodeIntegerValue (fieldNode ));
247
247
iterator .remove ();
248
248
break ;
249
- }
250
- case "pattern" : {
249
+ case "pattern" :
251
250
builder .pattern (XContentMapValues .nodeStringValue (fieldNode , null ));
252
251
iterator .remove ();
253
252
break ;
254
- }
255
- case "max" : {
253
+ case "max" :
256
254
builder .max (XContentMapValues .nodeIntegerValue (fieldNode ));
257
255
iterator .remove ();
258
256
break ;
259
- }
260
- case "binary" : {
257
+ case "binary" :
261
258
boolean b = XContentMapValues .nodeBooleanValue (fieldNode );
262
259
builder .binary (b );
263
260
iterator .remove ();
264
261
break ;
265
- }
266
- case "map" : {
262
+ case "map" :
267
263
builder .map (XContentMapValues .nodeMapValue (fieldNode , "map" ));
268
264
iterator .remove ();
269
265
break ;
270
- }
271
- case "languages" : {
266
+ case "languages" :
272
267
builder .languages (XContentMapValues .nodeStringArrayValue (fieldNode ));
273
268
iterator .remove ();
274
269
break ;
275
- }
276
- case "profile" : {
270
+ case "profile" :
277
271
builder .profile (XContentMapValues .nodeStringValue (fieldNode , null ));
278
272
iterator .remove ();
279
273
break ;
280
- }
274
+ case "language_to" :
275
+ Map <String , Object > map = XContentMapValues .nodeMapValue (fieldNode , null );
276
+ LanguageTo .Builder languageToBuilder = LanguageTo .builder ();
277
+ languageToBuilder .add (map );
278
+ builder .languageTo (languageToBuilder .build ());
279
+ iterator .remove ();
280
+ break ;
281
+ default :
282
+ break ;
281
283
}
282
284
}
283
285
return builder ;
@@ -288,17 +290,21 @@ public static class TypeParser implements Mapper.TypeParser {
288
290
289
291
private final int positionIncrementGap ;
290
292
293
+ private final LanguageTo languageTo ;
294
+
291
295
public LangdetectMapper (String simpleName ,
292
- MappedFieldType fieldType ,
293
- MappedFieldType defaultFieldType ,
294
- int positionIncrementGap ,
295
- int ignoreAbove ,
296
- Settings indexSettings ,
297
- MultiFields multiFields ,
298
- CopyTo copyTo ,
299
- LangdetectService langdetectService ) {
296
+ MappedFieldType fieldType ,
297
+ MappedFieldType defaultFieldType ,
298
+ int positionIncrementGap ,
299
+ int ignoreAbove ,
300
+ Settings indexSettings ,
301
+ MultiFields multiFields ,
302
+ CopyTo copyTo ,
303
+ LanguageTo languageTo ,
304
+ LangdetectService langdetectService ) {
300
305
super (simpleName , fieldType , defaultFieldType ,
301
306
positionIncrementGap , ignoreAbove , indexSettings , multiFields , copyTo );
307
+ this .languageTo = languageTo ;
302
308
this .langdetectService = langdetectService ;
303
309
this .positionIncrementGap = positionIncrementGap ;
304
310
}
@@ -337,7 +343,7 @@ protected void parseCreateField(ParseContext context, List<Field> fields) throws
337
343
try {
338
344
byte [] b = parser .binaryValue ();
339
345
if (b != null && b .length > 0 ) {
340
- value = new String (b , Charset . forName ( "UTF-8" ) );
346
+ value = new String (b , StandardCharsets . UTF_8 );
341
347
}
342
348
} catch (Exception e ) {
343
349
// ignore
@@ -348,6 +354,9 @@ protected void parseCreateField(ParseContext context, List<Field> fields) throws
348
354
for (Language lang : langs ) {
349
355
Field field = new Field (fieldType ().names ().indexName (), lang .getLanguage (), fieldType ());
350
356
fields .add (field );
357
+ if (languageTo .languageToFields ().containsKey (lang .getLanguage ())) {
358
+ parseLanguageToFields (context , languageTo .languageToFields ().get (lang .getLanguage ()));
359
+ }
351
360
}
352
361
} catch (LanguageDetectionException e ) {
353
362
context .createExternalValueContext ("unknown" );
@@ -377,5 +386,84 @@ protected void doXContentBody(XContentBuilder builder, boolean includeDefaults,
377
386
for (String key : map .keySet ()) {
378
387
builder .field (key , map .get (key ));
379
388
}
389
+ languageTo .toXContent (builder , params );
380
390
}
381
- }
391
+
392
+ @ SuppressWarnings ("unchecked" )
393
+ private static void parseLanguageToFields (ParseContext originalContext , Object languageToFields ) throws IOException {
394
+ List <Object > fieldList = languageToFields instanceof List ?
395
+ (List <Object >)languageToFields : Collections .singletonList (languageToFields );
396
+ ParseContext context = originalContext .createCopyToContext ();
397
+ for (Object field : fieldList ) {
398
+ ParseContext .Document targetDoc = null ;
399
+ for (ParseContext .Document doc = context .doc (); doc != null ; doc = doc .getParent ()) {
400
+ if (field .toString ().startsWith (doc .getPrefix ())) {
401
+ targetDoc = doc ;
402
+ break ;
403
+ }
404
+ }
405
+ if (targetDoc == null ) {
406
+ throw new IllegalArgumentException ("target doc is null" );
407
+ }
408
+ final ParseContext copyToContext ;
409
+ if (targetDoc == context .doc ()) {
410
+ copyToContext = context ;
411
+ } else {
412
+ copyToContext = context .switchDoc (targetDoc );
413
+ }
414
+ FieldMapper fieldMapper = copyToContext .docMapper ().mappers ().getMapper (field .toString ());
415
+ if (fieldMapper != null ) {
416
+ fieldMapper .parse (copyToContext );
417
+ } else {
418
+ throw new MapperParsingException ("attempt to copy value to non-existing field [" + field + "]" );
419
+ }
420
+ }
421
+ }
422
+
423
+ public static class LanguageTo {
424
+
425
+ private final Map <String , Object > languageToFields ;
426
+
427
+ private LanguageTo (Map <String , Object > languageToFields ) {
428
+ this .languageToFields = languageToFields ;
429
+ }
430
+
431
+ public XContentBuilder toXContent (XContentBuilder builder , Params params ) throws IOException {
432
+ if (!languageToFields .isEmpty ()) {
433
+ builder .startObject ("language_to" );
434
+ for (Map .Entry <String , Object > field : languageToFields .entrySet ()) {
435
+ builder .field (field .getKey (), field .getValue ());
436
+ }
437
+ builder .endObject ();
438
+ }
439
+ return builder ;
440
+ }
441
+
442
+ public static Builder builder () {
443
+ return new Builder ();
444
+ }
445
+
446
+ public static class Builder {
447
+ private final Map <String , Object > languageToBuilders = new LinkedHashMap <>();
448
+
449
+ public LanguageTo .Builder add (String language , String field ) {
450
+ languageToBuilders .put (language , field );
451
+ return this ;
452
+ }
453
+
454
+ public LanguageTo .Builder add (Map <String , Object > map ) {
455
+ languageToBuilders .putAll (map );
456
+ return this ;
457
+ }
458
+
459
+ public LanguageTo build () {
460
+ return new LanguageTo (Collections .unmodifiableMap (languageToBuilders ));
461
+ }
462
+ }
463
+
464
+ public Map <String , Object > languageToFields () {
465
+ return languageToFields ;
466
+ }
467
+ }
468
+
469
+ }
0 commit comments