Springboot集成Elasticsearch High Level REST Client实现增删改查实战

获取源码🚩

需要完整代码资料,请一键三连后评论区留下邮箱,安排发送!!!🤖

什么是High Level REST Client?

Elasticsearch 的 High Level REST Client 是一个用于与 Elasticsearch 进行交互的 Java 客户端库,它提供了比低级别的 REST 客户端更高级别的抽象。High Level REST Client 使用了 OkHttp 库作为底层的 HTTP 客户端,并且提供了自动重试、连接管理和错误处理等功能。它允许开发人员以面向对象的方式构建请求和解析响应,从而简化了与 Elasticsearch 的 REST API 的交互过程。

✔️优点:

  • 易用性:High Level REST Client 提供了丰富的 API,使得常见的 Elasticsearch 操作变得简单直观。
  • 自动重试和错误处理:它能够处理网络故障和重试失败的请求,减少了开发人员需要处理的异常情况。
  • 封装了 JSON 处理:它自动处理了请求和响应的序列化和反序列化,使得开发人员无需直接处理 JSON 字符串。
  • 连接管理:它提供了连接池管理,可以复用连接,提高性能。

❌缺点:

  • 依赖较大:由于其提供了丰富的功能,因此其依赖库和整体大小相对较大。
  • 性能开销:高层面的抽象可能会引入额外的性能开销,尤其是在高并发场景下。

High Level REST Client的核心

索引管理

CreateIndexRequest 和 CreateIndexResponse:用于创建一个新的索引。

GetIndexRequest 和 GetIndexResponse:用于获取索引的元数据。

DeleteIndexRequest 和 DeleteIndexResponse:用于删除一个索引。

文档操作

IndexRequest 和 IndexResponse:用于索引(或更新)一个文档。

UpdateRequest 和 UpdateResponse:用于更新已存在的文档。

GetRequest 和 GetResponse:用于检索一个文档。

DeleteRequest 和 DeleteResponse:用于删除一个文档。

搜索和聚合

SearchRequest 和 SearchResponse:用于执行搜索查询和聚合。

CountRequest 和 CountResponse:用于计算满足给定条件的文档数量。

ScrollRequest 和 ScrollResponse:用于滚动搜索结果,获取大量数据。

批量操作

BulkRequest 和 BulkResponse:用于执行批量操作,如批量索引、更新或删除多个文档。

request.source()等于DSL中query{}

Sprinboot集成High Level REST Client

创建索引

可以使用postman或者谷歌浏览器插件Elasticvue 创建:

json 复制代码
{
  "article_doc": {
    "aliases": {},
    "mappings": {
      "properties": {
        "author": {
          "type": "keyword"
        },
        "category": {
          "type": "keyword"
        },
        "content": {
          "type": "text",
          "analyzer": "ik_max_word",
          "search_analyzer": "ik_smart"
        },
        "createTime": {
          "type": "date",
          "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
        },
        "id": {
          "type": "keyword"
        },
        "readCount": {
          "type": "integer"
        },
        "title": {
          "type": "text",
          "analyzer": "ik_max_word",
          "search_analyzer": "ik_smart"
        }
      }
    },
    "settings": {
      "index": {
        "routing": {
          "allocation": {
            "include": {
              "_tier_preference": "data_content"
            }
          }
        },
        "number_of_shards": "1",
        "provided_name": "article_doc",
        "creation_date": "1721725035763",
        "number_of_replicas": "1",
        "uuid": "r55CXBCLSxO8aFWPtL1Niw",
        "version": {
          "created": "7130299"
        }
      }
    }
  }
}

添加pom依赖

xml 复制代码
<dependency>
	<groupId>org.elasticsearch</groupId>
	<artifactId>elasticsearch</artifactId>
	<version>7.14.0</version>
</dependency>

<dependency>
	<groupId> org.elasticsearch.client</groupId>
	<artifactId>elasticsearch-rest-high-level-client</artifactId>
	<version>7.14.0</version>
</dependency>

编写配置类

java 复制代码
@Configuration
public class ElasticsearchConfig {
    @Value("${elasticsearch.host}")
    private String host;

    @Value("${elasticsearch.port}")
    private int port;

    /*@Value("${elasticsearch.username}")
    private String userName;

    @Value("${elasticsearch.password}")
    private String password;*/

    /**
     * 如果@Bean没有指定bean的名称,那么这个bean的名称就是方法名
     */
    @Bean
    public RestHighLevelClient restHighLevelClient() {
        return new RestHighLevelClient(
                RestClient.builder(
                        new HttpHost(host, port, "http")
                )
        );
    }


}

编写模型

java 复制代码
@Data
@TableName("tb_article")
public class Article {
    private String id;
    private String author;
    private String category;
    private String title;
    private String content;
    private Integer readCount;
    @JSONField(format = "yyyy-MM-dd HH:mm:ss")
    private Date createTime;
}

编写接口服务类

获取索引结构接口

http://localhost:9000/articleDoc/getMapping

数据同步接口

java 复制代码
/**
     *  批量从数据库导入
     * @throws IOException
     */
    public void importFromDb() throws IOException {
        List<Article> articleList = articleService.list();
        BulkRequest bulkRequest = new BulkRequest();
        for (Article doc : articleList) {
            String data = JSON.toJSONString(doc);
            IndexRequest indexRequest = new IndexRequest(Constant.ARTICLE_INDEX);
            indexRequest.id(doc.getId()).source(data, XContentType.JSON);
            bulkRequest.add(indexRequest);
        }
        BulkResponse response = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
        log.info("批量导入状态:{}, 耗时{}", response.status(), response.getTook().getSeconds());
    }

精确查询

java 复制代码
public List<Article> searchByAuthor(String author) {
        try {
            // 构建查询条件(注意:termQuery 支持多种格式查询,如 boolean、int、double、string 等,这里使用的是 string 的查询)
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.query(QueryBuilders.termQuery("author", author));
            SearchRequest searchRequest = new SearchRequest(Constant.ARTICLE_INDEX);
            searchRequest.source(searchSourceBuilder);
            // 执行查询,然后处理响应结果
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            // 根据状态和数据条数验证是否返回了数据
            List<Article> articleList = new ArrayList<>();
            if (RestStatus.OK.equals(searchResponse.status()) && searchResponse.getHits().getTotalHits().value > 0) {
                SearchHits hits = searchResponse.getHits();
                for (SearchHit hit : hits) {
                    Article doc = JSON.parseObject(hit.getSourceAsString(), Article.class);
                    articleList.add(doc);
                }
            }
            return articleList;
        } catch (IOException e) {
            log.error("精确查询异常:", e);
            return null;
        }
    }

全文查询

  • 查全部,
    java MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
    太简单,不再演示。
java 复制代码
/**
     *  全文查询
     */
    public List<Article> matchQuery(String keyword) {
        try {
            // 构建查询条件
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.query(QueryBuilders.multiMatchQuery(keyword,"title","content"));
            // 创建查询请求对象,将查询对象配置到其中
            SearchRequest searchRequest = new SearchRequest(Constant.ARTICLE_INDEX);
            searchRequest.source(searchSourceBuilder);
            // 执行查询,然后处理响应结果
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            return getArticleListFromSearchResponse(searchResponse);
        } catch (IOException e) {
            log.error("全文查询异常", e);
            return null;
        }
    }

分页查询(带排序)

java 复制代码
/**
     *  分页查询
     * @param page
     */
    public void pageSortQuery(Page<Article> page) {
        try {
            // 构建查询条件
            MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
            // 创建查询源构造器
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.query(matchAllQueryBuilder);
            // 设置分页
            searchSourceBuilder.from((int) ((page.getCurrent()-1)*page.getSize()));
            searchSourceBuilder.size((int) page.getSize());
            // 按照阅读量排序
            searchSourceBuilder.sort("readCount", SortOrder.DESC);
            // 创建查询请求对象,将查询对象配置到其中
            SearchRequest searchRequest = new SearchRequest(Constant.ARTICLE_INDEX);
            searchRequest.source(searchSourceBuilder);
            // 执行查询,然后处理响应结果
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            // 根据状态和数据条数验证是否返回了数据
            page.setTotal(getHitTotal(searchResponse));
            page.setRecords(getArticleListFromSearchResponse(searchResponse));
        } catch (IOException e) {
            log.error("分页查询失败", e);
        }
    }

高亮查询✨

java 复制代码
public List<Article> highlightQuery(String keyword) {
        try {
            MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("title", keyword);
            HighlightBuilder highlightBuilder = new HighlightBuilder().field("title").preTags("<font color='red'>").postTags("</font>");
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.query(matchQueryBuilder);
            searchSourceBuilder.highlighter(highlightBuilder);
            searchSourceBuilder.size(100);
            SearchRequest searchRequest = new SearchRequest(Constant.ARTICLE_INDEX);
            searchRequest.source(searchSourceBuilder);
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            List<Article> articleList = new ArrayList<>();
            if (RestStatus.OK.equals(searchResponse.status()) && searchResponse.getHits().getTotalHits().value > 0) {
                SearchHits hits = searchResponse.getHits();
                for (SearchHit hit : hits) {
                    Article doc = JSON.parseObject(hit.getSourceAsString(), Article.class);
                    // 获取高亮的数据
                    HighlightField highlightField = hit.getHighlightFields().get("title");
                    System.out.println("高亮名称:" + highlightField.getFragments()[0].string());
                    // 替换掉原来的数据
                    Text[] fragments = highlightField.getFragments();
                    if (fragments != null && fragments.length > 0) {
                        StringBuilder title = new StringBuilder();
                        for (Text fragment : fragments) {
                            title.append(fragment);
                        }
                        doc.setTitle(title.toString());
                    }
                    articleList.add(doc);
                }
            }
            return articleList;
        } catch (Exception e) {
            log.error("高亮查询失败", e);
            return null;
        }
    }

范围查询

java 复制代码
/**
     *  范围查询
     *  时间文档表达式:https://www.elastic.co/guide/en/elasticsearch/reference/current/common-options.html#date-math
     * @return
     */
    public List<Article> rangeQuery() {
        try {
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            //searchSourceBuilder.query(QueryBuilders.rangeQuery("price").gte(10000));
            searchSourceBuilder.query(QueryBuilders.rangeQuery("createTime")
                    .gte("now-2d").includeLower(true).includeUpper(true));
            SearchRequest searchRequest = new SearchRequest(Constant.ARTICLE_INDEX);
            searchRequest.source(searchSourceBuilder);
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            return getArticleListFromSearchResponse(searchResponse);
        } catch (Exception e) {
            log.error("范围查询失败", e);
            return null;
        }
    }

布尔查询(BooleanQuery)

bool 查询可以用来合并多个条件查询结果的布尔逻辑,它包含一下操作符:

must :多个查询条件必须完全匹配,相当于关系型数据库中的 and。
should :至少有一个查询条件匹配,相当于关系型数据库中的 or。
must_not : 多个查询条件的相反匹配,相当于关系型数据库中的 not。
filter :过滤满足条件的数据。
range :条件筛选范围。
gt :大于,相当于关系型数据库中的 >。
gte :大于等于,相当于关系型数据库中的 >=。
lt :小于,相当于关系型数据库中的 <。
lte:小于等于,相当于关系型数据库中的 <=。

java 复制代码
public List<Article> highlightQuery(String keyword) {
        try {
            MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("title", keyword);
            HighlightBuilder highlightBuilder = new HighlightBuilder().field("title").preTags("<font color='red'>").postTags("</font>");
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.query(matchQueryBuilder);
            searchSourceBuilder.highlighter(highlightBuilder);
            searchSourceBuilder.size(100);
            SearchRequest searchRequest = new SearchRequest(Constant.ARTICLE_INDEX);
            searchRequest.source(searchSourceBuilder);
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            List<Article> articleList = new ArrayList<>();
            if (RestStatus.OK.equals(searchResponse.status()) && searchResponse.getHits().getTotalHits().value > 0) {
                SearchHits hits = searchResponse.getHits();
                for (SearchHit hit : hits) {
                    Article doc = JSON.parseObject(hit.getSourceAsString(), Article.class);
                    // 获取高亮的数据
                    HighlightField highlightField = hit.getHighlightFields().get("title");
                    System.out.println("高亮名称:" + highlightField.getFragments()[0].string());
                    // 替换掉原来的数据
                    Text[] fragments = highlightField.getFragments();
                    if (fragments != null && fragments.length > 0) {
                        StringBuilder title = new StringBuilder();
                        for (Text fragment : fragments) {
                            title.append(fragment);
                        }
                        doc.setTitle(title.toString());
                    }
                    articleList.add(doc);
                }
            }
            return articleList;
        } catch (Exception e) {
            log.error("高亮查询失败", e);
            return null;
        }
    }

聚合查询

在使用Elasticsearch时,更多会用到聚合操作,它类似SQL中的groupby操作。ES的聚合查询是先查出结果,然后对结果使用聚合函数做处理,常用的操作有:avg:求平均、max:最大值、min:最小值、sum:求和等。

在ES中聚合分为指标聚合和分桶聚合:

Metric 指标聚合:指标聚合对一个数据集求最大、最小、和、平均值等

Bucket 分桶聚合:除了有上面的聚合函数外,还可以对查询出的数据进行分组group by,再在组上进行游标聚合。

  • Metric 指标聚合
java 复制代码
/**
     *  指标查询
     */
    public int metricQuery() {
        try {
            MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.query(matchAllQueryBuilder);
            AggregationBuilder mostPopular = AggregationBuilders.max("mostPopular").field("readCount");
            searchSourceBuilder.aggregation(mostPopular);
            SearchRequest searchRequest = new SearchRequest(Constant.ARTICLE_INDEX);
            searchRequest.source(searchSourceBuilder);
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
//            log.info("查询结果:{}", JSON.toJSONString(searchResponse));
            Aggregations aggregations = searchResponse.getAggregations();
            ParsedMax max = aggregations.get("mostPopular");
            return (int) max.getValue();
        } catch (Exception e) {
            log.error("指标查询失败", e);
            return -1;
        }
    }
  • Bucket 分桶聚合

根据文章分类,统计文章数量。

java 复制代码
/**
     *  分桶聚合
     * @return
     */
    public Map<String,Object> bucketQuery() {
        try {
            // 构建查询条件
            MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
            // 创建查询源构造器
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.query(matchAllQueryBuilder);

            // 根据商品分类进行分组查询
            TermsAggregationBuilder categoryGroup = AggregationBuilders.terms("categoryGroup").field("category");
            searchSourceBuilder.aggregation(categoryGroup);

            // 创建查询请求对象,将查询对象配置到其中
            SearchRequest searchRequest = new SearchRequest(Constant.ARTICLE_INDEX);
            searchRequest.source(searchSourceBuilder);
            // 执行查询,然后处理响应结果
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            Aggregations aggregations = searchResponse.getAggregations();
            ParsedStringTerms agg = aggregations.get("categoryGroup");
            Map<String,Object> resultMap = new HashMap<>();
            for (Terms.Bucket bucket : agg.getBuckets()) {
                resultMap.put(bucket.getKeyAsString(), bucket.getDocCount());
            }
            return resultMap;
        } catch (Exception e) {
            log.error("分桶聚合查询失败", e);
            return null;
        }
    }

为什么8.0版本要弃用?

在 Elasticsearch 8.0 版本中,High Level REST Client 被标记为弃用,主要是因为以下几个原因:

  • 维护成本:High Level REST Client 的维护成本较高,因为它需要随着 Elasticsearch 的发展而持续更新,以保持与 REST API 的兼容性。
  • 性能考量:为了提高性能和减少内存消耗,Elasticsearch 开发团队决定移除一些高成本的组件,High Level REST Client 因其封装层次较多而成为目标之一。
  • 替代方案:Elasticsearch 推出了新的 Java API Client,这是一个更轻量级、更高效的选择,它直接使用了 Elasticsearch 的内部协议,从而提供了更好的性能和更低的延迟。
    新的 Java API Client 能够更好地利用 Elasticsearch 的内部机制,减少序列化和反序列化的开销,同时也提供了更细粒度的控制和更高的灵活性。因此,Elasticsearch 推荐用户迁移到新的 Java API Client 上。

所以后续我会再整理个新的Java API Client 用法。与时俱进。

点赞收藏加评论

用到的时候再来看,收获更大。

相关推荐
跟着珅聪学java1 小时前
spring boot +Elment UI 上传文件教程
java·spring boot·后端·ui·elementui·vue
我命由我123451 小时前
Spring Boot 自定义日志打印(日志级别、logback-spring.xml 文件、自定义日志打印解读)
java·开发语言·jvm·spring boot·spring·java-ee·logback
战族狼魂5 小时前
CSGO 皮肤交易平台后端 (Spring Boot) 代码结构与示例
java·spring boot·后端
这个懒人7 小时前
深入解析Translog机制:Elasticsearch的数据守护者
数据库·elasticsearch·nosql·translog
用键盘当武器的秋刀鱼8 小时前
springBoot统一响应类型3.5.1版本
java·spring boot·后端
小李同学_LHY9 小时前
三.微服务架构中的精妙设计:服务注册/服务发现-Eureka
java·spring boot·spring·springcloud
爱喝醋的雷达10 小时前
Spring SpringBoot 细节总结
java·spring boot·spring
愿你天黑有灯下雨有伞11 小时前
Docker 安装 Elasticsearch 教程
运维·elasticsearch·docker
嘵奇12 小时前
深入解析 Spring Boot 测试核心注解
java·spring boot·后端
技术liul13 小时前
解决Spring Boot Configuration Annotation Processor not configured
java·spring boot·后端