首页 > 编程语言 >springcloud学习记录day06--在Java中使用elasticsearch

springcloud学习记录day06--在Java中使用elasticsearch

时间:2022-10-24 17:14:16浏览次数:51  
标签:高亮 -- springcloud request param source 文档 Java QueryBuilders

RestClient查询文档

发起查询请求

以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文档数据

完整代码

/**
 * matchAll查询
 * @throws IOException
 */
@Test
public 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);
    //3.解析数据
    SearchHits hits = response.getHits();

    //查询到的总记录数
    TotalHits totalHits = hits.getTotalHits();
    System.out.println("搜索到的总数据量:"+totalHits);
    //查询所命中的文档数组
    SearchHit[] searchHits = hits.getHits();
    for (SearchHit hit :searchHits) {
        //获取文档source
        String json = hit.getSourceAsString();
        //将json反序列化为Java对象
        HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
        System.out.println(hotelDoc);
    }
}

小结

查询的基本步骤是:

  1. 创建SearchRequest对象

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

    ① QueryBuilders来构建查询条件

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

  3. 发送请求,得到结果

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

排序、分页

搜索结果的排序和分页是与query同级的参数,因此同样是使用request.source()来设置。

对应的API如下:

完整代码示例:

@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);
    }
}

实际案例

常见搜索功能

  • 全文检索
  • 精确检索
  • 字段过滤
  • 附近搜索
  • 排序控制

server代码

@Override
public PageResult search(RequestParam param) {
    //1.准备request
    SearchRequest request = new SearchRequest("hotel");

    //2.组织DSL
    BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

    //关键字搜索
    if (Strings.isEmpty(param.getKey())) {
        boolQuery.must(QueryBuilders.matchAllQuery());
    } else {
        boolQuery.must(QueryBuilders.matchQuery("all", param.getKey()));
    }

    //品牌过滤
    if (Strings.isNotEmpty(param.getBrand())) {
        boolQuery.filter(QueryBuilders.termQuery("brand", param.getBrand()));
    }
    //城市过滤
    if (Strings.isNotEmpty(param.getCity())) {
        boolQuery.filter(QueryBuilders.termQuery("city", param.getCity()));
    }
    //星级过滤
    if (Strings.isNotEmpty(param.getStarName())) {
        boolQuery.filter(QueryBuilders.termQuery("starName", param.getStarName()));
    }
    //最大价格过滤
    if (param.getMaxPrice() != null && param.getMaxPrice() != 0L) {
        boolQuery.filter(QueryBuilders.rangeQuery("price").lte(param.getMaxPrice()));
    }
    //最小价格过滤
    if (param.getMinPrice() != null && param.getMinPrice() != 0L) {
        boolQuery.filter(QueryBuilders.rangeQuery("price").gte(param.getMinPrice()));
    }

    //查询附近酒店
    String location = param.getLocation();
    if (Strings.isNotEmpty(location)) {
        request.source().sort(SortBuilders.geoDistanceSort("location", new GeoPoint(location))
                .order(SortOrder.ASC) //升序
                .unit(DistanceUnit.KILOMETERS) //单位 km
        );
    }

    //算分控制
    FunctionScoreQueryBuilder functionScoreQuery =
            QueryBuilders.functionScoreQuery(
                    boolQuery,
                    //functionScore数组,用于存放具体的算分函数
                    new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{
                            //具体的一个算分函数
                            new FunctionScoreQueryBuilder.FilterFunctionBuilder(
                                    //过滤条件
                                    QueryBuilders.termQuery("isAD",true),
                                    //算分模式,乘以固定值
                                    ScoreFunctionBuilders.weightFactorFunction(10)
                            )
                    }
            );


    request.source().query(functionScoreQuery);

    //3.分页设置
    int page = (param.getPage() - 1) * param.getSize();
    request.source().from(page).size(param.getSize());

    SearchResponse response = null;
    try {
        response = client.search(request, RequestOptions.DEFAULT);
    } catch (IOException e) {
        throw new RuntimeException(e);
    }

    //解析响应数据
    SearchHits responseHits = response.getHits();
    //获取总记录数
    long total = responseHits.getTotalHits().value;
    //获取文档数组
    SearchHit[] hits = responseHits.getHits();

    ArrayList<HotelDoc> list = new ArrayList<>();
    for (SearchHit hit :hits) {
        //获取文档数组中的原始数据
        String json = hit.getSourceAsString();
        //将json数据反序列化为Java对象
        HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
        //获取排序值
        Object[] sortValues = hit.getSortValues();
        if (sortValues.length != 0){
            hotelDoc.setDistance(sortValues[0]);
        }
        list.add(hotelDoc);
    }
    //组织响应数据
    PageResult pageResult = new PageResult();
    pageResult.setTotal(total);
    pageResult.setHotels(list);
    return pageResult;
}

标签:高亮,--,springcloud,request,param,source,文档,Java,QueryBuilders
From: https://www.cnblogs.com/xxgxs/p/16822053.html

相关文章

  • 1、图像预处理ImageDataGenerator
    1、介绍(1)图片生成器,负责生成一个批次一个批次的图片,以生成器的形式给模型训练;(2)对每一个批次的训练图片,适时地进行数据增强处理(dataaugmentation);数据增强处......
  • element UI 选择时间点(可选择某一个或者多个时间点)
    html代码如下:<el-date-pickerref="datesRef"type="dates"v-model="searchObj.dateArr":editable="false"format="yyyy-MM-dd"value-format="yyyy-MM-dd"placehold......
  • Linux安装redis7
    基础环境操作系统:centos7.9(64位)redis:7.0.5安装步骤1.安装1.1上传redis-7.0.5.tar.gz上传至服务器/opt文件夹下。1.2解压cd/opttarxzvfredis-7.0.5.tar.g......
  • JS事件循环之宏任务和微任务
    首先我们知道javascript是一个单线程的脚本语言,也就是说我们在执行代码的过程中不会出现同时进行两个进程(执行两段代码)。JS执行过程中会产生两种任务,分别是:同步任务和异......
  • nginx配置转发https域名到另一个域名上
    server{listen443ssl;server_namewww.test.com;ssl_protocolsTLSv1.2TLSv1.1TLSv1;ssl_ciphersECDHE-RSA-AES128-GCM-SHA256:ECDH......
  • 使用DRF实现五个api接口
    使用DRF实现五个api接口2.1新建appdjango-adminstartappapp012.2配置环境#注册app01和rest_framework,由于drf提供了web调试界面,所以静态文件功能不能注释掉,不然......
  • 序列化器的简单使用
    序列化器的简单使用3.1新建appdjango-adminstartappsers3.2注册appINSTALLED_APPS=[#'django.contrib.admin','django.contrib.auth','django.......
  • MySQL 中 不等于 会过滤掉 Null 的问题
    1.原因: 在写SQL条件语句时经常用到不等于!=的筛选条件。  此时要注意此条件会将字段为Null的数据也当做满足不等于的条件而将数据筛选掉。 2.实例:表A ......
  • xss攻击
    xss键盘记录xss插入代码<scripttype="text/javascript"src="./log.js"></script>log.jsdocument.onkeypress=function(evt){evt=evt?evt:window.event;key=St......
  • 对称加密、非对称加密 与 HTTPS
    一、对称加密(SymmetricCryptography)对称加密是最快速、最简单的一种加密方式,加密(encryption)与解密(decryption)用的是同样的密钥(secretkey)。对称加密有很多种算法,由于它效......