DATAES-132 - adding possibility to configure mapping with nested and include in parent option

This commit is contained in:
msachs 2014-10-20 21:52:54 +02:00 committed by Mohsin Husen
parent cd9ed2cde8
commit 7cf7cb9168
5 changed files with 131 additions and 74 deletions

View File

@ -15,7 +15,12 @@
*/
package org.springframework.data.elasticsearch.annotations;
import java.lang.annotation.*;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author Rizwan Idrees
@ -46,4 +51,7 @@ public @interface Field {
String indexAnalyzer() default "";
String[] ignoreFields() default {};
boolean includeInParent() default false;
}

View File

@ -79,13 +79,13 @@ class MappingBuilder {
// Properties
XContentBuilder xContentBuilder = mapping.startObject(FIELD_PROPERTIES);
mapEntity(xContentBuilder, clazz, true, idFieldName, EMPTY, false, FieldType.Auto);
mapEntity(xContentBuilder, clazz, true, idFieldName, EMPTY, false, FieldType.Auto,null);
return xContentBuilder.endObject().endObject().endObject();
}
private static void mapEntity(XContentBuilder xContentBuilder, Class clazz, boolean isRootObject, String idFieldName,
String nestedObjectFieldName, boolean nestedOrObjectField, FieldType fieldType) throws IOException {
String nestedObjectFieldName, boolean nestedOrObjectField, FieldType fieldType, Field fieldAnnotation) throws IOException {
java.lang.reflect.Field[] fields = retrieveFields(clazz);
@ -94,7 +94,12 @@ class MappingBuilder {
if (nestedOrObjectField) {
type = fieldType.toString().toLowerCase();
}
xContentBuilder.startObject(nestedObjectFieldName).field(FIELD_TYPE, type).startObject(FIELD_PROPERTIES);
XContentBuilder t = xContentBuilder.startObject(nestedObjectFieldName).field(FIELD_TYPE, type);
if (nestedOrObjectField && FieldType.Nested == fieldType && fieldAnnotation.includeInParent()) {
t.field("include_in_parent", fieldAnnotation.includeInParent());
}
t.startObject(FIELD_PROPERTIES);
}
for (java.lang.reflect.Field field : fields) {
@ -112,7 +117,7 @@ class MappingBuilder {
continue;
}
boolean nestedOrObject = isNestedOrObjectField(field);
mapEntity(xContentBuilder, getFieldType(field), false, EMPTY, field.getName(), nestedOrObject, singleField.type());
mapEntity(xContentBuilder, getFieldType(field), false, EMPTY, field.getName(), nestedOrObject, singleField.type(),field.getAnnotation(Field.class));
if (nestedOrObject) {
continue;
}

View File

@ -15,13 +15,20 @@
*/
package org.springframework.data.elasticsearch;
import static org.apache.commons.lang.RandomStringUtils.*;
import static org.elasticsearch.index.query.QueryBuilders.*;
import static org.apache.commons.lang.RandomStringUtils.randomNumeric;
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.nestedQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.Assert.*;
import static org.junit.Assert.assertThat;
import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
@ -35,7 +42,12 @@ import org.springframework.data.elasticsearch.core.query.GetQuery;
import org.springframework.data.elasticsearch.core.query.IndexQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.data.elasticsearch.entities.*;
import org.springframework.data.elasticsearch.entities.Author;
import org.springframework.data.elasticsearch.entities.Book;
import org.springframework.data.elasticsearch.entities.Car;
import org.springframework.data.elasticsearch.entities.GirlFriend;
import org.springframework.data.elasticsearch.entities.Person;
import org.springframework.data.elasticsearch.entities.PersonMultipleLevelNested;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@ -71,17 +83,17 @@ public class NestedObjectTests {
@Test
public void shouldIndexInitialLevelNestedObject() {
List<Car> cars = new ArrayList<Car>();
final List<Car> cars = new ArrayList<Car>();
Car saturn = new Car();
final Car saturn = new Car();
saturn.setName("Saturn");
saturn.setModel("SL");
Car subaru = new Car();
final Car subaru = new Car();
subaru.setName("Subaru");
subaru.setModel("Imprezza");
Car ford = new Car();
final Car ford = new Car();
ford.setName("Ford");
ford.setModel("Focus");
@ -89,26 +101,26 @@ public class NestedObjectTests {
cars.add(subaru);
cars.add(ford);
Person foo = new Person();
final Person foo = new Person();
foo.setName("Foo");
foo.setId("1");
foo.setCar(cars);
Car car = new Car();
final Car car = new Car();
car.setName("Saturn");
car.setModel("Imprezza");
Person bar = new Person();
final Person bar = new Person();
bar.setId("2");
bar.setName("Bar");
bar.setCar(Arrays.asList(car));
List<IndexQuery> indexQueries = new ArrayList<IndexQuery>();
IndexQuery indexQuery1 = new IndexQuery();
final List<IndexQuery> indexQueries = new ArrayList<IndexQuery>();
final IndexQuery indexQuery1 = new IndexQuery();
indexQuery1.setId(foo.getId());
indexQuery1.setObject(foo);
IndexQuery indexQuery2 = new IndexQuery();
final IndexQuery indexQuery2 = new IndexQuery();
indexQuery2.setId(bar.getId());
indexQuery2.setObject(bar);
@ -119,10 +131,10 @@ public class NestedObjectTests {
elasticsearchTemplate.bulkIndex(indexQueries);
elasticsearchTemplate.refresh(Person.class, true);
QueryBuilder builder = nestedQuery("car", boolQuery().must(termQuery("car.name", "saturn")).must(termQuery("car.model", "imprezza")));
final QueryBuilder builder = nestedQuery("car", boolQuery().must(termQuery("car.name", "saturn")).must(termQuery("car.model", "imprezza")));
SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(builder).build();
List<Person> persons = elasticsearchTemplate.queryForList(searchQuery, Person.class);
final SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(builder).build();
final List<Person> persons = elasticsearchTemplate.queryForList(searchQuery, Person.class);
assertThat(persons.size(), is(1));
}
@ -130,7 +142,7 @@ public class NestedObjectTests {
@Test
public void shouldIndexMultipleLevelNestedObject() {
//given
List<IndexQuery> indexQueries = createPerson();
final List<IndexQuery> indexQueries = createPerson();
//when
elasticsearchTemplate.putMapping(PersonMultipleLevelNested.class);
@ -138,16 +150,36 @@ public class NestedObjectTests {
elasticsearchTemplate.refresh(PersonMultipleLevelNested.class, true);
//then
GetQuery getQuery = new GetQuery();
final GetQuery getQuery = new GetQuery();
getQuery.setId("1");
PersonMultipleLevelNested personIndexed = elasticsearchTemplate.queryForObject(getQuery, PersonMultipleLevelNested.class);
final PersonMultipleLevelNested personIndexed = elasticsearchTemplate.queryForObject(getQuery, PersonMultipleLevelNested.class);
assertThat(personIndexed, is(notNullValue()));
}
@Test
public void shouldIndexMultipleLevelNestedObjectWithIncludeInParent() {
//given
final List<IndexQuery> indexQueries = createPerson();
//when
elasticsearchTemplate.putMapping(PersonMultipleLevelNested.class);
elasticsearchTemplate.bulkIndex(indexQueries);
// then
final Map mapping = elasticsearchTemplate.getMapping(PersonMultipleLevelNested.class);
assertThat(mapping,is(notNullValue()));
final Map propertyMap = (Map) mapping.get("properties");
assertThat(propertyMap,is(notNullValue()));
final Map bestCarsAttributes = (Map) propertyMap.get("bestCars");
assertThat(bestCarsAttributes.get("include_in_parent"),is(notNullValue()));
}
@Test
public void shouldSearchUsingNestedQueryOnMultipleLevelNestedObject() {
//given
List<IndexQuery> indexQueries = createPerson();
final List<IndexQuery> indexQueries = createPerson();
//when
elasticsearchTemplate.putMapping(PersonMultipleLevelNested.class);
@ -155,15 +187,15 @@ public class NestedObjectTests {
elasticsearchTemplate.refresh(PersonMultipleLevelNested.class, true);
//then
BoolQueryBuilder builder = boolQuery();
final BoolQueryBuilder builder = boolQuery();
builder.must(nestedQuery("girlFriends", termQuery("girlFriends.type", "temp")))
.must(nestedQuery("girlFriends.cars", termQuery("girlFriends.cars.name", "Ford".toLowerCase())));
.must(nestedQuery("girlFriends.cars", termQuery("girlFriends.cars.name", "Ford".toLowerCase())));
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(builder)
.build();
final SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(builder)
.build();
Page<PersonMultipleLevelNested> personIndexed = elasticsearchTemplate.queryForPage(searchQuery, PersonMultipleLevelNested.class);
final Page<PersonMultipleLevelNested> personIndexed = elasticsearchTemplate.queryForPage(searchQuery, PersonMultipleLevelNested.class);
assertThat(personIndexed, is(notNullValue()));
assertThat(personIndexed.getTotalElements(), is(1L));
assertThat(personIndexed.getContent().get(0).getId(), is("1"));
@ -172,55 +204,55 @@ public class NestedObjectTests {
private List<IndexQuery> createPerson() {
PersonMultipleLevelNested person1 = new PersonMultipleLevelNested();
final PersonMultipleLevelNested person1 = new PersonMultipleLevelNested();
person1.setId("1");
person1.setName("name");
Car saturn = new Car();
final Car saturn = new Car();
saturn.setName("Saturn");
saturn.setModel("SL");
Car subaru = new Car();
final Car subaru = new Car();
subaru.setName("Subaru");
subaru.setModel("Imprezza");
Car car = new Car();
final Car car = new Car();
car.setName("Saturn");
car.setModel("Imprezza");
Car ford = new Car();
final Car ford = new Car();
ford.setName("Ford");
ford.setModel("Focus");
GirlFriend permanent = new GirlFriend();
final GirlFriend permanent = new GirlFriend();
permanent.setName("permanent");
permanent.setType("permanent");
permanent.setCars(Arrays.asList(saturn, subaru));
GirlFriend temp = new GirlFriend();
final GirlFriend temp = new GirlFriend();
temp.setName("temp");
temp.setType("temp");
temp.setCars(Arrays.asList(car, ford));
person1.setGirlFriends(Arrays.asList(permanent, temp));
IndexQuery indexQuery1 = new IndexQuery();
final IndexQuery indexQuery1 = new IndexQuery();
indexQuery1.setId(person1.getId());
indexQuery1.setObject(person1);
PersonMultipleLevelNested person2 = new PersonMultipleLevelNested();
final PersonMultipleLevelNested person2 = new PersonMultipleLevelNested();
person2.setId("2");
person2.setName("name");
person2.setGirlFriends(Arrays.asList(permanent));
IndexQuery indexQuery2 = new IndexQuery();
final IndexQuery indexQuery2 = new IndexQuery();
indexQuery2.setId(person2.getId());
indexQuery2.setObject(person2);
List<IndexQuery> indexQueries = new ArrayList<IndexQuery>();
final List<IndexQuery> indexQueries = new ArrayList<IndexQuery>();
indexQueries.add(indexQuery1);
indexQueries.add(indexQuery2);
@ -230,17 +262,17 @@ public class NestedObjectTests {
@Test
public void shouldSearchBooksForPersonInitialLevelNestedType() {
List<Car> cars = new ArrayList<Car>();
final List<Car> cars = new ArrayList<Car>();
Car saturn = new Car();
final Car saturn = new Car();
saturn.setName("Saturn");
saturn.setModel("SL");
Car subaru = new Car();
final Car subaru = new Car();
subaru.setName("Subaru");
subaru.setModel("Imprezza");
Car ford = new Car();
final Car ford = new Car();
ford.setName("Ford");
ford.setModel("Focus");
@ -248,43 +280,43 @@ public class NestedObjectTests {
cars.add(subaru);
cars.add(ford);
Book java = new Book();
final Book java = new Book();
java.setId("1");
java.setName("java");
Author javaAuthor = new Author();
final Author javaAuthor = new Author();
javaAuthor.setId("1");
javaAuthor.setName("javaAuthor");
java.setAuthor(javaAuthor);
Book spring = new Book();
final Book spring = new Book();
spring.setId("2");
spring.setName("spring");
Author springAuthor = new Author();
final Author springAuthor = new Author();
springAuthor.setId("2");
springAuthor.setName("springAuthor");
spring.setAuthor(springAuthor);
Person foo = new Person();
final Person foo = new Person();
foo.setName("Foo");
foo.setId("1");
foo.setCar(cars);
foo.setBooks(Arrays.asList(java, spring));
Car car = new Car();
final Car car = new Car();
car.setName("Saturn");
car.setModel("Imprezza");
Person bar = new Person();
final Person bar = new Person();
bar.setId("2");
bar.setName("Bar");
bar.setCar(Arrays.asList(car));
List<IndexQuery> indexQueries = new ArrayList<IndexQuery>();
IndexQuery indexQuery1 = new IndexQuery();
final List<IndexQuery> indexQueries = new ArrayList<IndexQuery>();
final IndexQuery indexQuery1 = new IndexQuery();
indexQuery1.setId(foo.getId());
indexQuery1.setObject(foo);
IndexQuery indexQuery2 = new IndexQuery();
final IndexQuery indexQuery2 = new IndexQuery();
indexQuery2.setId(bar.getId());
indexQuery2.setObject(bar);
@ -295,22 +327,22 @@ public class NestedObjectTests {
elasticsearchTemplate.bulkIndex(indexQueries);
elasticsearchTemplate.refresh(Person.class, true);
QueryBuilder builder = nestedQuery("books", boolQuery().must(termQuery("books.name", "java")));
final QueryBuilder builder = nestedQuery("books", boolQuery().must(termQuery("books.name", "java")));
SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(builder).build();
List<Person> persons = elasticsearchTemplate.queryForList(searchQuery, Person.class);
final SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(builder).build();
final List<Person> persons = elasticsearchTemplate.queryForList(searchQuery, Person.class);
assertThat(persons.size(), is(1));
}
/*
DATAES-73
*/
*/
@Test
public void shouldIndexAndSearchMapAsNestedType() {
//given
Book book1 = new Book();
Book book2 = new Book();
final Book book1 = new Book();
final Book book2 = new Book();
book1.setId(randomNumeric(5));
book1.setName("testBook1");
@ -318,21 +350,21 @@ public class NestedObjectTests {
book2.setId(randomNumeric(5));
book2.setName("testBook2");
Map<Integer, Collection<String>> map1 = new HashMap<Integer, Collection<String>>();
final Map<Integer, Collection<String>> map1 = new HashMap<Integer, Collection<String>>();
map1.put(1, Arrays.asList("test1", "test2"));
Map<Integer, Collection<String>> map2 = new HashMap<Integer, Collection<String>>();
final Map<Integer, Collection<String>> map2 = new HashMap<Integer, Collection<String>>();
map2.put(1, Arrays.asList("test3", "test4"));
book1.setBuckets(map1);
book2.setBuckets(map2);
List<IndexQuery> indexQueries = new ArrayList<IndexQuery>();
IndexQuery indexQuery1 = new IndexQuery();
final List<IndexQuery> indexQueries = new ArrayList<IndexQuery>();
final IndexQuery indexQuery1 = new IndexQuery();
indexQuery1.setId(book1.getId());
indexQuery1.setObject(book1);
IndexQuery indexQuery2 = new IndexQuery();
final IndexQuery indexQuery2 = new IndexQuery();
indexQuery2.setId(book2.getId());
indexQuery2.setObject(book2);
@ -342,10 +374,10 @@ public class NestedObjectTests {
elasticsearchTemplate.bulkIndex(indexQueries);
elasticsearchTemplate.refresh(Book.class, true);
//then
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(nestedQuery("buckets", termQuery("buckets.1", "test3")))
.build();
Page<Book> books = elasticsearchTemplate.queryForPage(searchQuery, Book.class);
final SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(nestedQuery("buckets", termQuery("buckets.1", "test3")))
.build();
final Page<Book> books = elasticsearchTemplate.queryForPage(searchQuery, Book.class);
assertThat(books.getContent().size(), is(1));
assertThat(books.getContent().get(0).getId(), is(book2.getId()));

View File

@ -40,7 +40,7 @@ public class Person {
@Field(type = FieldType.Nested)
private List<Car> car;
@Field(type = FieldType.Nested)
@Field(type = FieldType.Nested, includeInParent=true)
private List<Book> books;
public String getId() {

View File

@ -43,6 +43,9 @@ public class PersonMultipleLevelNested {
@Field(type = FieldType.Nested)
private List<Car> cars;
@Field(type = FieldType.Nested, includeInParent=true)
private List<Car> bestCars;
public String getId() {
return id;
}
@ -74,4 +77,13 @@ public class PersonMultipleLevelNested {
public void setCars(List<Car> cars) {
this.cars = cars;
}
public List<Car> getBestCars() {
return bestCars;
}
public void setBestCars(List<Car> bestCars) {
this.bestCars = bestCars;
}
}