首页 > 其他分享 >RestClient查询文档(*)

RestClient查询文档(*)

时间:2025-01-17 09:47:02浏览次数:1  
标签:高亮 RestClient request 查询 source 文档 QueryBuilders response

match_all查询

代码解读:

  • 第一步,创建SearchRequest对象,指定索引库名

  • 第二步,利用request.source()构建DSL,DSL中可以包含查询、分页、排序、高亮等

    • query():代表查询条件,利用QueryBuilders.matchAllQuery()构建一个match_all查询的DSL
  • 第三步,利用client.search()发送请求,得到响应

这里关键的API有两个,一个是request.source(),其中包含了查询、排序、分页、高亮等所有功能:

另一个是QueryBuilders,其中包含match、term、function_score、bool等各种查询:

解析响应

elasticsearch返回的结果是一个JSON字符串,结构包含:

  • hits:命中的结果
    • total:总条数,其中的value是具体的总条数值
    • max_score:所有结果中得分最高的文档的相关性算分
    • hits:搜索结果的文档数组,其中的每个文档都是一个json对象
      • _source:文档中的原始数据,也是json对象

因此,我们解析响应结果,就是逐层解析JSON字符串,流程如下:

  • SearchHits:通过response.getHits()获取,就是JSON中的最外层的hits,代表命中的结果
    • SearchHits#getTotalHits().value:获取总条数信息
    • SearchHits#getHits():获取SearchHit数组,也就是文档数组
      • SearchHit#getSourceAsString():获取文档结果中的_source,也就是原始的json文档数据.

完整代码

@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.解析响应
    handleResponse(response);
}

private void handleResponse(SearchResponse response) {
    // 4.解析响应
    SearchHits searchHits = response.getHits();
    // 4.1.获取总条数
    long total = searchHits.getTotalHits().value;
    System.out.println("共搜索到" + total + "条数据");
    // 4.2.文档数组
    SearchHit[] hits = searchHits.getHits();
    // 4.3.遍历
    for (SearchHit hit : hits) {
        // 获取文档source
        String json = hit.getSourceAsString();
        // 反序列化
        HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
        System.out.println("hotelDoc = " + hotelDoc);
    }
}

查询的基本步骤是:

  1. 创建SearchRequest对象

  2. 准备Request.source(),也就是DSL。

    ① QueryBuilders来构建查询条件

    ② 传入Request.source() 的 query() 方法

  3. 发送请求,得到结果

  4. 解析结果(参考JSON结果,从外到内,逐层解析)

全文检索

@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.解析响应
    handleResponse(response);

}

精确查询

布尔查询

@Test
void testBool() throws IOException {
    // 1.准备Request
    SearchRequest request = new SearchRequest("hotel");
    // 2.准备DSL
    // 2.1.准备BooleanQuery
    BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
    // 2.2.添加term
    boolQuery.must(QueryBuilders.termQuery("city", "杭州"));
    // 2.3.添加range
    boolQuery.filter(QueryBuilders.rangeQuery("price").lte(250));

    request.source().query(boolQuery);
    // 3.发送请求
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    // 4.解析响应
    handleResponse(response);

}

排序、分页

@Test
void testPageAndSort() throws IOException {
    // 页码,每页大小
    int page = 1, size = 5;

    // 1.准备Request
    SearchRequest request = new SearchRequest("hotel");
    // 2.准备DSL
    // 2.1.query
    request.source().query(QueryBuilders.matchAllQuery());
    // 2.2.排序 sort
    request.source().sort("price", SortOrder.ASC);
    // 2.3.分页 from、size
    request.source().from((page - 1) * size).size(5);
    // 3.发送请求
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    // 4.解析响应
    handleResponse(response);

}

高亮

高亮的代码与之前代码差异较大,有两点:

  • 查询的DSL:其中除了查询条件,还需要添加高亮条件,同样是与query同级。
  • 结果解析:结果除了要解析_source文档数据,还要解析高亮结果

高亮请求构建

高亮请求的构建API如下:

上述代码省略了查询条件部分,但是大家不要忘了:高亮查询必须使用全文检索查询,并且要有搜索关键字,将来才可以对关键字高亮

@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.解析响应
    handleResponse(response);
}

高亮结果解析

高亮的结果与查询的文档结果默认是分离的,并不在一起。

因此解析高亮的代码需要额外处理:

 

代码解读:

  • 第一步:从结果中获取source。hit.getSourceAsString(),这部分是非高亮结果,json字符串。还需要反序列为HotelDoc对象
  • 第二步:获取高亮结果。hit.getHighlightFields(),返回值是一个Map,key是高亮字段名称,值是HighlightField对象,代表高亮值
  • 第三步:从map中根据高亮字段名称,获取高亮字段值对象HighlightField
  • 第四步:从HighlightField中获取Fragments,并且转为字符串。这部分就是真正的高亮字符串了
  • 第五步:用高亮的结果替换HotelDoc中的非高亮结果

完整代码如下:

private void handleResponse(SearchResponse response) {
    // 4.解析响应
    SearchHits searchHits = response.getHits();
    // 4.1.获取总条数
    long total = searchHits.getTotalHits().value;
    System.out.println("共搜索到" + total + "条数据");
    // 4.2.文档数组
    SearchHit[] hits = searchHits.getHits();
    // 4.3.遍历
    for (SearchHit hit : hits) {
        // 获取文档source
        String json = hit.getSourceAsString();
        // 反序列化
        HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
        // 获取高亮结果
        Map<String, HighlightField> highlightFields = hit.getHighlightFields();
        if (!CollectionUtils.isEmpty(highlightFields)) {
            // 根据字段名获取高亮结果
            HighlightField highlightField = highlightFields.get("name");
            if (highlightField != null) {
                // 获取高亮值
                String name = highlightField.getFragments()[0].string();
                // 覆盖非高亮结果
                hotelDoc.setName(name);
            }
        }
        System.out.println("hotelDoc = " + hotelDoc);
    }
}

示例代码:

  1 @Slf4j
  2 @Service
  3 public class HotelService extends ServiceImpl<HotelMapper, Hotel> implements IHotelService {
  4 
  5     @Autowired
  6     private RestHighLevelClient restHighLevelClient;
  7 
  8     @Override
  9     public PageResult search(RequestParams params) {
 10         try {
 11             // 1.准备Request
 12             SearchRequest request = new SearchRequest("hotel");
 13             // 2.准备请求参数
 14             // 2.1.query
 15             buildBasicQuery(params, request);
 16             // 2.2.分页
 17             int page = params.getPage();
 18             int size = params.getSize();
 19             request.source().from((page - 1) * size).size(size);
 20             // 2.3.距离排序
 21             String location = params.getLocation();
 22             if (StringUtils.isNotBlank(location)) {
 23                 request.source().sort(SortBuilders
 24                         .geoDistanceSort("location", new GeoPoint(location))
 25                         .order(SortOrder.ASC)
 26                         .unit(DistanceUnit.KILOMETERS)
 27                 );
 28             }
 29             // 3.发送请求
 30             SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
 31             // 4.解析响应
 32             return handleResponse(response);
 33         } catch (IOException e) {
 34             throw new RuntimeException("搜索数据失败", e);
 35         }
 36     }
 37 
 38     private void buildBasicQuery(RequestParams params, SearchRequest request) {
 39         // 1.准备Boolean查询
 40         BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
 41 
 42         // 1.1.关键字搜索,match查询,放到must中
 43         String key = params.getKey();
 44         if (StringUtils.isNotBlank(key)) {
 45             // 不为空,根据关键字查询
 46             boolQuery.must(QueryBuilders.matchQuery("all", key));
 47         } else {
 48             // 为空,查询所有
 49             boolQuery.must(QueryBuilders.matchAllQuery());
 50         }
 51 
 52         // 1.2.品牌
 53         String brand = params.getBrand();
 54         if (StringUtils.isNotBlank(brand)) {
 55             boolQuery.filter(QueryBuilders.termQuery("brand", brand));
 56         }
 57         // 1.3.城市
 58         String city = params.getCity();
 59         if (StringUtils.isNotBlank(city)) {
 60             boolQuery.filter(QueryBuilders.termQuery("city", city));
 61         }
 62         // 1.4.星级
 63         String starName = params.getStarName();
 64         if (StringUtils.isNotBlank(starName)) {
 65             boolQuery.filter(QueryBuilders.termQuery("starName", starName));
 66         }
 67         // 1.5.价格范围
 68         Integer minPrice = params.getMinPrice();
 69         Integer maxPrice = params.getMaxPrice();
 70         if (minPrice != null && maxPrice != null) {
 71             maxPrice = maxPrice == 0 ? Integer.MAX_VALUE : maxPrice;
 72             boolQuery.filter(QueryBuilders.rangeQuery("price").gte(minPrice).lte(maxPrice));
 73         }
 74 
 75         // 2.算分函数查询
 76         FunctionScoreQueryBuilder functionScoreQuery = QueryBuilders.functionScoreQuery(
 77                 boolQuery, // 原始查询,boolQuery
 78                 new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{ // function数组
 79                         new FunctionScoreQueryBuilder.FilterFunctionBuilder(
 80                                 QueryBuilders.termQuery("isAD", true), // 过滤条件
 81                                 ScoreFunctionBuilders.weightFactorFunction(10) // 算分函数
 82                         )
 83                 }
 84         );
 85 
 86         // 3.设置查询条件
 87         request.source().query(functionScoreQuery);
 88     }
 89 
 90     private PageResult handleResponse(SearchResponse response) {
 91         SearchHits searchHits = response.getHits();
 92         // 4.1.总条数
 93         long total = searchHits.getTotalHits().value;
 94         // 4.2.获取文档数组
 95         SearchHit[] hits = searchHits.getHits();
 96         // 4.3.遍历
 97         List<HotelDoc> hotels = new ArrayList<>(hits.length);
 98         for (SearchHit hit : hits) {
 99             // 4.4.获取source
100             String json = hit.getSourceAsString();
101             // 4.5.反序列化,非高亮的
102             HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
103             // 4.6.处理高亮结果
104             // 1)获取高亮map
105             Map<String, HighlightField> map = hit.getHighlightFields();
106             if (map != null && !map.isEmpty()) {
107                 // 2)根据字段名,获取高亮结果
108                 HighlightField highlightField = map.get("name");
109                 if (highlightField != null) {
110                     // 3)获取高亮结果字符串数组中的第1个元素
111                     String hName = highlightField.getFragments()[0].toString();
112                     // 4)把高亮结果放到HotelDoc中
113                     hotelDoc.setName(hName);
114                 }
115             }
116             // 4.8.排序信息
117             Object[] sortValues = hit.getSortValues();
118             if (sortValues.length > 0) {
119                 hotelDoc.setDistance(sortValues[0]);
120             }
121 
122             // 4.9.放入集合
123             hotels.add(hotelDoc);
124         }
125         return new PageResult(total, hotels);
126     }
127 }
View Code

 

标签:高亮,RestClient,request,查询,source,文档,QueryBuilders,response
From: https://www.cnblogs.com/WarBlog/p/18675038

相关文章

  • 专利查询
    专利查询平台    专利制度的本质是公开换取保护,因此各国的专利管理机构都负有向公众提供专利信息的义务(绝大部分都是免费的,不过不敢把话说死,万一有奇葩国家呢)。所以主要国家和组织的专利管理机构官方网站都可以进行专利检索。    专利检索可以简单分为专利文本检索和......
  • 使用箭头注释增加PDF清晰度-MESCIUS PDF文档解决方案
    使用箭头注释增加PDF的清晰度2025年1月16日方向标记增强了文档审查和技术插图,提供更清晰的交流并提高PDF的可读性。MESCIUS的PDF文档解决方案箭头注释是一种可视化工具,允许用户使用箭头作为方向指示器来吸引用户对PDF中特定元素的注......
  • 查询、更新数组/嵌套对象
    查询、更新数组/嵌套对象我们可以对对象、对象中的元素、数组、数组中的元素进行匹配查询,甚至还可以对数组和对象相互嵌套的字段进行匹配查询/更新,下面我们从普通匹配开始讲讲如何进行匹配。普通匹配匹配记录中的嵌套字段匹配数组匹配数组匹配数组中元素匹配数组第n项......
  • GaussDB云原生数据库SQL引擎继承原来openGauss的词法解析,语法解析,查询重写,查询优化和
    云原生数据库SQL引擎继承原来openGauss的词法解析,语法解析,查询重写,查询优化和执行引擎的能力。由于云原生数据库是shareddisk架构,一个事务在一个节点上执行,所以不需要原来分布式根据分布式key进行数据分布,分布式执行和分布式2PC提交的能力。为了支持数据库粒度的异地多活,云原生......
  • 命中索引一定能提高查询速度吗?
    命中索引一定能提高查询速度吗?目录命中索引一定能提高查询速度吗?目录索引的基本原理索引命中与查询性能查询复杂性数据量与索引选择性更新与维护成本过多的索引何时索引能提高查询速度?简单查询高选择性字段适当的索引类型结论答案是否定的,在实际项目中我曾踩过这......
  • 约束.数据库设计.多表查询.事务
    1.约束非空约束:关键字是NOTNULL保证列中所有的数据不能有null值。唯一约束:关键字是UNIQUE保证列中所有数据各不相同。主键约束:关键字是PRIMARYKEY非空且唯一。默认约束:关键字是DEFAULT未指定值则采用默认值。外键约束:关键字是FOREIGNKEY练习根据需求,为表......
  • Day10-后端Web实战——Mysql多表操作&员工列表查询(分页查询)
    目录1.多表关系1.1一对多1.1.1关系实现1.1.2外键约束1.2一对一1.3多对多1.4案例2.多表查询2.1概述2.1.1数据准备2.1.2介绍2.1.3分类2.2内连接2.3外连接2.4子查询2.4.1介绍2.4.2标量子查询2.4.3列子查询2.4.4行子查询2.4.5表子查询2.5案例3.员......
  • 洛谷题单指南-线段树的进阶用法-P3168 [CQOI2015] 任务查询系统
    原题链接:https://www.luogu.com.cn/problem/P3168题意解读:一个任务管理系统,能够查询在某个时间点运行的任务中优先级最小的k个任务的优先级之和。解题思路:由于总时间n不超过100000,考虑针对所有时刻建立可持久化线段树,根节点为root[i]的线段树维护时刻i的任务情况,节点区间表示......
  • 如果在odoo模型中是一对多的字段,或者是计算字段,那么在查询的时候,怎么处理。
    在Odoo中,一对多字段(One2many)和计算字段(Computed)在查询时的处理与普通字段有所不同,因为它们并不直接映射到数据库表中的列。理解如何查询这些字段是非常重要的,下面我会分别介绍如何处理一对多字段和计算字段。1.一对多字段(One2many)一对多字段(One2many)在Odoo中是通过外键......
  • 媒体查询+雪碧图
    <媒体查询>----->媒体查询会根据设备的大小自动识别加载不同的样式     ------><metaname="viewport"content="width=device-width,initial-scale=1.0">这条属性为设置试图宽度,并禁止缩放,媒体查询实现统一网站在不同登录设备中实现不同效果,下面这段代码实现在设......