1 使用场景
在一些项目中,需要在程序中根据条件,动态生成es的index,达到整理数据的目的。
例如,大数据量的系统日志,需要按天分index,这时就需要动态生成Index。
2 Spel动态生成Index
这里使用spring-data-elasticsearch
的ElasticsearchRestTemplate
操作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);
}
}
以上内容属个人学习总结,如有不当之处,欢迎在评论中指正
网友评论