springboot使用elasticsearch報No property index found for type錯誤

1、前提:項目以前使用springboot+spring-data-mongodb。如今須要加入elasticsearch作搜索引擎,這樣mongo和elasticsearch共存了。java

 

2、報錯信息:mysql

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'TTSAudioInfoEsRepository': Invocation of init method failed; nested exception is org.springframework.data.mapping.PropertyReferenceException: No property index found for type TTSAudioInfo!
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1578)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:545)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1082)
    at org.springframework.data.repository.support.Repositories.cacheRepositoryFactory(Repositories.java:95)
    at org.springframework.data.repository.support.Repositories.populateRepositoryFactoryInformation(Repositories.java:88)
    at org.springframework.data.repository.support.Repositories.<init>(Repositories.java:81)
    at org.springframework.data.repository.support.DomainClassConverter.setApplicationContext(DomainClassConverter.java:98)
    at org.springframework.data.web.config.SpringDataWebConfiguration.addFormatters(SpringDataWebConfiguration.java:87)
    at org.springframework.web.servlet.config.annotation.WebMvcConfigurerComposite.addFormatters(WebMvcConfigurerComposite.java:49)
    at org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration.addFormatters(DelegatingWebMvcConfiguration.java:117)
    at org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport.mvcConversionService(WebMvcConfigurationSupport.java:542)
    at org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$EnableWebMvcConfiguration$$EnhancerBySpringCGLIB$$f6948e02.CGLIB$mvcConversionService$45(<generated>)
    at org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$EnableWebMvcConfiguration$$EnhancerBySpringCGLIB$$f6948e02$$FastClassBySpringCGLIB$$43c05aaf.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:356)
    at org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$EnableWebMvcConfiguration$$EnhancerBySpringCGLIB$$f6948e02.mvcConversionService(<generated>)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162)
    ... 73 common frames omitted
Caused by: org.springframework.data.mapping.PropertyReferenceException: No property index found for type TTSAudioInfo!
    at org.springframework.data.mapping.PropertyPath.<init>(PropertyPath.java:77)
    at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:329)
    at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:309)
    at org.springframework.data.mapping.PropertyPath.from(PropertyPath.java:272)
    at org.springframework.data.mapping.PropertyPath.from(PropertyPath.java:243)
    at org.springframework.data.repository.query.parser.Part.<init>(Part.java:76)
    at org.springframework.data.repository.query.parser.PartTree$OrPart.<init>(PartTree.java:235)
    at org.springframework.data.repository.query.parser.PartTree$Predicate.buildTree(PartTree.java:373)
    at org.springframework.data.repository.query.parser.PartTree$Predicate.<init>(PartTree.java:353)
    at org.springframework.data.repository.query.parser.PartTree.<init>(PartTree.java:84)
    at org.springframework.data.mongodb.repository.query.PartTreeMongoQuery.<init>(PartTreeMongoQuery.java:60)
    at org.springframework.data.mongodb.repository.support.MongoRepositoryFactory$MongoQueryLookupStrategy.resolveQuery(MongoRepositoryFactory.java:168)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.<init>(RepositoryFactorySupport.java:435)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:220)
    at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.initAndReturn(RepositoryFactoryBeanSupport.java:266)
    at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertiesSet(RepositoryFactoryBeanSupport.java:252)
    at org.springframework.data.mongodb.repository.support.MongoRepositoryFactoryBean.afterPropertiesSet(MongoRepositoryFactoryBean.java:108)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1637)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1574)
    ... 98 common frames omitted

 

3、錯誤分析:web

  一、TTSAudioInfo類是pojo類,既是mongo的document也是elasticsearch的documentredis

/**
 * @author: george
 * @date: 2018/6/26-16-39
 * @description:
 */
@org.springframework.data.elasticsearch.annotations.Document(indexName = "tts_audio_info", type = "tts_audio_info") //spring-data-elasticsearch註解
@org.springframework.data.mongodb.core.mapping.Document(collection = "TTSAudioInfo") //spring-data-mongodb註解
@Data  //lombok註解
public class TTSAudioInfo extends BaseModel {
    private static final long serialVersionUID = 1L;
    public static final String FIELD_QUESTION = "question";
    public static final String FIELD_ANSWER = "answer";
    public static final String FIELD_FILE_URI = "fileUri";
    public static final String FIELD_FILE_PATH = "filePath";

    private String question;
    @Field(type = FieldType.String, index = FieldIndex.analyzed)
    private String answer;
    private String fileUri;
    private String filePath;

    public TTSAudioInfo() {
    }
}

  二、而後是elasticsearch的repository接口,繼承的是ElasticsearchRepositoryspring

import ai.deepbrain.admin.domain.TTSAudioInfo;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;

/**
 * @author: george
 * @date: 2018/6/26-17-05
 * @description:
 */
public interface TTSAudioInfoEsRepository extends ElasticsearchRepository<TTSAudioInfo, String> {
}

  

分析:spring-data-mongo和spring-data-elasticsearch都屬於spring的spring-data項目,提供各類數據庫數據訪問的封裝(mongo、redis、oracle、mysql、jpa、elasticsearch等等等等)。他們封裝的格式基本同樣;sql

而在本文的錯誤中,咱們使用了mongodb和elasticsearch,咱們在查看TTSAudioInfoEsRepository繼承的ElasticsearchCrudRepository的繼承關係後得知,他和MongoRepository都繼承spring-data-commons的PagingAndSortingRepository。mongodb

(這裏還有一點就是全部repository接口寫在同一包下)因此致使了在mongodb掃描repository的時候也會掃描elasticsearch的repository,spring-data-mongodb會試圖代理TTSAudioInfoEsRepository ,可是發現TTSAudioInfoEsRepository 使用的TTSAudioInfo中沒有index屬性,從而報錯No property index found for type。數據庫

stackoverflow中有一篇相似的錯誤文章:https://stackoverflow.com/questions/36252099/no-property-index-found-for-type-user。springboot

4、解決辦法:mvc

既然知道錯誤的緣由了,那解決起來就相對簡單了。無非就是讓spring-data-mongo掃描mongodb的repository,spring-data-elasticsearch掃描elasticsearch的repository。

一、把不一樣類型的repository分別放在不一樣包下,而後在配置的地方指定掃描位置

  mongodb的配置類

@Configuration
@Import(value = MongoAutoConfiguration.class)
@EnableMongoRepositories(basePackages = "com.test.mongodb")
public class MongoConfiguration extends AbstractMongoConfiguration {

    @Autowired
    private MongoProperties mongoProperties;

    @Override
    protected String getDatabaseName() {
        return mongoProperties.getDatabase();
    }

    @Override
    public Mongo mongo() throws Exception {
        MongoClientURI clientURI = new MongoClientURI(mongoProperties.getUri());
        return new MongoClient(clientURI);
    }

    @Bean
    public ValidatingMongoEventListener validatingMongoEventListener() {
        return new ValidatingMongoEventListener(validator());
    }

    @Bean
    public LocalValidatorFactoryBean validator() {
        return new LocalValidatorFactoryBean();
    }

    @Bean
    public MappingMongoConverter mappingMongoConverter() throws Exception {
        DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory());
        MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, mongoMappingContext());
        // remove _class field
        converter.setTypeMapper(new DefaultMongoTypeMapper(null));
        converter.setCustomConversions(customConversions());
        return converter;
    }
}

  elasticsearch的配置類

@Configuration
@EnableElasticsearchRepositories(basePackages = "com.test.elasticsearch")
public class ElasticsearchConfiguration {

    @Bean
    public ElasticsearchTemplate elasticsearchTemplate(Client client,
                                                       Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder) {
        MappingElasticsearchConverter converter = new MappingElasticsearchConverter(
                new SimpleElasticsearchMappingContext());
        DefaultResultMapper mapper = new DefaultResultMapper(converter.getMappingContext(),
                new CustomEntityMapper(jackson2ObjectMapperBuilder.createXmlMapper(false).build()));
        return new ElasticsearchTemplate(client, converter, mapper);
    }

    public class CustomEntityMapper implements EntityMapper {

        private ObjectMapper objectMapper;

        public CustomEntityMapper(ObjectMapper objectMapper) {
            this.objectMapper = objectMapper;
            objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
        }

        @Override
        public String mapToString(Object object) throws IOException {
            return objectMapper.writeValueAsString(object);
        }

        @Override
        public <T> T mapToObject(String source, Class<T> clazz) throws IOException {
            return objectMapper.readValue(source, clazz);
        }
    }
}

二、在配置enabled註解的時候添加includeFilters

mongo:

@Configuration
@Import(value = MongoAutoConfiguration.class)
@EnableMongoRepositories(basePackages = "com.test",includeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = MongoRepository.class))
public class MongoConfiguration extends AbstractMongoConfiguration {

elasticsearch:

@Configuration
@EnableElasticsearchRepositories(basePackages = "com.test",includeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = ElasticsearchRepository.class))
public class ElasticsearchConfiguration {
相關文章
相關標籤/搜索