DATAES-86 - Add dynamic mapping(json) using @Mapping annotation

This commit is contained in:
Mohsin Husen 2014-04-30 11:48:00 +01:00
parent 8c63f3ee22
commit 9ce87f147a
6 changed files with 108 additions and 42 deletions

View File

@ -0,0 +1,34 @@
/*
* Copyright 2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.elasticsearch.annotations;
import java.lang.annotation.*;
import org.springframework.data.annotation.Persistent;
/**
* Elasticsearch Mapping
*
* @author Mohsin Husen
*/
@Persistent
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface Mapping {
String mappingPath() default "";
}

View File

@ -75,6 +75,7 @@ import org.springframework.data.domain.Page;
import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.ElasticsearchException; import org.springframework.data.elasticsearch.ElasticsearchException;
import org.springframework.data.elasticsearch.annotations.Document; import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Mapping;
import org.springframework.data.elasticsearch.annotations.Setting; import org.springframework.data.elasticsearch.annotations.Setting;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter; import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter; import org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter;
@ -138,6 +139,17 @@ public class ElasticsearchTemplate implements ElasticsearchOperations {
@Override @Override
public <T> boolean putMapping(Class<T> clazz) { public <T> boolean putMapping(Class<T> clazz) {
if (clazz.isAnnotationPresent(Mapping.class)) {
String mappingPath = clazz.getAnnotation(Mapping.class).mappingPath();
if (isNotBlank(mappingPath)) {
String mappings = readFileFromClasspath(mappingPath);
if (isNotBlank(mappings)) {
return putMapping(clazz, mappings);
}
} else {
logger.info("mappingPath in @Mapping has to be defined. Building mappings using @Field");
}
}
ElasticsearchPersistentEntity<T> persistentEntity = getPersistentEntityFor(clazz); ElasticsearchPersistentEntity<T> persistentEntity = getPersistentEntityFor(clazz);
XContentBuilder xContentBuilder = null; XContentBuilder xContentBuilder = null;
try { try {

View File

@ -16,24 +16,21 @@
package org.springframework.data.elasticsearch.entities; package org.springframework.data.elasticsearch.entities;
import org.springframework.data.annotation.Id; import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document; import org.springframework.data.elasticsearch.annotations.*;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import org.springframework.data.elasticsearch.annotations.Setting;
/** /**
* Sample SettingEntity for test out dynamic setting using @Setting Annotation * Sample DynamicSettingAndMappingEntity for test out dynamic setting using @Setting Annotation
* *
* @author Mohsin Husen * @author Mohsin Husen
*/ */
@Setting(settingPath = "/settings/test-settings.json")
@Document(indexName = "test-setting-index", type = "test-setting-type") @Document(indexName = "test-setting-index", type = "test-setting-type")
public class SettingEntity { @Setting(settingPath = "/settings/test-settings.json")
@Mapping(mappingPath = "/mappings/test-mappings.json")
public class DynamicSettingAndMappingEntity {
@Id @Id
private String id; private String id;
private String name; private String name;
@Field(type = FieldType.String, searchAnalyzer = "emailAnalyzer", indexAnalyzer = "emailAnalyzer")
private String email; private String email;
public String getId() { public String getId() {

View File

@ -15,14 +15,14 @@
*/ */
package org.springframework.data.elasticsearch.repositories.setting; package org.springframework.data.elasticsearch.repositories.setting;
import org.springframework.data.elasticsearch.entities.SettingEntity; import org.springframework.data.elasticsearch.entities.DynamicSettingAndMappingEntity;
import org.springframework.data.elasticsearch.repository.ElasticsearchCrudRepository; import org.springframework.data.elasticsearch.repository.ElasticsearchCrudRepository;
/** /**
* SettingEntityRepository * DynamicSettingAndMappingEntityRepository
* *
* @author Mohsin Husen * @author Mohsin Husen
*/ */
public interface SettingEntityRepository extends ElasticsearchCrudRepository<SettingEntity, String> { public interface DynamicSettingAndMappingEntityRepository extends ElasticsearchCrudRepository<DynamicSettingAndMappingEntity, String> {
} }

View File

@ -30,31 +30,31 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate; import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder; import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery; import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.data.elasticsearch.entities.SettingEntity; import org.springframework.data.elasticsearch.entities.DynamicSettingAndMappingEntity;
import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/** /**
* SettingEntityRepositoryTest * DynamicSettingAndMappingEntityRepositoryTests
* *
* @author Mohsin Husen * @author Mohsin Husen
*/ */
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:dynamic-settings-test.xml") @ContextConfiguration("classpath:dynamic-settings-test.xml")
public class SettingEntityRepositoryTest { public class DynamicSettingAndMappingEntityRepositoryTests {
@Autowired @Autowired
private SettingEntityRepository repository; private DynamicSettingAndMappingEntityRepository repository;
@Autowired @Autowired
private ElasticsearchTemplate elasticsearchTemplate; private ElasticsearchTemplate elasticsearchTemplate;
@Before @Before
public void before() { public void before() {
elasticsearchTemplate.deleteIndex(SettingEntity.class); elasticsearchTemplate.deleteIndex(DynamicSettingAndMappingEntity.class);
elasticsearchTemplate.createIndex(SettingEntity.class); elasticsearchTemplate.createIndex(DynamicSettingAndMappingEntity.class);
elasticsearchTemplate.putMapping(SettingEntity.class); elasticsearchTemplate.putMapping(DynamicSettingAndMappingEntity.class);
elasticsearchTemplate.refresh(SettingEntity.class, true); elasticsearchTemplate.refresh(DynamicSettingAndMappingEntity.class, true);
} }
/* /*
@ -66,8 +66,8 @@ public class SettingEntityRepositoryTest {
//delete , create and apply mapping in before method //delete , create and apply mapping in before method
// then // then
assertThat(elasticsearchTemplate.indexExists(SettingEntity.class), is(true)); assertThat(elasticsearchTemplate.indexExists(DynamicSettingAndMappingEntity.class), is(true));
Map map = elasticsearchTemplate.getSetting(SettingEntity.class); Map map = elasticsearchTemplate.getSetting(DynamicSettingAndMappingEntity.class);
assertThat(map.containsKey("index.number_of_replicas"), is(true)); assertThat(map.containsKey("index.number_of_replicas"), is(true));
assertThat(map.containsKey("index.number_of_shards"), is(true)); assertThat(map.containsKey("index.number_of_shards"), is(true));
assertThat(map.containsKey("index.analysis.analyzer.emailAnalyzer.tokenizer"), is(true)); assertThat(map.containsKey("index.analysis.analyzer.emailAnalyzer.tokenizer"), is(true));
@ -82,32 +82,32 @@ public class SettingEntityRepositoryTest {
@Test @Test
public void shouldSearchOnGivenTokenizerUsingGivenDynamicSettingsForGivenIndex() { public void shouldSearchOnGivenTokenizerUsingGivenDynamicSettingsForGivenIndex() {
//given //given
SettingEntity settingEntity1 = new SettingEntity(); DynamicSettingAndMappingEntity dynamicSettingAndMappingEntity1 = new DynamicSettingAndMappingEntity();
settingEntity1.setId(RandomStringUtils.randomNumeric(5)); dynamicSettingAndMappingEntity1.setId(RandomStringUtils.randomNumeric(5));
settingEntity1.setName("test-setting1"); dynamicSettingAndMappingEntity1.setName("test-setting1");
settingEntity1.setEmail("test_setting1@test.com"); dynamicSettingAndMappingEntity1.setEmail("test_setting1@test.com");
repository.save(settingEntity1); repository.save(dynamicSettingAndMappingEntity1);
SettingEntity settingEntity2 = new SettingEntity(); DynamicSettingAndMappingEntity dynamicSettingAndMappingEntity2 = new DynamicSettingAndMappingEntity();
settingEntity2.setId(RandomStringUtils.randomNumeric(5)); dynamicSettingAndMappingEntity2.setId(RandomStringUtils.randomNumeric(5));
settingEntity2.setName("test-setting2"); dynamicSettingAndMappingEntity2.setName("test-setting2");
settingEntity2.setEmail("test_setting2@test.com"); dynamicSettingAndMappingEntity2.setEmail("test_setting2@test.com");
repository.save(settingEntity2); repository.save(dynamicSettingAndMappingEntity2);
//when //when
SearchQuery searchQuery = new NativeSearchQueryBuilder() SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.termQuery("email", settingEntity1.getEmail())).build(); .withQuery(QueryBuilders.termQuery("email", dynamicSettingAndMappingEntity1.getEmail())).build();
long count = elasticsearchTemplate.count(searchQuery, SettingEntity.class); long count = elasticsearchTemplate.count(searchQuery, DynamicSettingAndMappingEntity.class);
List<SettingEntity> entityList = elasticsearchTemplate.queryForList(searchQuery, SettingEntity.class); List<DynamicSettingAndMappingEntity> entityList = elasticsearchTemplate.queryForList(searchQuery, DynamicSettingAndMappingEntity.class);
//then //then
assertThat(count, is(1L)); assertThat(count, is(1L));
assertThat(entityList, is(notNullValue())); assertThat(entityList, is(notNullValue()));
assertThat(entityList.size(), is(1)); assertThat(entityList.size(), is(1));
assertThat(entityList.get(0).getEmail(), is(settingEntity1.getEmail())); assertThat(entityList.get(0).getEmail(), is(dynamicSettingAndMappingEntity1.getEmail()));
} }
@Test @Test
@ -115,7 +115,7 @@ public class SettingEntityRepositoryTest {
//given //given
//delete , create and apply mapping in before method //delete , create and apply mapping in before method
//when //when
Map mapping = elasticsearchTemplate.getMapping(SettingEntity.class); Map mapping = elasticsearchTemplate.getMapping(DynamicSettingAndMappingEntity.class);
//then //then
Map properties = (Map) mapping.get("properties"); Map properties = (Map) mapping.get("properties");
assertThat(mapping, is(notNullValue())); assertThat(mapping, is(notNullValue()));
@ -127,9 +127,9 @@ public class SettingEntityRepositoryTest {
@Test @Test
public void shouldCreateMappingWithSpecifiedMappings() { public void shouldCreateMappingWithSpecifiedMappings() {
//given //given
elasticsearchTemplate.deleteIndex(SettingEntity.class); elasticsearchTemplate.deleteIndex(DynamicSettingAndMappingEntity.class);
elasticsearchTemplate.createIndex(SettingEntity.class); elasticsearchTemplate.createIndex(DynamicSettingAndMappingEntity.class);
elasticsearchTemplate.refresh(SettingEntity.class, true); elasticsearchTemplate.refresh(DynamicSettingAndMappingEntity.class, true);
//when //when
String mappings = "{\n" + String mappings = "{\n" +
" \"test-setting-type\" : {\n" + " \"test-setting-type\" : {\n" +
@ -138,10 +138,26 @@ public class SettingEntityRepositoryTest {
" }\n" + " }\n" +
" }\n" + " }\n" +
"}"; "}";
elasticsearchTemplate.putMapping(SettingEntity.class, mappings); elasticsearchTemplate.putMapping(DynamicSettingAndMappingEntity.class, mappings);
elasticsearchTemplate.refresh(SettingEntity.class, true); elasticsearchTemplate.refresh(DynamicSettingAndMappingEntity.class, true);
//then //then
Map mapping = elasticsearchTemplate.getMapping(SettingEntity.class); Map mapping = elasticsearchTemplate.getMapping(DynamicSettingAndMappingEntity.class);
Map properties = (Map) mapping.get("properties");
assertThat(mapping, is(notNullValue()));
assertThat(properties, is(notNullValue()));
assertThat(((String) ((Map) properties.get("email")).get("type")), is("string"));
assertThat((String) ((Map)properties.get("email")).get("analyzer"), is("emailAnalyzer"));
}
/*
DATAES-86
*/
@Test
public void shouldCreateMappingWithUsingMappingAnnotation() {
//given
//then
Map mapping = elasticsearchTemplate.getMapping(DynamicSettingAndMappingEntity.class);
Map properties = (Map) mapping.get("properties"); Map properties = (Map) mapping.get("properties");
assertThat(mapping, is(notNullValue())); assertThat(mapping, is(notNullValue()));
assertThat(properties, is(notNullValue())); assertThat(properties, is(notNullValue()));

View File

@ -0,0 +1,7 @@
{
"test-setting-type" : {
"properties" : {
"email" : {"type" : "string", "analyzer" : "emailAnalyzer" }
}
}
}