mirror of
https://github.com/spring-projects/spring-data-elasticsearch.git
synced 2025-06-12 07:02:10 +00:00
DATAES-132 - adding possibility to configure mapping with nested and include in parent option
This commit is contained in:
parent
cd9ed2cde8
commit
7cf7cb9168
@ -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;
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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()));
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user