聚合可以讓我們極其方便的實(shí)現(xiàn)對(duì)數(shù)據(jù)的統(tǒng)計(jì)、分析、運(yùn)算。例如:
什么品牌的手機(jī)最受歡迎?
這些手機(jī)的平均價(jià)格、最高價(jià)格、最低價(jià)格?
這些手機(jī)每月的銷售情況如何?
實(shí)現(xiàn)這些統(tǒng)計(jì)功能的比數(shù)據(jù)庫(kù)的sql要方便的多,而且查詢速度非??欤梢詫?shí)現(xiàn)近實(shí)時(shí)搜索效果
聚合種類
聚合常見的有三類:
-
桶(Bucket)聚合:用來對(duì)文檔做分組
-
TermAggregation:按照文檔字段值分組,例如按照品牌值分組、按照國(guó)家分組
-
Date Histogram:按照日期階梯分組,例如一周為一組,或者一月為一組
-
-
度量(Metric)聚合:用以計(jì)算一些值,比如:最大值、最小值、平均值等
-
Avg:求平均值
-
Max:求最大值
-
Min:求最小值
-
Stats:同時(shí)求max、min、avg、sum等
-
-
管道(pipeline)聚合:其它聚合的結(jié)果為基礎(chǔ)做聚合
注意:參加聚合的字段必須是keyword、日期、數(shù)值、布爾類型 ?
DSL實(shí)現(xiàn)聚合
語(yǔ)句
GET /hotel/_search
{
"size": 0,
"aggs": {
"brandAgg": {
"terms": {
"field": "brand",
"size": 20
}
}
}
}
- 設(shè)置size為0,結(jié)果中不包含文檔,只包含聚合結(jié)果
- aggs定義聚合
- brandAgg給聚合起個(gè)名字
- terms聚合的類型,按照品牌值聚合,所以選擇term
- field參與聚合的字段
- terms里面的sezi希望獲取的聚合結(jié)果數(shù)量
發(fā)起請(qǐng)求的結(jié)果?
聚合結(jié)果排序
默認(rèn)情況下,Bucket聚合會(huì)統(tǒng)計(jì)Bucket內(nèi)的文檔數(shù)量,記為count,并且按照count降序排序。
我們可以指定order屬性,自定義聚合的排序方式,按照_count降序排列
GET /hotel/_search
{
"size": 0,
"aggs": {
"brandAgg": {
"terms": {
"field": "brand",
"order": {
"_count": "desc"
},
"size": 20
}
}
}
}
發(fā)起請(qǐng)求的結(jié)果,?按照_count降序排列。
限定聚合范圍
默認(rèn)情況下,Bucket聚合是對(duì)索引庫(kù)的所有文檔做聚合,但真實(shí)場(chǎng)景下,用戶會(huì)輸入搜索條件,因此聚合必須是對(duì)搜索結(jié)果聚合。那么聚合必須添加限定條件。我們可以限定要聚合的文檔范圍,只要添加query條件即可。
?只對(duì)200元以下的文檔聚合
GET /hotel/_search
{
"query": {
"range": {
"price": {
"lte": 200
}
}
},
"size": 0,
"aggs": {
"brandAgg": {
"terms": {
"field": "brand",
"size": 20
}
}
}
}
聚合得到的品牌明顯變少了 ?
Metric聚合語(yǔ)法
現(xiàn)在我們需要對(duì)桶內(nèi)的酒店做運(yùn)算,獲取每個(gè)品牌的用戶評(píng)分的min、max、avg等值
?score_stats聚合是在brandAgg的聚合內(nèi)部嵌套的子聚合。因?yàn)槲覀冃枰诿總€(gè)桶分別計(jì)算
GET /hotel/_search
{
"size": 0,
"aggs": {
"brandAgg": {
"terms": {
"field": "brand",
"size": 20
},
"aggs": {
"score_stats": {
"stats": {
"field": "score"
}
}
}
}
}
}
我們還可以給聚合結(jié)果做個(gè)排序,例如按照每個(gè)桶的酒店平均分做排序,score_stats.avg對(duì)score聚合函數(shù)的平均值進(jìn)行降序排序。
GET /hotel/_search
{
"size": 0,
"aggs": {
"brandAgg": {
"terms": {
"field": "brand",
"size": 20,
"order": {
"score_stats.avg": "desc"
}
},
"aggs": {
"score_stats": {
"stats": {
"field": "score"
}
}
}
}
}
}
小結(jié)
aggs代表聚合,與query同級(jí) ?
聚合必須的三要素:
-
聚合名稱
-
聚合類型
-
聚合字段
聚合可配置屬性有:
-
size:指定聚合結(jié)果數(shù)量
-
order:指定聚合結(jié)果排序方式
-
field:指定聚合字段
java代碼實(shí)現(xiàn)聚合
搜索頁(yè)面的品牌、城市等信息不應(yīng)該是在頁(yè)面寫死,而是通過聚合索引庫(kù)中的酒店數(shù)據(jù)得來的 ?
controller類
import cn.itcast.hotel.pojo.PageResult;
import cn.itcast.hotel.pojo.RequestParams;
import cn.itcast.hotel.service.IHotelService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/hotel")
public class HotelController {
@Autowired
private IHotelService hotelService;
@PostMapping("filters")
public Map<String, List<String>> getFilters(@RequestBody RequestParams params){
return hotelService.getFilters(params);
}
}
service類
import cn.itcast.hotel.mapper.HotelMapper;
import cn.itcast.hotel.pojo.Hotel;
import cn.itcast.hotel.pojo.HotelDoc;
import cn.itcast.hotel.pojo.PageResult;
import cn.itcast.hotel.pojo.RequestParams;
import cn.itcast.hotel.service.IHotelService;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class HotelService extends ServiceImpl<HotelMapper, Hotel> implements IHotelService {
@Autowired
private RestHighLevelClient client;
@Override
public Map<String, List<String>> getFilters(RequestParams params) {
try {
// 1.準(zhǔn)備Request
SearchRequest request = new SearchRequest("hotel");
// 2.準(zhǔn)備DSL
// 2.1.query
// buildBasicQuery(params, request);
// 2.2.設(shè)置size
request.source().size(0);
// 2.3.聚合
buildAggregation(request);
// 3.發(fā)出請(qǐng)求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
// 4.解析結(jié)果
Map<String, List<String>> result = new HashMap<>();
Aggregations aggregations = response.getAggregations();
// 4.1.根據(jù)品牌名稱,獲取品牌結(jié)果
List<String> brandList = getAggByName(aggregations, "brandAgg");
result.put("品牌", brandList);
// 4.2.根據(jù)品牌名稱,獲取品牌結(jié)果
List<String> cityList = getAggByName(aggregations, "cityAgg");
result.put("城市", cityList);
// 4.3.根據(jù)品牌名稱,獲取品牌結(jié)果
List<String> starList = getAggByName(aggregations, "starAgg");
result.put("星級(jí)", starList);
return result;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private void buildAggregation(SearchRequest request) {
request.source().aggregation(AggregationBuilders
.terms("brandAgg")
.field("brand")
.size(100)
);
request.source().aggregation(AggregationBuilders
.terms("cityAgg")
.field("city")
.size(100)
);
request.source().aggregation(AggregationBuilders
.terms("starAgg")
.field("starName")
.size(100)
);
}
private List<String> getAggByName(Aggregations aggregations, String aggName) {
// 4.1.根據(jù)聚合名稱獲取聚合結(jié)果
Terms brandTerms = aggregations.get(aggName);
// 4.2.獲取buckets
List<? extends Terms.Bucket> buckets = brandTerms.getBuckets();
// 4.3.遍歷
List<String> brandList = new ArrayList<>();
for (Terms.Bucket bucket : buckets) {
// 4.4.獲取key
String key = bucket.getKeyAsString();
brandList.add(key);
}
return brandList;
}
}
發(fā)送請(qǐng)求,獲得結(jié)果文章來源:http://www.zghlxwxcb.cn/news/detail-701327.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-701327.html
到了這里,關(guān)于elasticsearch的數(shù)據(jù)聚合的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!