elasticsearch 下面简称为 es/ES
技术版本说明1. springboot .version - 2.5.3
2. jdk .version - 8
3. lombok.version - version - 1.18.10
4. hutool-all.version - 5.6.2
5. spring-boot-starter-data-elasticsearch.version - 延用springboot里的版本(即 2.5.3)
注意: 虽然延用(继承) 2.5.3 但是有三个版本必须移除然后选择自己es对应的版本!
如下三个: (使用你自己装的es的版本,例如我的7.7.0)
elasticsearch-rest-high-level-client - 7.7.0
elasticsearch-rest-client - 7.7.0
elasticsearch - 7.7.0
6. fastjson - version - 1.2.75
7. spring-boot-starter-aop - 延用springboot里的版本(即 2.5.3)
源码地址
gitee地址: https://gitee.com/zjydzyjs/spring-boot-use-case-collection/tree/master/es
为什么选择这个版本的springboot?首先得理解es 6.x 和 7.x 的不同,导致的springboot版本整合不同!
首先,来先跟我一起打开spring-data/elasticsearch官网
版本关系来到 3.1 Version
看到如下图:
因为我的 ES 版本为7.7.0,所以我的springboot 版本需要为 2.4.x以上。
你也应该根据自己的 ES 版本来选择对应的springboot 版本,或根据springboot版本选择对应的 ES 版本。
那么新版本有什么不一样?原文
译文
我在译文那里标了红框,官方说:
弃用TransportClient使用
那么这是为什么呢?
为什么弃用 TransportClient在文档5.1. Transport Client中找到答案
译文:
将TransportClient被弃用Elasticsearch 7的,并会在Elasticsearch 8被移除(见Elasticsearch文档)。TransportClient只要在使用的 Elasticsearch版本中可用,Spring Data Elasticsearch 就会支持它,但自 4.0 版以来已弃用使用它的类。
那官方都说了是 ES 官方放弃了这个 Transport Client ,那我们去看看。
译文:
在 7.0.0 中已弃用。
该TransportClient是赞成不赞成使用的Java的高级REST客户端,将在Elasticsearch 8.0被删除。该迁移指南描述了所有需要迁移的步骤。
ok了,那么我们就可以知道了,在Spring Data Elasticsearch中应该要使用 Java High Level REST Client。
弃用TransportClient后应该用什客户端?然后我们继续在Spring Data Elasticsearch文档中找这个客户端,
发现了文档中的 5.2. High Level REST Client
刚好与Java High Level REST Client 对应上。
yml配置说明 如下图(yml配置):
yml 配置(图)
备注: 我这里只是简单配置,如果需要自定义复杂配置,请自行配置;
为什么这么配置?提示: 我这里配置的是 ElasticsearchRestClientProperties
先找到 ES 对应自动配置;
搜索关键字 elasticsearch 得到下图结果:
我们可以看到红框内容,然后点进黄框(ctrl+鼠标左击)
得到以下内容:
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnClass({ElasticsearchRestTemplate.class})
@AutoConfigureAfter({ElasticsearchRestClientAutoConfiguration.class, ReactiveElasticsearchRestClientAutoConfiguration.class})
@import({baseConfiguration.class, RestClientConfiguration.class, ReactiveRestClientConfiguration.class})
public class ElasticsearchDataAutoConfiguration {
public ElasticsearchDataAutoConfiguration() {
}
}
@ConditionalOnClass({ElasticsearchRestTemplate.class})
解析: @ConditionalOnClass在 本文@ConditionalOnXXXX系列常用注解可以看到解释, 即为: “当前classpath下存在指定类,则实例化当前Bean”。
那么现在的意思就是我们的spring工程中有引入ElasticsearchRestTemplate.class就实例化 ElasticsearchDataAutoConfiguration.class
@AutoConfigureAfter({ElasticsearchRestClientAutoConfiguration.class, ReactiveElasticsearchRestClientAutoConfiguration.class})
解析: 顾名思义, ElasticsearchDataAutoConfiguration.class 加载会在 **{ElasticsearchRestClientAutoConfiguration.class, ReactiveElasticsearchRestClientAutoConfiguration.class}**两个类之后。
@import({baseConfiguration.class, RestClientConfiguration.class, ReactiveRestClientConfiguration.class})
解析: @import可以将类加入 IOC 容器,那么这就意味这交给spring去管理了,
它这里共写了三个类,因为我们是基于rest的高级客户端,所以我们要留意RestClientConfiguration,
其他的配置这里不深入讲述,可以参照官方文档!
OK,刚刚那些内容我都已经简单的讲述了,那么我们现在进去研究一下,yml配置 ,我们先进入 ElasticsearchRestClientProperties.class,顾名思义,它就是配置类!
ElasticsearchRestClientProperties 查看@ConfigurationProperties(
prefix = "spring.elasticsearch.rest"
)
public class ElasticsearchRestClientProperties {
private List uris = new ArrayList(Collections.singletonList("http://localhost:9200"));
private String username;
private String password;
private Duration connectionTimeout = Duration.ofSeconds(1L);
private Duration readTimeout = Duration.ofSeconds(30L);
private final ElasticsearchRestClientProperties.Sniffer sniffer = new ElasticsearchRestClientProperties.Sniffer();
public ElasticsearchRestClientProperties() {
}
public List getUris() {
return this.uris;
}
public void setUris(List uris) {
this.uris = uris;
}
public String getUsername() {
return this.username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return this.password;
}
public void setPassword(String password) {
this.password = password;
}
public Duration getConnectionTimeout() {
return this.connectionTimeout;
}
public void setConnectionTimeout(Duration connectionTimeout) {
this.connectionTimeout = connectionTimeout;
}
public Duration getReadTimeout() {
return this.readTimeout;
}
public void setReadTimeout(Duration readTimeout) {
this.readTimeout = readTimeout;
}
public ElasticsearchRestClientProperties.Sniffer getSniffer() {
return this.sniffer;
}
public static class Sniffer {
private Duration interval = Duration.ofMinutes(5L);
private Duration delayAfterFailure = Duration.ofMinutes(1L);
public Sniffer() {
}
public Duration getInterval() {
return this.interval;
}
public void setInterval(Duration interval) {
this.interval = interval;
}
public Duration getDelayAfterFailure() {
return this.delayAfterFailure;
}
public void setDelayAfterFailure(Duration delayAfterFailure) {
this.delayAfterFailure = delayAfterFailure;
}
}
}
相信大家看到
@ConfigurationProperties(
prefix = “spring.elasticsearch.rest”
)
应该知道我的yml为什么那么配置了吧!
那么yml 为什么怎么配置就完结… 撒花
那么它到底用的是不是 java High Level REST Client接下来回到ElasticsearchRestClientAutoConfiguration再进入RestHighLevelClientConfiguration.class
得到如下代码:
//这一个内部类,省略其他部分
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnMissingBean({RestHighLevelClient.class})
static class RestHighLevelClientConfiguration {
RestHighLevelClientConfiguration() {
}
@Bean
RestHighLevelClient elasticsearchRestHighLevelClient(RestClientBuilder restClientBuilder) {
return new RestHighLevelClient(restClientBuilder);
}
}
OK了,它其实就是 new RestHighLevelClient(restClientBuilder) 交给spring去管理。
所以,没错的,他就是用的 java High Level REST Client。
怎么去 ES 进行操作 1. 继承 ElasticsearchRepository 接口 说明 使用起来就和jpa差不多
实现 继承接口,用例如下:
@Repository public interface DemoElasticsearchRepository extends ElasticsearchRepository测试{ List getByNumber(Integer number); List getByDes(String des); void deleteByDes(String des); } 具体方法命名空间参考官网: https://docs.spring.io/spring-data/elasticsearch/docs/4.2.4/reference/html/#repositories.namespace-reference 下的 附录 A:命名空间参考
在类 {@link com.blacktea.es.EsApplicationDaoTests} 下,有部分例子,可以直接了解一下。
底层 它使用的 ES 客户端是什么?
我们先点击 ElasticsearchRepository,再点击PagingAndSortingRepository,
有一个方法:
Page searchSimilar(T var1, @Nullable String[] var2, Pageable var3);
点击实现 ->
可以看到
public PagesearchSimilar(T entity, @Nullable String[] fields, Pageable pageable) { Assert.notNull(entity, "Cannot search similar records for 'null'."); Assert.notNull(pageable, "'pageable' cannot be 'null'"); MoreLikeThisQuery query = new MoreLikeThisQuery(); query.setId(this.stringIdRepresentation(this.extractIdFromBean(entity))); query.setPageable(pageable); if (fields != null) { query.addFields(fields); } SearchHits searchHits = (SearchHits)this.execute((operations) -> { return operations.search(query, this.entityClass, this.getIndexCoordinates()); }); SearchPage searchPage = SearchHitSupport.searchPageFor(searchHits, pageable); return (Page)SearchHitSupport.unwrapSearchHits(searchPage); }
获取数据的代码如下:
SearchHitssearchHits = (SearchHits)this.execute((operations) -> { return operations.search(query, this.entityClass, this.getIndexCoordinates()); });
点击operations.searc()
进入接口 SearchOperations,
再点击实现类
得到如图
点击 ElasticsearchOperations
得到实现类
其实早在上一步就可以发现了,当前可以用的最终底层实现就是
ElasticsearchRestTemplate.class
底层实现图 底层原理解析public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate {
private static final Logger LOGGER = LoggerFactory.getLogger(ElasticsearchRestTemplate.class);
// ElasticsearchRestTemplate的底层交互ES的客户端是 RestHighLevelClient,
// 说明实际上我们之前的配置都是对的!
// ES 交互的三种方式也是对的,
// 1.继承 ElasticsearchRepository 接口
// 2.使用 ElasticsearchRestTemplate 类
// 3.直接使用 RestHighLevelClient 类
private final RestHighLevelClient client;
private final ElasticsearchExceptionTranslator exceptionTranslator = new ElasticsearchExceptionTranslator();
public ElasticsearchRestTemplate(RestHighLevelClient client) {
Assert.notNull(client, "Client must not be null!");
this.client = client;
this.initialize(this.createElasticsearchConverter());
}
public ElasticsearchRestTemplate(RestHighLevelClient client, ElasticsearchConverter elasticsearchConverter) {
Assert.notNull(client, "Client must not be null!");
this.client = client;
this.initialize(elasticsearchConverter);
}
}
2. 使用ElasticsearchRestTemplate类
说明
有方法1(继承 ElasticsearchRepository 接口) 的锚点 - 底层原理解析,可以知道使用该类其实是对 RestHighLevelClient类执行方法的封装,而继承接口的方式又是对该类的封装,所以你也可以直接使用该类进行直接调用。
3.使用RestHighLevelClient类 说明 既然前面两种都是基于RestHighLevelClient类,进行使用的,那么我也可以直接使用该类进行调用,所以我自己写了个 {@link com.blacktea.es.service.ElasticsearchServiceImpl} 接口服务(工具类)
测试 测试的例子,我大部分都写在了,{@link com.blacktea.es.EsApplicationTests}
ElasticsearchServiceImpl 说明 该类是我自己在学习过程中,参考资料进行编写的,没有经过大数据量的测试,如果需要用于项目中,建议使用方法1(继承 ElasticsearchRepository 接口)
public interface ElasticsearchService@ConditionalOnXXXX系列常用注解{ boolean createdocument(Object var2, String index, String id) throws IOException; T createdocument(Class var1,Object var2,String index,String id) throws IOException; boolean addBatchdocument(Map var,String index) throws IOException; boolean deletedocument(String index, String id) throws IOException; boolean deleteBatchdocument(String index, List ids) throws IOException; long deletedocument(String index, String key, Object value) throws IOException; long deletedocumentByCondition(String index, List conditionDTOS) throws IOException; boolean updatedocument(Object var2, String index, String id) throws IOException; T updatedocument(Class var1, Object var2, String index, String id) throws IOException; long updatedocumentByCondition(Object var2, String index, List conditionDTOS) throws IOException; long updatedocumentByCondition(scriptDto scriptDto, String index, List conditionDTOS) throws IOException; boolean updateBatchdocument(String index, Map params) throws IOException; T getdocument (Class var1, String index, String id) throws IOException; List getListByAndMap(Class var1, String index, Map map) throws IOException; List getListByAndMap(Class var1, String index, Map map ,Map sortOrderMap) throws IOException; List getListByCondition(Class var1, String index, List conditionDos) throws IOException; List getListByCondition(Class var1, String index, ESSearchDto searchDto) throws IOException; Page getPageByCondition(Class var1, String index, ESSearchDto esSearchDto, PageRequest pageRequest) throws IOException; Page getPageFromSizeByCondition(Class var1, String index, ESSearchDto esSearchDto, RequestFromSizePage requestFromSizePage) throws IOException; Long count(String idnex, QueryBuilder query) throws IOException; }
@ConditionalOnBean:当给定的在bean存在时,则实例化当前Bean
@ConditionalOnMissingBean:当给定的在bean不存在时,则实例化当前Bean
@ConditionalOnClass:当前classpath下存在指定类,则实例化当前Bean
@ConditionalOnMissingClass:当前classpath下不存在指定类,则实例化当前Bean
@ConditionalOnexpression:依赖于SpEL表达式值的条件元素的配置注释,条件为true,则实例化当前bean。如:@ConditionalOnexpression("${redis.enabled}==1&&${redis.cluster.enabled:true}&&'${redis.name}'.equals('myredis')")
@ConditionalOnWebApplication:当Spring为web服务时,才使注解的类生效;通常是配置类;
@ConditionalOnProperty:通过@ConditionalOnProperty控制配置类是否生效,可以将配置与代码进行分离,实现了更好的控制配置。如:@ConditionalOnProperty(prefix = "filter",name = "loginFilter",havingValue = "true"),配置文件代码为filter.loginFilter=true。@ConditionalOnProperty 实现是通过 havingValue 与配置文件中的值对比,返回为true则配置类生效,反之失效。
@ConditionalOnResource:仅当指定的资源在类路径上时才生效。如:@ConditionalOnResource(resources="classpath:jdbc.properties")
感谢
spring-boot 官网
es 官网
https://blog.csdn.net/qq_33375499/article/details/106711248
https://www.jianshu.com/p/733e7e1e4de5
b 站 狂神说java



