【ElasticSearch】使用 Java 客户端 RestClient 实现对文档的查询操作,以及对搜索结果的排序、分页、高亮处理

这篇具有很好参考价值的文章主要介绍了【ElasticSearch】使用 Java 客户端 RestClient 实现对文档的查询操作,以及对搜索结果的排序、分页、高亮处理。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


前言:RestClient 查询文档的 RestAPI

在 Elasticsearch 中,通过 RestAPI 进行 DSL 查询语句的构建通常是通过 HighLevelRestClient 中的 resource() 方法来实现的。该方法包含了查询、排序、分页、高亮等所有功能,为构建复杂的查询提供了便捷的接口。

resthighlevelclient高亮显示查询,微服务,ElasticSearch,elasticsearch

RestAPI 中构建查询条件的核心部分是由一个名为 QueryBuilders 的工具类提供的。该工具类包含了各种查询方法,如下图所示:

resthighlevelclient高亮显示查询,微服务,ElasticSearch,elasticsearch

查询的基本步骤如下:

  1. 创建 SearchRequest 对象。
  2. 准备 Request.source(),也就是 DSL。
  3. 使用 QueryBuilders 构建查询条件。
  4. 将查询条件传入 Request.source().query() 方法。
  5. 发送请求,得到结果。
  6. 解析结果,可以参考 JSON 结果,从外到内逐层解析。

这种方式使得构建复杂的查询变得简单而灵活。在接下来的实例中,我们将深入学习如何使用 HighLevelRestClient 中的 resource() 方法构建各种查询,并充分利用 QueryBuilders 工具类来满足不同的搜索需求。

一、全文检索查询

1.1 match_all 查询

match_all 查询的单元测试代码:

@Test
void testMatchAll() throws IOException {
    // 1. 准备Request
    SearchRequest request = new SearchRequest("hotel");

    // 2. 组织 DSL 请求
    request.source().query(QueryBuilders.matchAllQuery());

    // 3. 发送请求
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);

    // 4. 解析结果
    List<HotelDoc> hotelDocs = handleResponse(response);
    System.out.println(hotelDocs);
}

这个测试代码演示了如何使用 match_all 查询来获取指定索引(这里是 “hotel”)下的所有文档。具体步骤如下:

  1. 创建 SearchRequest 对象,指定索引为 “hotel”。
  2. 使用 QueryBuilders.matchAllQuery() 构建查询条件。
  3. 将查询条件添加到请求的 DSL 中。
  4. 发送请求,得到查询结果。
  5. 解析查询结果,将文档转换为 HotelDoc 对象。

1.2 match 查询

@Test
void testMatch() throws IOException {
    // 1. 准备Request
    SearchRequest request = new SearchRequest("hotel");

    // 2. 组织 DSL 请求
    request.source().query(QueryBuilders.matchQuery("all", "如家"));

    // 3. 发送请求
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);

    // 4. 解析结果
    List<HotelDoc> hotelDocs = handleResponse(response);
    System.out.println(hotelDocs);
}

这个测试代码演示了如何使用 match 查询来搜索包含特定关键词(这里是 “如家”)的文档。具体步骤如下:

  1. 创建 SearchRequest 对象,指定索引为 “hotel”。
  2. 使用 QueryBuilders.matchQuery("all", "如家") 构建查询条件,表示在 “all” 字段中搜索包含 “如家” 的文档。
  3. 将查询条件添加到请求的 DSL 中。
  4. 发送请求,得到查询结果。
  5. 解析查询结果,将文档转换为 HotelDoc 对象。

1.3 multi_match 查询

@Test
void testMultiMatch() throws IOException {
    // 1. 准备Request
    SearchRequest request = new SearchRequest("hotel");

    // 2. 组织 DSL 请求
    request.source().query(QueryBuilders.multiMatchQuery("如家", "name", "business"));

    // 3. 发送请求
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);

    // 4. 解析结果
    List<HotelDoc> hotelDocs = handleResponse(response);
    System.out.println(hotelDocs);
}

这个测试代码演示了如何使用 multi_match 查询来在多个字段(这里是 “name” 和 “business”)中搜索包含特定关键词(这里是 “如家”)的文档。具体步骤如下:

  1. 创建 SearchRequest 对象,指定索引为 “hotel”。
  2. 使用 QueryBuilders.multiMatchQuery("如家", "name", "business") 构建查询条件,表示在 “name” 和 “business” 字段中搜索包含 “如家” 的文档。
  3. 将查询条件添加到请求的 DSL 中。
  4. 发送请求,得到查询结果。
  5. 解析查询结果,将文档转换为 HotelDoc 对象。

可以看到,这些测试代码的结构类似,只是在构建查询条件时使用了不同的 QueryBuilders 方法,用于满足不同的查询需求。

二、精确查询

精确查询常见的有 term 查询和 range 查询,同样使用 QueryBuilders 指定具体的查询方式。

2.1 term 查询

@Test
void testTerm() throws IOException {
    // 1. 准备Request
    SearchRequest request = new SearchRequest("hotel");

    // 2. 组织 DSL 请求
  	request.source().query(QueryBuilders.termQuery("city", "上海"));

    // 3. 发送请求
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);

    // 4. 解析结果
    List<HotelDoc> hotelDocs = handleResponse(response);
    System.out.println(hotelDocs);
}

这个测试代码演示了如何使用 term 查询来搜索指定字段(这里是 “city”)中包含特定关键词(这里是 “上海”)的文档。具体步骤如下:

  1. 创建 SearchRequest 对象,指定索引为 “hotel”。
  2. 使用 QueryBuilders.termQuery("city", "上海") 构建查询条件,表示在 “city” 字段中搜索包含 “上海” 的文档。
  3. 将查询条件添加到请求的 DSL 中。
  4. 发送请求,得到查询结果。
  5. 解析查询结果,将文档转换为 HotelDoc 对象。

2.2 range 查询

@Test
void testRange() throws IOException {
    // 1. 准备Request
    SearchRequest request = new SearchRequest("hotel");

    // 2. 组织 DSL 请求
    request.source().query(QueryBuilders.rangeQuery("price").gte(150).lte(200));

    // 3. 发送请求
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);

    // 4. 解析结果
    List<HotelDoc> hotelDocs = handleResponse(response);
    System.out.println(hotelDocs);
}

这个测试代码演示了如何使用 range 查询来搜索指定字段(这里是 “price”)中在给定范围内的文档。具体步骤如下:

  1. 创建 SearchRequest 对象,指定索引为 “hotel”。
  2. 使用 QueryBuilders.rangeQuery("price").gte(150).lte(200) 构建查询条件,表示在 “price” 字段中搜索价格在 150 到 200 之间的文档。
  3. 将查询条件添加到请求的 DSL 中。
  4. 发送请求,得到查询结果。
  5. 解析查询结果,将文档转换为 HotelDoc 对象。

这些测试代码演示了如何使用精确查询来满足特定的搜索需求。在实际应用中,可以根据具体的业务场景和数据结构选择不同的查询方式。

三、复合查询:Boolean 查询与 function score 查询的综合案例

例如,现在通过一个酒店预订网址的查询功能不但可以在搜索框输入关键字进行查询,还可以勾选指定的筛选条件,比如城市、星级、品牌和价格范围:

resthighlevelclient高亮显示查询,微服务,ElasticSearch,elasticsearch
另外,再所有的酒店数据中还存在一部分属于广告(ES 文档中新增一个布尔类型的 isAD 字段表示),要求查询结果中的广告需要顶置显示,因此整个查询分为两部分:即 boolean 查询和 function score 查询。

  • boolean 查询:实现对搜索关键字的查询,以及过滤:城市、星级、品牌和价格等条件;
  • function score 查询:实现对广告文档的相关性增加操作。

具体的查询代码如下:

private static void buildBasicQuery(RequestParams params, SearchRequest request) {
    // 1. 原始查询 Query

    BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
    // 关键字搜索 must
    String key = params.getKey();
    if (key == null || key.isEmpty()) {
        boolQuery.must(QueryBuilders.matchAllQuery());
    } else {
        boolQuery.must(QueryBuilders.matchQuery("all", key));
    }

    // 城市条件
    if (params.getCity() != null && !params.getCity().isEmpty()) {
        boolQuery.filter(QueryBuilders.termQuery("city", params.getCity()));
    }
    // 品牌条件
    if (params.getBrand() != null && !params.getBrand().isEmpty()) {
        boolQuery.filter(QueryBuilders.termQuery("brand", params.getBrand()));
    }
    // 星级条件
    if (params.getStarName() != null && !params.getStarName().isEmpty()) {
        boolQuery.filter(QueryBuilders.termQuery("starName", params.getStarName()));
    }
    // 价格范围
    if (params.getMaxPrice() != null && params.getMinPrice() != null) {
        boolQuery.filter(QueryBuilders
                .rangeQuery("price").lte(params.getMaxPrice()).gte(params.getMinPrice()));
    }

    // 2. 算分查询
    FunctionScoreQueryBuilder functionScoreQuery =
            QueryBuilders.functionScoreQuery(
                    // 原始查询,相关信算法的查询
                    boolQuery,
                    // function score 数组
                    new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{
                            // 其中一个具体的 function score
                            new FunctionScoreQueryBuilder.FilterFunctionBuilder(
                                    // 过滤条件
                                    QueryBuilders.termQuery("isAD", true),
                                    // 算分函数
                                    ScoreFunctionBuilders.weightFactorFunction(10)
                            )
                    });

    request.source().query(functionScoreQuery);
}

对上述代码的详细说明:

  • RequestParams 是一个封装了前端请求参数的对象,里面包含了 ES 文档中的各个字段;
  • 在这个方法中,首先构建了一个 boolQuery 作为原始查询条件,包含了关键字搜索、城市、品牌、星级和价格范围等多个条件;
  • 接着,构建了一个 functionScoreQuery,将原始查询作为参数传入,同时定义了一个 FilterFunctionBuilder,用于处理广告部分的查询,对广告文档的分数进行加权,使其在查询结果中更靠前显示;
  • 最后,将 functionScoreQuery 设置为请求的查询条件。

这个综合的查询案例涵盖了多个条件的组合查询以及对特定文档的加权分数处理。在实际应用中,可以根据业务需求扩展和修改这个查询方法。

四、对查询结果的处理

4.1 将查询结果按照自己的距离远近排序

在前端查询酒店数据的时候,一般都会定位获取到自己当前的位置,然后传递给后端。

  • RequestParams 作为前端参数的封装对象,包含了这个位置信息,可通过get 方法进行获取;
  • 然后可以通过 SortBuilders 中的 geoDistanceSort 方法计算距离并进行排序操作,即可获取酒店与自己的实际距离。
String location = params.getLocation();
if (location != null && !location.isEmpty()) {
    request.source().sort(SortBuilders
            .geoDistanceSort("location", new GeoPoint(location))
            .order(SortOrder.ASC)
            .unit(DistanceUnit.KILOMETERS)
    );
}

4.2 根据前端请求参数进行分页操作

分页需要的页码以及页面大小一般都由前端传递参数给后端,然后后端获取这两个参数进行分页操作。

  • RequestParams 作为前端参数的封装对象,包含了这两个参数,可通过get 方法进行获取;
  • 然后再根据分页偏移量的计算公式offset = (page - 1) * size 即可获取偏移量,然后通过 sourcefromsize 方法,即可实现分页查询。

例如:

int page = params.getPage();
            int size = params.getSize();
            request.source().from((page - 1) * size).size(size);

4.3 对搜索关键字进行高亮处理

要对搜索关键字进行高亮处理同样非常简单,只需要使用 resouce 中的 highlighter 方法指定要进行高亮的字段即可。

实现的示例代码如下:

@Test
void testHighlight() throws IOException {

    // 1. 准备Request
    SearchRequest request = new SearchRequest("hotel");

    // 2. 组织 DSL 请求
    // 2.1 query
    request.source().query(QueryBuilders.matchQuery("all", "如家"));

    // 2.2 设置高亮
    request.source().highlighter(new HighlightBuilder().field("name").requireFieldMatch(false));

    // 3. 发送请求
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);

    // 4. 解析结果
    List<HotelDoc> hotelDocs = handleResponse(response);
    System.out.println(hotelDocs);
}

说明:

注意requireFieldMatch方法的作用是高亮的字段是否需要和搜索的字段匹配。例如:使用字段 all 查询匹配 brand 字段,此时 brand 字段使用了 copy_toall 字段,因此要高亮的字段并不匹配,如果不设置 requireFieldMatchfalse 则会高亮失败。

对结果的解析:
实现高亮的原理是对搜索关键字加上了 <em> </em> 标签,通过在 Kibana 中使用高亮处理的 DSL 语句可以发现:

resthighlevelclient高亮显示查询,微服务,ElasticSearch,elasticsearch
其实高亮的处理并没有作用到查询出的原始文档中,而是在每个 hits 里面新增了一个 highlight 字段,里面包含了高亮的关键字,因此还需要对 handleResponse 函数进行改造,使得能够处理高亮的查询结果:

例如,在handleResponse 函数的 result.add(hotelDoc) 这句代码之前,新增了以下代码用于处理高亮的情况,即使用高亮处理了的关键字替换查询结果中对应的关键字:

// 获取高亮结果
Map<String, HighlightField> highlightFields = hit.getHighlightFields();
if(highlightFields != null && !highlightFields.isEmpty()) {
    // 获取高亮名称
    HighlightField highlightField = highlightFields.get("name");
    // 获取高亮的值
    String name = highlightField.getFragments()[0].toString();
    hotelDoc.setName(name);
}

当运行这段测试代码,即可发现成功对 name 字段的 “如家” 添加了 <em> </em> 标签:

resthighlevelclient高亮显示查询,微服务,ElasticSearch,elasticsearch文章来源地址https://www.toymoban.com/news/detail-792664.html

到了这里,关于【ElasticSearch】使用 Java 客户端 RestClient 实现对文档的查询操作,以及对搜索结果的排序、分页、高亮处理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 干货 | Elasticsearch Java 客户端演进历史和选型指南

    Elasticsearch 官方提供了很多版本的 Java 客户端,包含但不限于: Transport 客户端 Java REST 客户端 Low Level REST 客户端 High Level REST 客户端 Java API 客户端 非官方的 Java 客户端,包含但不限于: Jest 客户端 BBoss 客户端 Spring Data Elasticsearch 客户端 ...... 写出来的就接近十款客户端! El

    2023年04月11日
    浏览(37)
  • ElasticSearch-学习笔记04【Java客户端操作索引库】

    Java后端-学习路线-笔记汇总表【黑马程序员】 ElasticSearch-学习笔记01【ElasticSearch基本介绍】 【day01】 ElasticSearch-学习笔记02【ElasticSearch索引库维护】 ElasticSearch-学习笔记03【ElasticSearch集群】 ElasticSearch-学习笔记04【Java客户端操作索引库】 【day02】 ElasticSearch-学习笔记05【Spri

    2023年04月09日
    浏览(31)
  • 【Elasticsearch学习笔记五】es常用的JAVA API、es整合SpringBoot项目中使用、利用JAVA代码操作es、RestHighLevelClient客户端对象

    目录 一、Maven项目集成Easticsearch 1)客户端对象 2)索引操作 3)文档操作 4)高级查询 二、springboot项目集成Spring Data操作Elasticsearch 1)pom文件 2)yaml 3)数据实体类 4)配置类 5)Dao数据访问对象 6)索引操作 7)文档操作 8)文档搜索 三、springboot项目集成bboss操作elasticsearch

    2023年04月09日
    浏览(36)
  • java后端使用websocket实现与客户端之间接收及发送消息

    客户端请求websocket接口,连接通道=》我这边业务成功客户端发消息=》客户端自动刷新。 接口:ws://localhost:8080/websocket/xx 经测试,成功 如果是线上服务器连接,则需要在nginx里配置websocket相关内容,再重启nginx,代码如下 本地连接的时候用的是ws://,因为是http链接,但是如果是

    2024年02月16日
    浏览(29)
  • Elasticsearch Java客户端和Spring data elasticsearch-Elasticsearch文章三

    https://www.elastic.co/cn/ 整合springboot看上一篇文章 一定要对应好版本,Elasticsearch 的不同版本变化是真大, https://docs.spring.io/spring-data/elasticsearch/docs/4.4.10/reference/html/ Springboot: 2.7.10 spring-data-elasticsearch: 4.4.10 spring-boot-starter-data-elasticsearch: 2.7.10 elasticsearch-java: 7.17.9 https://github.com/

    2024年02月14日
    浏览(26)
  • 【网络原理】使用Java基于UDP实现简单客户端与服务器通信

    我们用Java实现UDP数据报套接字编程,需要借用以下API来实现 网络编程, 本质上是要操作网卡. 但是网卡不方便直接操作. 在操作系统内核中, 使用了一种特殊的叫做 “socket” 这样的文件来抽象表示网卡. 因此进行网络通信, 势必需要先有一个 socket 对象. DatagramSocket 是UDP Socket,

    2024年03月11日
    浏览(45)
  • windows环境安装elasticsearch+kibana并完成JAVA客户端查询

    elasticsearch 官网下载比较慢,有时还打不开,可以通过https://elasticsearch.cn/download/下载,先找到对应的版本,最好使用迅雷下载,秒下的,我的下载速度可以达到40M/S 解压后点击 elasticsearch-7.10.0binelasticsearch.bat 运行成功后,输入http://120.0.0.1:9200,可以访问说明ES启动成功 点击

    2024年02月14日
    浏览(33)
  • Java使用Milo实现OPC UA客户端,封装spring boot starter

    最新版本更新日志查看:https://github.com/kangaroo1122/milo-spring-boot-starter/blob/main/UPDATE.md、https://gitee.com/vampire001/milo-spring-boot-starter/blob/master/UPDATE.md,此处不再更新 由eclipse开源,地址:https://github.com/eclipse/milo,可以基于此开发OPC UA客户端或者服务端。 本文介绍基于milo 封装的sp

    2024年02月09日
    浏览(36)
  • Elasticsearch8.x版本Java客户端Elasticsearch Java API Client中常用API练习

    在Es7.15版本之后,es官方将它的高级客户端RestHighLevelClient标记为弃用状态。同时推出了全新的java API客户端Elasticsearch Java API Client,该客户端也将在Elasticsearch8.0及以后版本中成为官方推荐使用的客户端。 Elasticsearch Java API Client支持除Vector title search API和Find structure API之外的所有

    2024年04月11日
    浏览(33)
  • [elastic 8.x]java客户端连接elasticsearch与操作索引与文档

    为了方便演示,我关闭了elasticsearch的安全验证,带安全验证的初始化方式将在最后专门介绍 其中,HotelDoc是一个实体类 带安全验证的连接有点复杂,将下列代码中CA证书的位置改为实际所在的位置就行了。 password为elastic的密码,可以在我的另一篇文章中查看密码的重置方式

    2024年04月11日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包