mirror of
https://github.com/spring-projects/spring-data-elasticsearch.git
synced 2025-07-05 10:12:33 +00:00
DATAES-420 - Analyzer of main field ignored when using @MultiField annotation
This commit is contained in:
parent
36c52a5308
commit
1b0006f9f7
@ -33,11 +33,15 @@ public @interface InnerField {
|
|||||||
|
|
||||||
boolean index() default true;
|
boolean index() default true;
|
||||||
|
|
||||||
|
DateFormat format() default DateFormat.none;
|
||||||
|
|
||||||
|
String pattern() default "";
|
||||||
|
|
||||||
boolean store() default false;
|
boolean store() default false;
|
||||||
|
|
||||||
boolean fielddata() default false;
|
boolean fielddata() default false;
|
||||||
|
|
||||||
String searchAnalyzer() default "";
|
String searchAnalyzer() default "";
|
||||||
|
|
||||||
String indexAnalyzer() default "";
|
String analyzer() default "";
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,7 @@ import static org.springframework.util.StringUtils.*;
|
|||||||
* @author Pavel Luhin
|
* @author Pavel Luhin
|
||||||
* @author Mark Paluch
|
* @author Mark Paluch
|
||||||
* @author Sascha Woo
|
* @author Sascha Woo
|
||||||
|
* @author Nordine Bittich
|
||||||
*/
|
*/
|
||||||
class MappingBuilder {
|
class MappingBuilder {
|
||||||
|
|
||||||
@ -221,85 +222,103 @@ class MappingBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply mapping for a single @Field annotation
|
* Add mapping for @Field annotation
|
||||||
*
|
*
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
private static void addSingleFieldMapping(XContentBuilder xContentBuilder, java.lang.reflect.Field field,
|
private static void addSingleFieldMapping(XContentBuilder builder, java.lang.reflect.Field field, Field annotation, boolean nestedOrObjectField) throws IOException {
|
||||||
Field fieldAnnotation, boolean nestedOrObjectField) throws IOException {
|
|
||||||
xContentBuilder.startObject(field.getName());
|
|
||||||
if(!nestedOrObjectField) {
|
|
||||||
xContentBuilder.field(FIELD_STORE, fieldAnnotation.store());
|
|
||||||
}
|
|
||||||
if(fieldAnnotation.fielddata()) {
|
|
||||||
xContentBuilder.field(FIELD_DATA, fieldAnnotation.fielddata());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FieldType.Auto != fieldAnnotation.type()) {
|
|
||||||
xContentBuilder.field(FIELD_TYPE, fieldAnnotation.type().name().toLowerCase());
|
|
||||||
if (FieldType.Date == fieldAnnotation.type() && DateFormat.none != fieldAnnotation.format()) {
|
|
||||||
xContentBuilder.field(FIELD_FORMAT, DateFormat.custom == fieldAnnotation.format()
|
|
||||||
? fieldAnnotation.pattern() : fieldAnnotation.format());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!fieldAnnotation.index()) {
|
|
||||||
xContentBuilder.field(FIELD_INDEX, fieldAnnotation.index());
|
|
||||||
}
|
|
||||||
if (isNotBlank(fieldAnnotation.searchAnalyzer())) {
|
|
||||||
xContentBuilder.field(FIELD_SEARCH_ANALYZER, fieldAnnotation.searchAnalyzer());
|
|
||||||
}
|
|
||||||
if (isNotBlank(fieldAnnotation.analyzer())) {
|
|
||||||
xContentBuilder.field(FIELD_INDEX_ANALYZER, fieldAnnotation.analyzer());
|
|
||||||
}
|
|
||||||
xContentBuilder.endObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply mapping for a single nested @Field annotation
|
|
||||||
*
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
private static void addNestedFieldMapping(XContentBuilder builder, java.lang.reflect.Field field,
|
|
||||||
InnerField annotation) throws IOException {
|
|
||||||
builder.startObject(annotation.suffix());
|
|
||||||
//builder.field(FIELD_STORE, annotation.store());
|
|
||||||
if (FieldType.Auto != annotation.type()) {
|
|
||||||
builder.field(FIELD_TYPE, annotation.type().name().toLowerCase());
|
|
||||||
}
|
|
||||||
if(!annotation.index()) {
|
|
||||||
builder.field(FIELD_INDEX, annotation.index());
|
|
||||||
}
|
|
||||||
if (isNotBlank(annotation.searchAnalyzer())) {
|
|
||||||
builder.field(FIELD_SEARCH_ANALYZER, annotation.searchAnalyzer());
|
|
||||||
}
|
|
||||||
if (isNotBlank(annotation.indexAnalyzer())) {
|
|
||||||
builder.field(FIELD_INDEX_ANALYZER, annotation.indexAnalyzer());
|
|
||||||
}
|
|
||||||
if (annotation.fielddata()) {
|
|
||||||
builder.field(FIELD_DATA, annotation.fielddata());
|
|
||||||
}
|
|
||||||
builder.endObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Multi field mappings for string type fields, support for sorts and facets
|
|
||||||
*
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
private static void addMultiFieldMapping(XContentBuilder builder, java.lang.reflect.Field field,
|
|
||||||
MultiField annotation, boolean nestedOrObjectField) throws IOException {
|
|
||||||
builder.startObject(field.getName());
|
builder.startObject(field.getName());
|
||||||
builder.field(FIELD_TYPE, annotation.mainField().type().name().toLowerCase());
|
addFieldMappingParameters(builder, annotation, nestedOrObjectField);
|
||||||
|
builder.endObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add mapping for @MultiField annotation
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private static void addMultiFieldMapping(
|
||||||
|
XContentBuilder builder,
|
||||||
|
java.lang.reflect.Field field,
|
||||||
|
MultiField annotation,
|
||||||
|
boolean nestedOrObjectField) throws IOException {
|
||||||
|
|
||||||
|
// main field
|
||||||
|
builder.startObject(field.getName());
|
||||||
|
addFieldMappingParameters(builder, annotation.mainField(), nestedOrObjectField);
|
||||||
|
|
||||||
|
// inner fields
|
||||||
builder.startObject("fields");
|
builder.startObject("fields");
|
||||||
//add standard field
|
|
||||||
//addSingleFieldMapping(builder, field, annotation.mainField(), nestedOrObjectField);
|
|
||||||
for (InnerField innerField : annotation.otherFields()) {
|
for (InnerField innerField : annotation.otherFields()) {
|
||||||
addNestedFieldMapping(builder, field, innerField);
|
builder.startObject(innerField.suffix());
|
||||||
|
addFieldMappingParameters(builder, innerField, false);
|
||||||
|
builder.endObject();
|
||||||
}
|
}
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
|
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void addFieldMappingParameters(XContentBuilder builder, Object annotation, boolean nestedOrObjectField) throws IOException {
|
||||||
|
boolean index = true;
|
||||||
|
boolean store = false;
|
||||||
|
boolean fielddata = false;
|
||||||
|
FieldType type = null;
|
||||||
|
DateFormat dateFormat = null;
|
||||||
|
String datePattern = null;
|
||||||
|
String analyzer = null;
|
||||||
|
String searchAnalyzer = null;
|
||||||
|
|
||||||
|
if (annotation instanceof Field) {
|
||||||
|
// @Field
|
||||||
|
Field fieldAnnotation = (Field) annotation;
|
||||||
|
index = fieldAnnotation.index();
|
||||||
|
store = fieldAnnotation.store();
|
||||||
|
fielddata = fieldAnnotation.fielddata();
|
||||||
|
type = fieldAnnotation.type();
|
||||||
|
dateFormat = fieldAnnotation.format();
|
||||||
|
datePattern = fieldAnnotation.pattern();
|
||||||
|
analyzer = fieldAnnotation.analyzer();
|
||||||
|
searchAnalyzer = fieldAnnotation.searchAnalyzer();
|
||||||
|
} else if (annotation instanceof InnerField) {
|
||||||
|
// @InnerField
|
||||||
|
InnerField fieldAnnotation = (InnerField) annotation;
|
||||||
|
index = fieldAnnotation.index();
|
||||||
|
store = fieldAnnotation.store();
|
||||||
|
fielddata = fieldAnnotation.fielddata();
|
||||||
|
type = fieldAnnotation.type();
|
||||||
|
dateFormat = fieldAnnotation.format();
|
||||||
|
datePattern = fieldAnnotation.pattern();
|
||||||
|
analyzer = fieldAnnotation.analyzer();
|
||||||
|
searchAnalyzer = fieldAnnotation.searchAnalyzer();
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("annotation must be an instance of @Field or @InnerField");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!nestedOrObjectField) {
|
||||||
|
builder.field(FIELD_STORE, store);
|
||||||
|
}
|
||||||
|
if (fielddata) {
|
||||||
|
builder.field(FIELD_DATA, fielddata);
|
||||||
|
}
|
||||||
|
if (type != FieldType.Auto) {
|
||||||
|
builder.field(FIELD_TYPE, type.name().toLowerCase());
|
||||||
|
|
||||||
|
if (type == FieldType.Date && dateFormat != DateFormat.none) {
|
||||||
|
builder.field(FIELD_FORMAT, dateFormat == DateFormat.custom ? datePattern : dateFormat.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!index) {
|
||||||
|
builder.field(FIELD_INDEX, index);
|
||||||
|
}
|
||||||
|
if (isNotBlank(analyzer)) {
|
||||||
|
builder.field(FIELD_INDEX_ANALYZER, analyzer);
|
||||||
|
}
|
||||||
|
if (isNotBlank(searchAnalyzer)) {
|
||||||
|
builder.field(FIELD_SEARCH_ANALYZER, searchAnalyzer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected static boolean isEntity(java.lang.reflect.Field field) {
|
protected static boolean isEntity(java.lang.reflect.Field field) {
|
||||||
TypeInformation typeInformation = ClassTypeInformation.from(field.getType());
|
TypeInformation typeInformation = ClassTypeInformation.from(field.getType());
|
||||||
Class<?> clazz = getFieldType(field);
|
Class<?> clazz = getFieldType(field);
|
||||||
|
@ -25,6 +25,7 @@ import java.io.IOException;
|
|||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@ -43,6 +44,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
|||||||
* @author Jakub Vavrik
|
* @author Jakub Vavrik
|
||||||
* @author Mohsin Husen
|
* @author Mohsin Husen
|
||||||
* @author Keivn Leturc
|
* @author Keivn Leturc
|
||||||
|
* @author Nordine Bittich
|
||||||
*/
|
*/
|
||||||
@RunWith(SpringJUnit4ClassRunner.class)
|
@RunWith(SpringJUnit4ClassRunner.class)
|
||||||
@ContextConfiguration("classpath:elasticsearch-template-test.xml")
|
@ContextConfiguration("classpath:elasticsearch-template-test.xml")
|
||||||
@ -189,8 +191,28 @@ public class MappingBuilderTests {
|
|||||||
elasticsearchTemplate.createIndex(Book.class);
|
elasticsearchTemplate.createIndex(Book.class);
|
||||||
elasticsearchTemplate.putMapping(Book.class);
|
elasticsearchTemplate.putMapping(Book.class);
|
||||||
//when
|
//when
|
||||||
|
|
||||||
//then
|
//then
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test // DATAES-420
|
||||||
|
public void shouldUseBothAnalyzer() {
|
||||||
|
//given
|
||||||
|
elasticsearchTemplate.deleteIndex(Book.class);
|
||||||
|
elasticsearchTemplate.createIndex(Book.class);
|
||||||
|
elasticsearchTemplate.putMapping(Book.class);
|
||||||
|
|
||||||
|
//when
|
||||||
|
Map mapping = elasticsearchTemplate.getMapping(Book.class);
|
||||||
|
Map descriptionMapping = (Map) ((Map) mapping.get("properties")).get("description");
|
||||||
|
Map prefixDescription = (Map) ((Map) descriptionMapping.get("fields")).get("prefix");
|
||||||
|
|
||||||
|
//then
|
||||||
|
assertThat(prefixDescription.size(), is(3));
|
||||||
|
assertThat(prefixDescription.get("type"), equalTo("text"));
|
||||||
|
assertThat(prefixDescription.get("analyzer"), equalTo("stop"));
|
||||||
|
assertThat(prefixDescription.get("search_analyzer"), equalTo("standard"));
|
||||||
|
assertThat(descriptionMapping.get("type"), equalTo("text"));
|
||||||
|
assertThat(descriptionMapping.get("analyzer"), equalTo("whitespace"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,8 +42,8 @@ public class ArticleEntity {
|
|||||||
@MultiField(
|
@MultiField(
|
||||||
mainField = @Field(type = Text),
|
mainField = @Field(type = Text),
|
||||||
otherFields = {
|
otherFields = {
|
||||||
@InnerField(suffix = "untouched", type = Text, store = true, fielddata = true, indexAnalyzer = "keyword"),
|
@InnerField(suffix = "untouched", type = Text, store = true, fielddata = true, analyzer = "keyword"),
|
||||||
@InnerField(suffix = "sort", type = Text, store = true, indexAnalyzer = "keyword")
|
@InnerField(suffix = "sort", type = Text, store = true, analyzer = "keyword")
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
private List<String> authors = new ArrayList<>();
|
private List<String> authors = new ArrayList<>();
|
||||||
|
@ -29,10 +29,13 @@ import org.springframework.data.annotation.Id;
|
|||||||
import org.springframework.data.elasticsearch.annotations.Document;
|
import org.springframework.data.elasticsearch.annotations.Document;
|
||||||
import org.springframework.data.elasticsearch.annotations.Field;
|
import org.springframework.data.elasticsearch.annotations.Field;
|
||||||
import org.springframework.data.elasticsearch.annotations.FieldType;
|
import org.springframework.data.elasticsearch.annotations.FieldType;
|
||||||
|
import org.springframework.data.elasticsearch.annotations.InnerField;
|
||||||
|
import org.springframework.data.elasticsearch.annotations.MultiField;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Rizwan Idrees
|
* @author Rizwan Idrees
|
||||||
* @author Mohsin Husen
|
* @author Mohsin Husen
|
||||||
|
* @author Nordine Bittich
|
||||||
*/
|
*/
|
||||||
@Setter
|
@Setter
|
||||||
@Getter
|
@Getter
|
||||||
@ -49,4 +52,11 @@ public class Book {
|
|||||||
private Author author;
|
private Author author;
|
||||||
@Field(type = FieldType.Nested)
|
@Field(type = FieldType.Nested)
|
||||||
private Map<Integer, Collection<String>> buckets = new HashMap<>();
|
private Map<Integer, Collection<String>> buckets = new HashMap<>();
|
||||||
|
@MultiField(
|
||||||
|
mainField = @Field(type = FieldType.Text, analyzer = "whitespace"),
|
||||||
|
otherFields = {
|
||||||
|
@InnerField(suffix = "prefix", type = FieldType.Text, analyzer = "stop", searchAnalyzer = "standard")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
private String description;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user