JavaRestClient搜索
概述
查询的基本步骤如下:
- 创建
request对象,这次是搜索,所以是SearchRequest - 准备请求参数,也就是查询DSL对应的JSON参数
- 发起请求
- 解析响应,响应结果相对复杂,需要逐层解析
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:同时求max、min、avg、sum等
- 管道(
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:聚合的类型,按分类聚合,所以用termfield:参与聚合的字段名称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聚合,就可以同时获取min、max、avg等结果。
语法:
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);
}
}