当前位置:   article > 正文

【SpringBoot】整合Elasticsearch 操作索引及文档_esclient springboot

esclient springboot

官网操作文档:Elasticsearch Clients | Elastic      

         踩坑太多了。。。这里表明一下Spring Boot2.4以上版本可能会出现问题,所以我降到了2.2.1.RELEASE。对于现在2023年6月而言,Es版本已经到了8.8,而SpringBoot版本已经到了3.x版本。如果是高版本的Boot在配置类的时候会发现RestHighLevelClient已过时。从官网也可以看的出来RestHighLevelClient已过时。所以这篇博文中不会用到关于RestHighLevelClient的Api。

        此篇博文的对应版本关系:Elasticsearch 8.2.0 + Spring Boot 2.7.5。在进入到下面的案例,我需要在这之前先介绍RestClient、RestHighLevelClient、RestClientTransport、ElasticsearchClient。

RestClient

        这个类主要是用作于与服务端IP以及端口的配置,在其的builder()方法可以设置登陆权限的账号密码、连接时长等等。总而言之就是服务端配置

RestClientTransport

        这是Jackson映射器创建传输。建立客户端与服务端之间的连接传输数据。这是在创建ElasticsearchClient需要的参数,而创建RestClientTransport就需要上面创建的RestClient。

ElasticsearchClient

        这个就是Elasticsearch的客户端。调用Elasticsearch语法所用到的类,其就需要传入上面介绍的RestClientTransport。

引入依赖

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
  4. </dependency>
  5. <!-- 高版本还需引入此依赖 -->
  6. <dependency>
  7. <groupId>jakarta.json</groupId>
  8. <artifactId>jakarta.json-api</artifactId>
  9. <version>2.0.0</version>
  10. </dependency>

修改yml

        需要注意的是账号和密码可以不需要,看自己的Elasticsearch是否有配置账号密码。具体对Elasticsearch的登陆操作可以看:中偏下的位置就是对账号密码的设置。【Linux】Docker部署镜像环境 (持续更新ing)_小白的救赎的博客-CSDN博客

  1. server:
  2. port: 8080
  3. elasticsearch:
  4. hostAndPort: 192.168.217.128:9200 # 低版本使用的
  5. ip: 192.168.217.128
  6. port: 9200
  7. username: elastic
  8. password: 123456
  9. connectionTimeout: 1000
  10. socketTimeout: 30000

配置类    

        这里演示两种情况的配置:第一个代码块是SpringBoot2.4以下 + 7.x版本Elasticsearch的配置。第二个代码块是Spring2.4以上 + 8.x版本Elasticsearch的配置。

  1. @Configuration
  2. public class ElasticConfig extends AbstractElasticsearchConfiguration {
  3. @Value("${elasticsearch.hostAndPort}")
  4. private String hostAndPort;
  5. @Value("${elasticsearch.username}")
  6. private String username;
  7. @Value("${elasticsearch.password}")
  8. private String password;
  9. @Value("${elasticsearch.connectionTimeout}")
  10. private String connectTimeout;
  11. @Value("${elasticsearch.socketTimeout}")
  12. private String socketTimeout;
  13. /**
  14. * create Elasticsearch client
  15. * @return RestHighLevelClient
  16. */
  17. @Bean
  18. public RestHighLevelClient elasticsearchClient() {
  19. final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
  20. credentialsProvider.setCredentials(AuthScope.ANY,new UsernamePasswordCredentials(username, password));
  21. ClientConfiguration clientConfiguration = ClientConfiguration.builder()
  22. .connectedTo(hostAndPort)
  23. .withConnectTimeout(Long.parseLong(connectTimeout))
  24. .withSocketTimeout(Long.parseLong(socketTimeout))
  25. .withBasicAuth(username, password)
  26. .build();
  27. return RestClients.create(clientConfiguration).rest();
  28. }
  29. /**
  30. * 将连接传入 Elasticsearch在 Spring Boot的模板类中
  31. * @return 返回 Es的模板类
  32. */
  33. @Bean
  34. public ElasticsearchRestTemplate elasticsearchRestTemplate() {
  35. return new ElasticsearchRestTemplate(elasticsearchClient());
  36. }
  37. }
  1. @Configuration
  2. public class ElasticConfig {
  3. @Value("${elasticsearch.ip}")
  4. private String ip;
  5. @Value("${elasticsearch.port}")
  6. private String port;
  7. @Value("${elasticsearch.username}")
  8. private String username;
  9. @Value("${elasticsearch.password}")
  10. private String password;
  11. @Value("${elasticsearch.connectionTimeout}")
  12. private String connectTimeout;
  13. @Value("${elasticsearch.socketTimeout}")
  14. private String socketTimeout;
  15. /**
  16. * create Elasticsearch client
  17. * @return RestHighLevelClient
  18. */
  19. @Bean
  20. public ElasticsearchClient elasticsearchClient() {
  21. final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
  22. credentialsProvider.setCredentials(AuthScope.ANY,new UsernamePasswordCredentials(username, password));
  23. RestClient restClient = RestClient.builder(
  24. new HttpHost(ip, Integer.parseInt(port)))
  25. .setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider))
  26. .setRequestConfigCallback(new RestClientBuilder.RequestConfigCallback() {
  27. @Override
  28. public RequestConfig.Builder customizeRequestConfig(RequestConfig.Builder builder) {
  29. return builder.setConnectTimeout(Integer.parseInt(connectTimeout)).setSocketTimeout(Integer.parseInt(socketTimeout));
  30. }
  31. }).build();
  32. ElasticsearchTransport transport
  33. = new RestClientTransport(restClient, new JacksonJsonpMapper());
  34. return new ElasticsearchClient(transport);
  35. }
  36. }

控制层

        这里为了方便快速入门,就把所有业务代码都放在控制层中了。这篇博文主要是对索引进行操作,所以说获取到ElasticsearchClient后会调用indices()方法,这个方法就是操作索引的方法。次代码块是展示变量以及类注解。后面逐一暂时各个测试代码块Api以及返回结果。

  1. @RestController
  2. @RequestMapping("/es")
  3. @Slf4j
  4. public class EsController{
  5. @Autowired
  6. private ElasticConfig elasticConfig;
  7. }

创建索引

  1. /**
  2. * create index
  3. * @return is success?
  4. */
  5. @PutMapping("/createIndex")
  6. public boolean createIndex() throws IOException {
  7. CreateIndexRequest indexRequest
  8. = new CreateIndexRequest.Builder().index("user").build();
  9. CreateIndexResponse indexResponse
  10. = elasticConfig.esClient().indices().create(indexRequest);
  11. boolean isSuccess = indexResponse.acknowledged();
  12. if(isSuccess) {
  13. log.info("创建索引成功");
  14. } else {
  15. log.info("创建索引失败");
  16. }
  17. return isSuccess;
  18. }

查询单个索引数据

  1. /**
  2. * get one index data by id
  3. */
  4. @GetMapping("/getIndex")
  5. public void getIndex() throws IOException {
  6. GetResponse<User> response = elasticConfig.esClient().get(g -> g
  7. .index("user")
  8. .id("1000")
  9. ,User.class
  10. );
  11. if(response.found()) {
  12. log.info("此用户的姓名为,{}",response.source().getUsername());
  13. } else {
  14. log.info("未查询到此用户");
  15. }
  16. }

删除索引

        这里我测试删除索引成功后又把索引添加了回去。为了后面的其它操作做准备。

  1. /**
  2. * delete one index
  3. */
  4. @DeleteMapping("/deleteIndex")
  5. public boolean deleteIndex() throws IOException {
  6. DeleteIndexRequest indexRequest
  7. = new DeleteIndexRequest.Builder().index("user").build();
  8. DeleteIndexResponse deleteResponse
  9. = elasticConfig.esClient().indices().delete(indexRequest);
  10. boolean isSuccess = deleteResponse.acknowledged();
  11. if(isSuccess) {
  12. log.info("删除索引成功");
  13. } else {
  14. log.info("删除索引失败");
  15. }
  16. return isSuccess;
  17. }

增加索引内容

        这里我新增了个实体类,方便添加到索引内容中。这里大概有四种方式可以创建,这里我演示了三种方式,第四种是使用到了ElasticsearchAsyncClient ,这是Elastic异步客户端。

  1. @Data
  2. @AllArgsConstructor
  3. @NoArgsConstructor
  4. public class User {
  5. private String username;
  6. private String sex;
  7. private Integer age;
  8. }
  1. /**
  2. * 向索引内容插入数据
  3. */
  4. @PostMapping("/insertIndexData")
  5. public void insertIndexData() throws IOException {
  6. User user = new User("zhangSan","男",18);
  7. /*
  8. 第一种方式:使用DSL语法创建对象
  9. IndexRequest<User> indexRequest = IndexRequest.of(i -> i
  10. .index("user")
  11. .id("1000")
  12. .document(user)
  13. IndexResponse indexResponse = elasticConfig.esClient().index(indexRequest.build());
  14. );
  15. */
  16. /*
  17. 第二种方式:使用Elasticsearch客户端上配置的对象映射器映射到JSON。
  18. IndexResponse indexResponse = elasticConfig.esClient().index(i -> i
  19. .index("user")
  20. .id("1000")
  21. .document(user)
  22. );
  23. */
  24. // 第三种方式:使用构造器模式
  25. IndexRequest.Builder<User> indexRequest = new IndexRequest.Builder<>();
  26. indexRequest.index("user");
  27. indexRequest.id("1000");
  28. indexRequest.document(user);
  29. IndexResponse indexResponse = elasticConfig.esClient().index(indexRequest.build());
  30. log.info("index,{}",indexResponse.index());
  31. log.info("id,{}",indexResponse.id());
  32. log.info("version,{}",indexResponse.version());
  33. }

批量添加索引数据

        BulkRequest包含一组操作,每个操作都是具有多个变体的类型。为了创建这个请求,可以方便地将构建器对象用于主请求,并将流利的DSL用于每个操作。下面的示例显示了如何为列表或应用程序对象编制索引。

        operations是BulkOperation的生成器,BulkOperation是一种变体类型。此类型具有索引创建更新删除变体。

  1. /**
  2. * 批量插入索引数据
  3. */
  4. @PostMapping("/batchInsertIndex")
  5. public void batchInsertIndex() throws IOException {
  6. // 将需要批量添加的数据放到List中
  7. List<User> list = new ArrayList<>();
  8. list.add(new User("liSi","女",20));
  9. list.add(new User("wangWu","男",22));
  10. // 使用BulkRequest的构造器
  11. BulkRequest.Builder request = new BulkRequest.Builder();
  12. for(User user : list) {
  13. request.operations(l -> l
  14. .index(i -> i
  15. .index("user")
  16. .document(user)
  17. )
  18. );
  19. }
  20. BulkResponse response = elasticConfig.esClient().bulk(request.build());
  21. if(response.errors()) {
  22. log.info("批量插入报错");
  23. } else {
  24. log.info("批量插入成功");
  25. }
  26. }

批量删除索引数据

  1. /**
  2. * 批量删除索引数据
  3. */
  4. @DeleteMapping("/batchDeleteIndex")
  5. public void batchDeleteIndex() throws IOException {
  6. BulkRequest.Builder request = new BulkRequest.Builder();
  7. // 根据id做到删除索引的数据
  8. request.operations(l -> l
  9. .delete(i -> i
  10. .index("user")
  11. .id("vGK5sogBM87kk5Mw8V0P")
  12. )
  13. );
  14. request.operations(l -> l
  15. .delete(i -> i
  16. .index("user")
  17. .id("u2K5sogBM87kk5Mw8V0P")
  18. )
  19. );
  20. BulkResponse response = elasticConfig.esClient().bulk(request.build());
  21. if(response.errors()) {
  22. log.info("批量删除报错");
  23. } else {
  24. log.info("批量删除成功");
  25. }
  26. }

          这里批量删除接口测试完后,我又批量添加了几行数据,方便下面方法的测试。

  1. // 以下就是我添加的数据
  2. list.add(new User("liSi","女",20));
  3. list.add(new User("wangWu","男",22));
  4. list.add(new User("zhaoLiu","男",20));
  5. list.add(new User("xiaoQi","女",21));

简单查询/单条件

        可以组合多种类型的搜索查询。我们将从简单的文本匹配查询开始。单条件准确查询主要用到的关键字是term。而模糊查询就需要用到match。而match这里就不演示了。

  1. /**
  2. * 单条件查询
  3. */
  4. @GetMapping("/search")
  5. public void search() throws IOException {
  6. SearchResponse<User> response = elasticConfig.esClient().search(s -> s
  7. .index("user")
  8. .query(q -> q
  9. .term(e -> e
  10. .field("age")
  11. .value("20")
  12. )
  13. ), User.class
  14. );
  15. // 获取查询后的命中条数:其中包括 TotalHitsRelation 以及 total
  16. TotalHits total = response.hits().total();
  17. boolean isExactResult = total.relation() == TotalHitsRelation.Eq;
  18. if (isExactResult) {
  19. log.info("There are " + total.value() + " results");
  20. } else {
  21. log.info("There are more than " + total.value() + " results");
  22. }
  23. // 解析查询到的所有信息
  24. List<Hit<User>> hits = response.hits().hits();
  25. for(Hit<User> hit : hits) {
  26. log.info("id,{}", hit.id());
  27. }
  28. }

多条件查询 / 范围查询

        Elasticsearch允许将单个查询组合起来,以构建更复杂的搜索请求。当前数据有五条,为了更好的多条件查询,我又增加了5条数据。多条件查询用到的关键字主要就是bool

  1. // 起初的5条数据
  2. list.add(new User("zhangSan","男",18));
  3. list.add(new User("liSi","女",20));
  4. list.add(new User("wangWu","男",22));
  5. list.add(new User("zhaoLiu","男",20));
  6. list.add(new User("xiaoQi","女",21));
  7. // 以下就是我添加的数据
  8. list.add(new User("zhangSan","男",20));
  9. list.add(new User("zhangSan","男",21));
  10. list.add(new User("zhangSan","男",22));
  11. list.add(new User("zhangSan","男",23));
  12. list.add(new User("zhangSan","男",24));
  1. /**
  2. * 多条件查询
  3. */
  4. @GetMapping("/batchSearch")
  5. public void batchSearch() throws IOException {
  6. // 查询性别
  7. Query sex = MatchQuery.of(m -> m
  8. .field("sex")
  9. .query("男")
  10. )._toQuery();
  11. // 查询年龄区间
  12. Query age = RangeQuery.of(r -> r
  13. .field("age")
  14. .lte(JsonData.of(20))
  15. .gte(JsonData.of(18))
  16. )._toQuery();
  17. // 结合性别和年龄区间查询来搜索用户索引
  18. SearchResponse<User> response = elasticConfig.esClient().search(s -> s
  19. .index("user")
  20. .query(q -> q
  21. .bool(b -> b
  22. .must(sex)
  23. .must(age)
  24. )
  25. ),User.class
  26. );
  27. // 获取查询后的命中条数:其中包括 TotalHitsRelation 以及 total
  28. TotalHits total = response.hits().total();
  29. boolean isExactResult = total.relation() == TotalHitsRelation.Eq;
  30. if (isExactResult) {
  31. log.info("There are " + total.value() + " results");
  32. } else {
  33. log.info("There are more than " + total.value() + " results");
  34. }
  35. // 解析查询到的所有信息
  36. List<Hit<User>> hits = response.hits().hits();
  37. for(Hit<User> hit : hits) {
  38. log.info("id,{}", hit.id());
  39. }
  40. }

分页查询

        主要就是Elasticsearch语法中的from与size表示:当前页的开始索引处以及每页条数。

  1. /**
  2. * 分页查询
  3. */
  4. @GetMapping("/searchByPage")
  5. public void searchByPage() throws IOException {
  6. // 假设每页3条数据 那么查询第二页的参数就是:开始索引处为(2 - 1) * 3 = 3 以及 每页条数3
  7. SearchResponse<User> response = elasticConfig.esClient().search(b -> b
  8. .index("user")
  9. .from(3)
  10. .size(3)
  11. ,User.class
  12. );
  13. log.info("查询到的总条数为,{}",response.hits().total().value());
  14. List<Hit<User>> hits = response.hits().hits();
  15. for(Hit<User> hit : hits) {
  16. log.info("查询到的id,{}", hit.id());
  17. }
  18. }

查询所有索引数据

  1. /**
  2. * get all index data
  3. */
  4. @GetMapping("/getAllIndex")
  5. public void getAllIndex() throws IOException {
  6. SearchResponse<User> response = elasticConfig.esClient().search(s -> s
  7. .index("user")
  8. ,User.class);
  9. // 解析查询到的所有信息
  10. List<Hit<User>> hits = response.hits().hits();
  11. for(Hit<User> hit : hits) {
  12. log.info(String.valueOf(hit.source()));
  13. }
  14. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/481083
推荐阅读
相关标签
  

闽ICP备14008679号