Elasticsearch(4):Java Rest Client 搜索与聚合速查

JavaRestClient搜索

概述

查询的基本步骤如下:

  1. 创建request对象,这次是搜索,所以是SearchRequest
  2. 准备请求参数,也就是查询DSL对应的JSON参数
  3. 发起请求
  4. 解析响应,响应结果相对复杂,需要逐层解析
java 复制代码
@Test
void testMatchAll() throws IOException {
    //1、创建request
    SearchRequest request = new SearchRequest("item");
    //2、准备请求参数
    SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
    sourceBuilder.query(QueryBuilders.matchAllQuery());
    request.source(sourceBuilder);
    //3、发送请求
    SearchResponse response=client.search(request, RequestOptions.DEFAULT) ;
    //4、处理请求
    ResponseHandler(response);
}
private void ResponseHandler(SearchResponse response) throws IOException {
    SearchHits hits = response.getHits();
    //1、获取总条数
    Long total = hits.getTotalHits().value;
    System.out.println("共搜索到"+total+"条数据");
    //2、遍历结果
    for(SearchHit hit : hits.getHits()){
        //3、得到source,就是基础的json文件
        String source = hit.getSourceAsString();
        //4、返序列化并打印
        ItemDoc itemdoc= JSONUtil.toBean(source,ItemDoc.class);
    }
}

注:

​ SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

可能必须手动new出来,否则不会初始化

叶子查询

match查询

json 复制代码
@Test
void testMatch() throws IOException {
    // 1.创建Request
    SearchRequest request = new SearchRequest("item");
    // 2.组织请求参数
    request.source().query(QueryBuilders.matchQuery("brand", "华为"));
    // 3.发送请求
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    // 4.解析响应
    ResponseHandler(response);
}

multimatch查询

java 复制代码
@Test
void TestMultiMatch() throws IOException {
    SearchRequest request = new SearchRequest("item");
    // 2.组织请求参数
    request.source().query(QueryBuilders.multiMatchQuery("华为", "brand"));
    // 3.发送请求
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    // 4.解析响应
    ResponseHandler(response);
}

range查询

java 复制代码
@Test
void TestRangeTest() throws IOException {
    SearchRequest request = new SearchRequest("item");
    // 2.组织请求参数
    request.source().query(QueryBuilders.rangeQuery("price").gte(10000).lte(1000000));
    // 3.发送请求
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    // 4.解析响应
    ResponseHandler(response);
}

term查询

java 复制代码
@Test
void TestTermSearch() throws IOException {
    SearchRequest request = new SearchRequest("item");
    // 2.组织请求参数
    request.source().query(QueryBuilders.termQuery("brand", "华为"));
    // 3.发送请求
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    // 4.解析响应
    ResponseHandler(response);

}

复合查询

java 复制代码
@Test
void UnionSearch() throws IOException {
    // 1.创建Request
    SearchRequest request = new SearchRequest("item");
    // 2.组织请求参数
    BoolQueryBuilder query = QueryBuilders.boolQuery();
    query.must(QueryBuilders.matchQuery("name", "华为新品"));
    query.filter(QueryBuilders.termQuery("brand.keyword", "华为"));
    query.filter(QueryBuilders.rangeQuery("price").lte(3000000));
    request.source().query(query);
    // 3.发送请求
    SearchResponse response = client.s-earch(request, RequestOptions.DEFAULT);
    // 4.解析响应
    ResponseHandler(response);
}

排序和分页

Java 复制代码
@Test
void testPageAndSort() throws IOException {
    int pageNo = 1, pageSize = 5;

    // 1.创建Request
    SearchRequest request = new SearchRequest("items");
    // 2.组织请求参数
    // 2.1.搜索条件参数
    request.source().query(QueryBuilders.matchQuery("name", "脱脂牛奶"));
    // 2.2.排序参数
    request.source().sort("price", SortOrder.ASC);
    // 2.3.分页参数
    request.source().from((pageNo - 1) * pageSize).size(pageSize);
    // 3.发送请求
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    // 4.解析响应
    handleResponse(response);
}

高亮

java 复制代码
@Test
void Highlight() throws IOException {
    SearchRequest request = new SearchRequest("item");
    // 2.组织请求参数
    //查询条件
    request.source().query(QueryBuilders.matchQuery("name", "华为新品"));
    //高亮条件
    request.source().highlighter(SearchSourceBuilder.highlight()
            .field("name")
            .preTags("<em>")
            .postTags("</em>"));
    // 3.发送请求
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    // 4.解析响应
    ResponseHandler(response);
}

查询结果处理

java 复制代码
private void ResponseHandler(SearchResponse response) throws IOException {
    SearchHits hits = response.getHits();
    //1、获取总条数
    Long total = hits.getTotalHits().value;
    System.out.println("共搜索到"+total+"条数据");
    //2、遍历结果
    for(SearchHit hit : hits.getHits()){
        //3、得到source,就是基础的json文件
        String source = hit.getSourceAsString();
        //4、返序列化并打印
        ItemDoc itemdoc= JSONUtil.toBean(source,ItemDoc.class);
        //5、获取高亮
        Map<String, HighlightField> hfs = hit.getHighlightFields();
        if(CollUtils.isNotEmpty(hfs)){
            //有结果,提前高亮部分
            HighlightField hf = hfs.get("name");
            String hfStr = hf.getFragments()[0].toString();
            itemdoc.setName(hfStr);
        }
        System.out.println(itemdoc);
    }
}
java 复制代码
HighlightField hf = hfs.get("name");

这里就是要高亮的字段位置

聚合

概述

聚合(aggregations)可以让我们极其方便的实现对数据的统计、分析、运算。

聚合常见的有三类:

  • 桶(Bucket)聚合 :用来对文档做分组
    • TermAggregation:按照文档字段值分组,例如按照品牌值分组、按照国家分组
    • Date Histogram:按照日期阶梯分组,例如一周为一组,或者一月为一组
  • **度量(Metric聚合 :用以计算一些值,比如:最大值、最小值、平均值等
    • Avg:求平均值
    • Max:求最大值
    • Min:求最小值
    • Stats:同时求maxminavgsum
  • 管道(pipeline)聚合:其它聚合的结果为基础做进一步运算

**注意:**参加聚合的字段必须是keyword、日期、数值、布尔类型

DSL实现聚合

Bucket聚合

以分类(category)字段对数据分组。

category值一样的放在同一组,属于Bucket聚合中的Term聚合。

基本语法如下:

JSON 复制代码
GET /items/_search
{
  "size": 0, 
  "aggs": {
    "category_agg": {
      "terms": {
        "field": "category",
        "size": 20
      }
    }
  }
}

语法说明:

  • size:设置size为0,就是每页查0条,则结果中就不包含文档,只包含聚合
  • aggs:定义聚合
    • category_agg:聚合名称,自定义,但不能重复
      • terms:聚合的类型,按分类聚合,所以用term
        • field:参与聚合的字段名称
        • size:希望返回的聚合结果的最大数量

带条件的聚合

JSON 复制代码
GET /items/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "term": {
            "category": "手机"
          }
        },
        {
          "range": {
            "price": {
              "gte": 300000
            }
          }
        }
      ]
    }
  }, 
  "size": 0, //返回多少条文档
  "aggs": {
    "brand_agg": {
      "terms": {
        "field": "brand",
        "size": 20//返回多少条bucket
      }
    }
  }
}

例:

  • 搜索查询条件:
    • 价格低于3000
    • 必须是手机
  • 聚合目标:统计的是品牌,肯定是对brand字段做term聚合
json 复制代码
GET /item/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "term": {
            "category.keyword": "手机"
          }
        },
        {
          "range": {
            "price": {
              "lte": 300000
            }
          }
        }
      ]
    }
  },
  "size": 20,
  "aggs": {
    "Brand_aggs": {
      "terms": {
        "field": "brand.keyword",
        "size": 20
      }
    }
  }
}

并列聚合

aggs内可实现对多个桶的统计

如:

json 复制代码
GET /item/_search
{
  "size": 0,
  "aggs": {
    "brandAgg": {
      "terms": {
        "field": "brand.keyword"
      }
    },
    "categoryAgg": {
      "terms": {
        "field": "category.keyword"
      }
    },
    "priceAgg": {
      "range": {
        "field": "price",
        "ranges": [
          {
            "to": 50000
          },
          {
            "from": 50000,
            "to": 100000
          },
          {
            "from": 100000
          }
        ]
      }
    }
  }
}

嵌套聚合

再一个桶内嵌套了另一个桶

就是给一个分类里再进行细化的分类

如华为有手机和平板

json 复制代码
GET /item/_search
{
  "size": 0, 
  "aggs": {

    "brandAgg": {

      "terms": {
        "field": "brand.keyword"
      },

      "aggs": {

        "categoryAgg": {
          "terms": {
            "field": "category.keyword"
          }
        }

      }
    }

  }
}

metric聚合

需要对桶内做运算,获取最小值、最大值、平均值等。

这就要用到Metric聚合了,例如stat聚合,就可以同时获取minmaxavg等结果。

语法:

JSON 复制代码
GET /items/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "term": {
            "category": "手机"
          }
        },
        {
          "range": {
            "price": {
              "gte": 300000
            }
          }
        }
      ]
    }
  }, 
  "size": 0, 
  "aggs": {
    "brand_agg": {
      "terms": {
        "field": "brand",
        "size": 20
      },
      "aggs": {
        "stats_meric": {
          "stats": {
            "field": "price"
          }
        }
      }
    }
  }
}

新加了一个aggs参数。这个聚合就是brand_agg的子聚合,会对brand_agg形成的每个桶中的文档分别统计。

  • stats_meric:聚合名称
    • stats:聚合类型,stats是metric聚合的一种
      • field:聚合字段,这里选择price,统计价格

例:

json 复制代码
GET /item/_search
{
  "size": 0,
  "aggs": {
    "brandAgg": {
      "terms": {
        "field": "brand.keyword"
      },
      "aggs": {
        "stats_meric": {
          "stats": {
            "field": "price"
          }
        }
      }
    }
  }
}

总结:

aggs代表聚合,与query同级,

此时query的作用是

  • 限定聚合的的文档范围

聚合必须的三要素:

  • 聚合名称
  • 聚合类型
  • 聚合字段

聚合可配置属性有:

  • size:指定聚合结果数量
  • order:指定聚合结果排序方式
  • field:指定聚合字段

restclient实现聚合

利用request.source()方法来设置。

聚合条件的要利用AggregationBuilders这个工具类来构造。

聚合结果与搜索文档同一级别,因此需要单独获取和解析。

再 aggregations下一级,可能为term,stats等,需要按情况讨论

以term为例:

java 复制代码
@Test
void testAgg() throws IOException {
    // 1.创建Request
    SearchRequest request = new SearchRequest("items");
    // 2.准备请求参数
    BoolQueryBuilder bool = QueryBuilders.boolQuery()
            .filter(QueryBuilders.termQuery("category", "手机"))
            .filter(QueryBuilders.rangeQuery("price").gte(300000));
    request.source().query(bool).size(0);
    // 3.聚合参数
    request.source().aggregation(
            AggregationBuilders.terms("brand_agg").field("brand").size(5)
    );
    // 4.发送请求
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    // 5.解析聚合结果
    Aggregations aggregations = response.getAggregations();
    // 5.1.获取品牌聚合
    Terms brandTerms = aggregations.get("brand_agg");
    // 5.2.获取聚合中的桶
    List<? extends Terms.Bucket> buckets = brandTerms.getBuckets();
    // 5.3.遍历桶内数据
    for (Terms.Bucket bucket : buckets) {
        // 5.4.获取桶内key
        String brand = bucket.getKeyAsString();
        System.out.print("brand = " + brand);
        long count = bucket.getDocCount();
        System.out.println("; count = " + count);
    }
}
相关推荐
小旭95271 小时前
MySQL 主从复制、MyCat 读写分离与分库分表实战
java·数据库·sql·mysql·database
计算机安禾1 小时前
【算法分析与设计】第38篇:最近点对与分治在几何中的应用
java·服务器·网络·数据库·算法
梦梦代码精1 小时前
功能堆砌不如好扩展:4 款开源商城系统的选型思考
java·docker·uni-app·开源·php
计算机安禾1 小时前
【算法分析与设计】第37篇:平面扫描与线段交问题
java·大数据·数据库·算法·机器学习
兰令水1 小时前
leecodecode【二叉树排序+最近公共祖先】【2026.6.2打卡-java版本】
java·数据结构·算法·leetcode
人道领域1 小时前
【LeetCode刷题日记】77&&216.回溯算法剪枝优化在组合问题中的应用
java·算法·leetcode
诸葛务农1 小时前
共沸脱水技术及其在光刻胶用PGMEA纯化中的应用(上)
java·数据库·算法
风兮雨露1 小时前
Java 从入门到精通,前端资料
java·开发语言·前端
NE_STOP1 小时前
Docker--认识Docker网络
java