聚合(aggregations)
:可以实现对文档数据的统计、分析、运算。
聚合常见的有三类:
桶(Bucket)排序:用来对文档做分组。
TermAggregation:按照文档字段值分组。
Date Histogram:按照日期阶梯分组,例如一周为一组,或者一月为一组。
度量(Metric)聚合:用以计算一些值,比如:最大值、最小值、平均值等
Avg:求平均值
Max:求最大值
Min:求最小值
Stats:同时求max、min、avg、sum等
管道(pipeline)聚合:其它聚合的结果为基础做聚合。
参与聚合的字段类型必须是:
案例一:统计所有数据中的酒店品牌,此时可以根据酒店品牌名称做聚合。
# 聚合功能,自定义排序规则
GET /hotel1/_search
{
"size": 0, // 设置size为0,结果中不包含文档,只包含聚合结果
"aggs": { // 定义聚合
"brandAggs": {
"terms": { // 聚合类型,按照品牌值聚合
"field": "brand", // 参与聚合的字段
"size": 20 // 希望获取的聚合结果数量
}
}
}
}
案例二:聚合结果排序
# 聚合功能,自定义排序规则
GET /hotel1/_search
{
"size": 0,
"aggs": {
"brandAggs": {
"terms": {
"order": {
"_count": "asc"
},
"field": "brand",
"size": 30
}
}
}
}
案例三:限定聚合范围
# 聚合功能,自定义聚合范围
GET /hotel1/_search
{
"query": {
"range": {
"price": {
"lte": 200
}
}
},
"size": 0,
"aggs": {
"brandAggs": {
"terms": {
"field": "brand",
"size": 20
}
}
}
}
总结:
aggs代表聚合,与query同级,此时query的作用是限定聚合文档的范围。
聚合必须的三要素:
聚合可配置属性:
# 嵌套metric聚合
GET /hotel1/_search
{
"size": 0,
"aggs": {
"brandAggs": {
"terms": {
"field": "brand",
"size": 20,
"order": {
"scoreAggs.avg": "desc"
}
},
"aggs": {
"scoreAggs": {
"stats": {
"field": "score"
}
}
}
}
}
}
@Test
void brandAggregation() throws IOException {
// 1.准备request对象
SearchRequest request = new SearchRequest("hotel1");
// 2.准备DSL
request.source().size(0);
request.source().aggregation(AggregationBuilders
.terms("brand_agg")
.field("brand")
.size(20)
);
// 3. 发送请求
SearchResponse searchResponse = client.search(request, RequestOptions.DEFAULT);
// 4.解析结果
Aggregations aggregations = searchResponse.getAggregations();
// 4.1根据名称获取聚合结果
Terms brandTerm = aggregations.get("brand_agg");
// 获取桶
List<? extends Terms.Bucket> buckets = brandTerm.getBuckets();
// 遍历
for (Terms.Bucket bucket : buckets) {
// 获取key,即品牌信息
String brandName = bucket.getKeyAsString();
System.out.println(brandName);
}
}
Github地址:https://github.com/lonre/elasticsearch-analysis-pinyin-segmentation
在GitHub下载后,解压并拷贝到Elasticsearch的plugins目录下,重启elasticsearch。
具体使用参考官方(即Github)中的使用案例。
elasticsearch中分词器(analyzer)的组成包含三部分:
我们可以在创建索引库时,通过settings来配置自定义的analyzer(分词器):
拼音分词器适合在创建倒排索引时使用,但不能在搜索的时候使用:
如果我们在搜索时也使用拼音分词的话,搜索狮子也搜索到了虱子,这肯定是不行的。
因此字段在创建倒排索引时应该有my_analyzer分词器,字段在搜索时应该使用ik_smart分词器:
PUT /test
{
"settings": {
"analysis": {
"analyzer": {
"my_analyzer": {
"tokenizer": "ik_max_word",
"filter": "py"
}
},
"filter": {
"py": {
"type": "pinyin",
"keep_full_pinyin": false,
"keep_joined_full_pinyin": true,
"keep_original": true,
"limit_first_letter_length": 16,
"remove_duplicated_term": true,
"none_chinese_pinyin_tokenize": false
}
}
}
},
"mappings": {
"properties": {
"name": {
"type": "text",
"analyzer": "my_analyzer",
"search_analyzer": "ik_smart"
}
}
}
}
elasticsearch提供了Completion Suggester
查询来实现自动补全功能。这个查询会匹配以用户输入内容开头的词条并返回。为了提高补全查询的效率,对于文档中的字段类型有一些约束:
# 自动补全查询
POST /test1/_search
{
"suggest": {
"title_suggest": {
"text": "s",
"completion": {
"field": "title",
"skip_duplicates": true,
"size": 10
}
}
}
}
@Test
void testSuggest() throws IOException {
// 1.准备request对象
SearchRequest request = new SearchRequest("hotel");
// 2.准备DSL
request.source().suggest(new SuggestBuilder().addSuggestion(
"suggestions",
SuggestBuilders.completionSuggestion("suggestion")
.prefix("h")
.skipDuplicates(true)
.size(10)
));
// 3.发起请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
// 4.解析结果
Suggest suggest = response.getSuggest();
// 4.1 根据名称获取补全结果
CompletionSuggestion suggestion = suggest.getSuggestion("suggestions");
// 4.2 获取options并遍历
List<CompletionSuggestion.Entry.Option> options = suggestion.getOptions();
for (CompletionSuggestion.Entry.Option option : options) {
String text = option.getText().string();
System.out.println(text);
}
}
elasticsearch中的酒店数据来自于mysql数据库,因此mysql数据发生改变时,elasticsearch也必须跟着改变,这个就是elasticsearch与mysql之间的数据同步。
微服务中,负责酒店管理的业务(mysql)与负责酒店搜索的业务(elasticsearch)可能在两个不同的微服务上,那么数据同步该如何实现呢?
方案一:同步调用
方案三:监听binlog