Elasticsearch学习笔记-p7(数据聚合&自动补全)
Posted LL.LEBRON
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Elasticsearch学习笔记-p7(数据聚合&自动补全)相关的知识,希望对你有一定的参考价值。
文章目录
视频指路👉 B站黑马微服务超级推荐!!
数据聚合&自动补全
1.数据聚合
聚合是什么?
聚合可以让我们极其方便的实现对数据的统计、分析、运算。例如:
- 什么品牌的手机最受欢迎?
- 这些手机的平均价格、最高价格、最低价格?
- 这些手机每月的销售情况如何?
实现这些统计功能的比数据库的sql要方便的多,而且查询速度非常快,可以实现近实时搜索效果。
1.1 聚合的种类
聚合常见的有三类:
-
桶(Bucket) 聚合:用来对文档做分组
- TermAggregation:按照文档字段值分组,例如按照品牌值分组、按照国家分组
- Date Histogram:按照日期阶梯分组,例如一周为一组,或者一月为一组
-
度量(Metric) 聚合:用以计算一些值,比如:最大值、最小值、平均值等
- Avg:求平均值
- Max:求最大值
- Min:求最小值
- Stats:同时求max、min、avg、sum等
-
管道(pipeline) 聚合:其它聚合的结果为基础做聚合
注意: 参加聚合的字段必须是keyword、日期、数值、布尔类型,不能是text!
1.2 DSL实现聚合
1.2.1 Bucket聚合语法
例如:我们要统计所有数据中的酒店品牌有几种,其实就是按照品牌对数据分组。此时可以根据酒店品牌的名称做聚合,也就是 Bucket
聚合。
GET /hotel/_search
"size": 0, // 设置size为0,结果中不包含文档,只包含聚合结果
"aggs": // 定义聚合
"brandAgg": //给聚合起个名字
"terms": // 聚合的类型,按照品牌值聚合,所以选择term
"field": "brand", // 参与聚合的字段
"size": 20 // 希望获取的聚合结果数量
1.2.2 聚合结果排序
默认情况下,Bucket
聚合会统计Bucket内的文档数量,记为_count
,并且按照_count
降序排序。
我们可以指定order
属性,自定义聚合的排序方式:
GET /hotel/_search
"size": 0,
"aggs":
"brandAgg":
"terms":
"field": "brand",
"order":
"_count": "asc" // 按照_count升序排列
,
"size": 20
1.2.3 限定聚合范围
默认情况下,Bucket
聚合是对索引库的所有文档做聚合,但真实场景下,用户会输入搜索条件,因此聚合必须是对搜索结果聚合。那么聚合必须添加限定条件。
我们可以限定要聚合的文档范围,只要添加query
条件即可:
GET /hotel/_search
"query":
"range":
"price":
"lte": 200 // 只对200元以下的文档聚合
,
"size": 0,
"aggs":
"brandAgg":
"terms":
"field": "brand",
"size": 20
这次,聚合得到的品牌明显变少了:
1.2.4.Metric聚合语法
上节课,我们对酒店按照品牌分组,形成了一个个桶。现在我们需要对桶内的酒店做运算,获取每个品牌的用户评分的min、max、avg等值。
这就要用到Metric
聚合了,例如stat
聚合:就可以获取min、max、avg等结果。
GET /hotel/_search
"size": 0,
"aggs":
"brandAgg":
"terms":
"field": "brand",
"size": 20
,
"aggs": // 是brands聚合的子聚合,也就是分组后对每组分别计算
"score_stats": // 聚合名称
"stats": // 聚合类型,这里stats可以计算min、max、avg等
"field": "score" // 聚合字段,这里是score
这次的score_stats聚合是在brandAgg的聚合内部嵌套的子聚合。因为我们需要在每个桶分别计算。
另外,我们还可以给聚合结果做个排序,例如按照每个桶的酒店平均分做排序:
1.2.5 总结
aggs代表聚合,与query同级,此时query的作用是?
- 限定聚合的的文档范围
聚合必须的三要素:
- 聚合名称
- 聚合类型
- 聚合字段
聚合可配置属性有:
size
:指定聚合结果数量order
:指定聚合结果排序方式field
:指定聚合字段
1.3 RestAPI实现聚合
聚合条件与query
条件同级别,因此需要使用request.source()
来指定聚合条件。
聚合条件的语法:
聚合的结果也与查询结果不同,API也比较特殊。不过同样是JSON逐层解析:
代码如下:
//聚合
@Test
void testAggregation() throws IOException
//1.准备Request
SearchRequest request = new SearchRequest("hotel");
//2.准备DSL
request.source().size(0);
request.source().aggregation(AggregationBuilders
.terms("brandAgg")
.field("brand")
.size(20)
);
//3.发出请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//4.解析结果
Aggregations aggregations = response.getAggregations();
//4.1根据聚合名称获取聚合结果
Terms brandTerms = aggregations.get("brandAgg");
//4.2获取buckets
List<? extends Terms.Bucket> buckets = brandTerms.getBuckets();
//4.3遍历
for (Terms.Bucket bucket : buckets)
//4.4获取key
String key = bucket.getKeyAsString();
System.out.println(key);
2.自动补全
当用户在搜索框输入字符时,我们应该提示出与该字符有关的搜索项,如图:
这种根据用户输入的字母,提示完整词条的功能,就是自动补全了。
因为需要根据拼音字母来推断,因此要用到拼音分词功能。
2.1 拼音分词器
要实现根据字母做补全,就必须对文档按照拼音分词。插件地址:https://github.com/medcl/elasticsearch-analysis-pinyin
使用 docker volume inspect es-plugins
查看插件目录,将下载的文件解压上传,重启 Elasticsearch
测试用法如下:
POST /_analyze
"text": "如家酒店还不错",
"analyzer": "pinyin"
结果:
2.2 自定义分词器
默认的拼音分词器会将每个汉字单独分为拼音,而我们希望的是每个词条形成一组拼音,需要对拼音分词器做个性化定制,形成自定义分词器。
elasticsearch
中分词器(analyzer)的组成包含三部分:
character filters
:在tokenizer之前对文本进行处理。例如删除字符、替换字符tokenizer
:将文本按照一定的规则切割成词条(term)。例如keyword,就是不分词;还有ik_smarttokenizer filter
:将tokenizer输出的词条做进一步处理。例如大小写转换、同义词处理、拼音处理等
文档分词时会依次由这三部分来处理文档:
声明自定义分词器的语法如下:
PUT /test
"settings":
"analysis":
"analyzer": // 自定义分词器
"my_analyzer": // 分词器名称
"tokenizer": "ik_max_word",
"filter": "py"
,
"filter": // 自定义tokenizer filter
"py": // 过滤器名称
"type": "pinyin", // 过滤器类型,这里是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"
测试:
总结:
如何使用拼音分词器?
-
①下载pinyin分词器
-
②解压并放到elasticsearch的plugin目录
-
③重启即可
如何自定义分词器?
-
①创建索引库时,在settings中配置,可以包含三部分
-
②character filter
-
③tokenizer
-
④filter
拼音分词器注意事项?
- 为了避免搜索到同音字,搜索时不要使用拼音分词器
2.3 自动补全查询
elasticsearch
提供了 Completion Suggester 查询来实现自动补全功能。这个查询会匹配以用户输入内容开头的词条并返回;为了提高补全查询的效率,对于文档中字段的类型有一些约束
- 参与补全查询的字段必须是
completion
类型。 - 字段的内容一般是用来补全的多个词条形成的数组。
比如,一个这样的索引库:
// 创建索引库
PUT test
"mappings":
"properties":
"title":
"type": "completion"
然后插入下面的数据:
// 示例数据
POST test/_doc
"title": ["Sony", "WH-1000XM3"]
POST test/_doc
"title": ["SK-II", "PITERA"]
POST test/_doc
"title": ["Nintendo", "switch"]
查询的DSL语句如下:
// 自动补全查询
GET /test/_search
"suggest":
"title_suggest":
"text": "s", // 关键字
"completion":
"field": "title", // 补全查询的字段
"skip_duplicates": true, // 跳过重复的
"size": 10 // 获取前10条结果
2.4 自动补全查询的JavaAPI
之前我们学习了自动补全查询的DSL,而没有学习对应的JavaAPI,这里给出一个示例:
而自动补全的结果也比较特殊,解析的代码如下:
代码如下:
//补全
@Test
void testSuggest() throws IOException
//1.准备Reequest
SearchRequest request = new SearchRequest("hotel");
//2.准备DSL
request.source().suggest(new SuggestBuilder().addSuggestion(
"suggestions",
SuggestBuilders.completionSuggestion("suggestion")
.prefix("h")
.size(10)
.skipDuplicates(true)
));
//3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//4.解析结果
//4.1 得到Suggest
Suggest suggest = response.getSuggest();
//4.2 根据名称获取补全结果
CompletionSuggestion suggestion = suggest.getSuggestion("suggestions");
//4.3获取options并遍历
for (CompletionSuggestion.Entry.Option option : suggestion.getOptions())
//4.4获取一个option中text,也就是补全的词条
String text = option.getText().toString();
System.out.println(text);
最后喜欢的小伙伴,记得三连哦!😏🍭😘
以上是关于Elasticsearch学习笔记-p7(数据聚合&自动补全)的主要内容,如果未能解决你的问题,请参考以下文章
999页阿里P7Java学习笔记在互联网上火了,完整版开放下载