1 使用场景

在一些项目中,需要在程序中根据条件,动态生成es的index,达到整理数据的目的。
例如,大数据量的系统日志,需要按天分index,这时就需要动态生成Index。

2 Spel动态生成Index

这里使用spring-data-elasticsearchElasticsearchRestTemplate操作es,版本为3.2.0。

<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-elasticsearch</artifactId>
    <version>3.2.0.RELEASE</version>
</dependency>

在使用@Document注解标识POJO对象时,可以指定静态IndexName。

@Document(indexName = "indexName", type = "logger")

但是要如何动态生成index呢?这里使用Spel

Spel的全称是Spring Expression Language,是spring的一种表达式语言,功能很强大,官方网址

使用Spel可以在注解中通过表达式调用Bean的方法来给参数赋值。

所以动态生成的思路就是创建一个index的生成器,在@Ducument中调用生成器方法给indexName属性赋值。

生成器实例如下:

@Component("indexNameGenerator")
public class IndexNameGenerator {
    public String commonIndex() {
        //根据日期生成index
        String date = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        return "collectlog_" + date;
    }
}

Document类的实例如下:

@NoArgsConstructor
@Data
@Document(indexName = "#{@indexNameGenerator.commonIndex()}", type = "logger")
public class ESDocument {
    @Field(analyzer = "ik_max_word", searchAnalyzer = "ik_max_word")
    private String content;
    private String cluster;
    private long date = LocalDateTime.now().toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
    private String path;
    private String ip;
    private String level;
}

可以看到,在@Document注解中,调用了indexNameGenerator.commonIndex(),方法获取每天的Index。
该方法会在每次新增数据的时候被调用。

3 一些注意事项

要注意的是Spel使用context获取对应的Bean Resolver,如果项目运行中报异常,

org.springframework.expression.spel.SpelEvaluationException: 
EL1057E: No bean resolver registered in the context to resolve access to bean 'indexNameGenerator'

这个原因主要是Spel中使用的spring context有问题造成的,可以断点到,SpelExpression#getValue方法中调试问题。

org.springframework.expression.spel.standard.SpelExpression#getValue(org.springframework.expression.EvaluationContext, java.lang.Class<T>) 

在ES使用时,如果是手动创建的ElasticsearchRestTemplate,在创建实例时一定要设置ElasticsearchConverter,不然会报上述异常。

ElasticsearchConverter可以使用springboot autoconfig中生成的Bean,里面已注入正确的ApplicationContext,实例如下:

@EnableConfigurationProperties(ESProperties.class)
@Service("elasticSearchHandlerFactory")
public class ElasticSearchHandlerFactory {
    @Resource
    ESProperties esProperties;

    /**
     * 已经在elastic autoconfig 中创建,可以直接使用
     */
    @Resource
    ElasticsearchConverter elasticsearchConverter;

    public ElasticsearchRestTemplate getHandler() {
        ESProperties.DbConfig dbConfig = esProperties.getDbList().get("c1");
        final ClientConfiguration configuration = ClientConfiguration.builder()
                .connectedTo(dbConfig.getHostAndPort())
                .withBasicAuth(dbConfig.getUsername(), dbConfig.getPassword())
                .build();
        RestHighLevelClient client = RestClients.create(configuration).rest();
        return new ElasticsearchRestTemplate(client, elasticsearchConverter);
    }
}

以上内容属个人学习总结,如有不当之处,欢迎在评论中指正


dothetrick
349 声望6 粉丝

摸爬滚打中的程序员