Skip to content

Commit 56ff9bc

Browse files
committed
Apply keyword normalizers in the field retrieval API. (elastic#59260)
As we discussed in the meta-issue, when returning `keyword` in the fields retrieval API, we'll apply their `normalizer`. This decision is not a clear-cut one, and we'll validate it with internal users before merging the feature branch.
1 parent 2fe80b4 commit 56ff9bc

File tree

2 files changed

+41
-19
lines changed

2 files changed

+41
-19
lines changed

server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java

+34-19
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
import org.elasticsearch.search.aggregations.support.CoreValuesSourceType;
4848

4949
import java.io.IOException;
50+
import java.io.UncheckedIOException;
5051
import java.util.Collections;
5152
import java.util.Iterator;
5253
import java.util.List;
@@ -361,25 +362,9 @@ protected void parseCreateField(ParseContext context) throws IOException {
361362
return;
362363
}
363364

364-
final NamedAnalyzer normalizer = fieldType().normalizer();
365+
NamedAnalyzer normalizer = fieldType().normalizer();
365366
if (normalizer != null) {
366-
try (TokenStream ts = normalizer.tokenStream(name(), value)) {
367-
final CharTermAttribute termAtt = ts.addAttribute(CharTermAttribute.class);
368-
ts.reset();
369-
if (ts.incrementToken() == false) {
370-
throw new IllegalStateException("The normalization token stream is "
371-
+ "expected to produce exactly 1 token, but got 0 for analyzer "
372-
+ normalizer + " and input \"" + value + "\"");
373-
}
374-
final String newValue = termAtt.toString();
375-
if (ts.incrementToken()) {
376-
throw new IllegalStateException("The normalization token stream is "
377-
+ "expected to produce exactly 1 token, but got 2+ for analyzer "
378-
+ normalizer + " and input \"" + value + "\"");
379-
}
380-
ts.end();
381-
value = newValue;
382-
}
367+
value = normalizeValue(normalizer, value);
383368
}
384369

385370
// convert to utf8 only once before feeding postings/dv/stored fields
@@ -398,6 +383,26 @@ protected void parseCreateField(ParseContext context) throws IOException {
398383
}
399384
}
400385

386+
private String normalizeValue(NamedAnalyzer normalizer, String value) throws IOException {
387+
try (TokenStream ts = normalizer.tokenStream(name(), value)) {
388+
final CharTermAttribute termAtt = ts.addAttribute(CharTermAttribute.class);
389+
ts.reset();
390+
if (ts.incrementToken() == false) {
391+
throw new IllegalStateException("The normalization token stream is "
392+
+ "expected to produce exactly 1 token, but got 0 for analyzer "
393+
+ normalizer + " and input \"" + value + "\"");
394+
}
395+
final String newValue = termAtt.toString();
396+
if (ts.incrementToken()) {
397+
throw new IllegalStateException("The normalization token stream is "
398+
+ "expected to produce exactly 1 token, but got 2+ for analyzer "
399+
+ normalizer + " and input \"" + value + "\"");
400+
}
401+
ts.end();
402+
return newValue;
403+
}
404+
}
405+
401406
@Override
402407
protected String parseSourceValue(Object value, String format) {
403408
if (format != null) {
@@ -408,7 +413,17 @@ protected String parseSourceValue(Object value, String format) {
408413
if (keywordValue.length() > ignoreAbove) {
409414
return null;
410415
}
411-
return keywordValue;
416+
417+
NamedAnalyzer normalizer = fieldType().normalizer();
418+
if (normalizer == null) {
419+
return keywordValue;
420+
}
421+
422+
try {
423+
return normalizeValue(normalizer, keywordValue);
424+
} catch (IOException e) {
425+
throw new UncheckedIOException(e);
426+
}
412427
}
413428

414429
@Override

server/src/test/java/org/elasticsearch/index/mapper/KeywordFieldMapperTests.java

+7
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,13 @@ public void testParseSourceValue() {
650650
assertEquals("42", ignoreAboveMapper.parseSourceValue(42L, null));
651651
assertEquals("true", ignoreAboveMapper.parseSourceValue(true, null));
652652

653+
KeywordFieldMapper normalizerMapper = new KeywordFieldMapper.Builder("field")
654+
.normalizer(indexService.getIndexAnalyzers(), "lowercase")
655+
.build(context);
656+
assertEquals("value", normalizerMapper.parseSourceValue("VALUE", null));
657+
assertEquals("42", normalizerMapper.parseSourceValue(42L, null));
658+
assertEquals("value", normalizerMapper.parseSourceValue("value", null));
659+
653660
KeywordFieldMapper nullValueMapper = new KeywordFieldMapper.Builder("field")
654661
.nullValue("NULL")
655662
.build(context);

0 commit comments

Comments
 (0)