一般网站建设多少钱便宜的网站好吗,浙江省建筑培训网,做网站选用什么域名比较好,保险网官网一、数据聚合
聚合#xff08;aggregations#xff09;#xff1a; 实现对文档数据的统计、分析、运算。
#xff08;一#xff09;聚合的常见种类
桶#xff08;Bucket#xff09;聚合#xff1a; 用来做文档分组。 TermAggregation#xff1a; 按照文档字段值分组…一、数据聚合
聚合aggregations 实现对文档数据的统计、分析、运算。
一聚合的常见种类
桶Bucket聚合 用来做文档分组。 TermAggregation 按照文档字段值分组Date Histogram 按照日期阶梯分组例如一周一组一月一组 度量Metric聚合 用以计算一些值比如最大值、最小值、平均值等。 Avg 求平均值Max 求最大值Min 求最小值Stats 同时求max、min、avg、sum等 管道pipeline聚合 其它聚合的结果为基础的聚合。
参与聚合的字段类型
keyword数值日期布尔
二DSL实现聚合
1、桶聚合
当我们统计所有数据中的酒店品牌有几种此时可以根据酒店品牌的名称做聚合。
1基本实现
GET /hotel/_search
{size: 0, // 设置size为0结果中不包含文档只包含聚合结果aggs: { // 定义聚合brandAgg: { // 给聚合起个名字terms: { // 聚合的类型按照品牌值聚合所以选择termfield: brand, //参与聚合的字段size: 20 // 希望获取的聚合结果数量}}}
}2Bucket聚合结果排序
默认情况下Bucket聚合会统计Bucket内的文档数量记为_count并且按照_count降序排序。
那么如何修改排序?
GET /hotel/_search
{size: 0, // 设置size为0结果中不包含文档只包含聚合结果aggs: { // 定义聚合brandAgg: { // 给聚合起个名字terms: { // 聚合的类型按照品牌值聚合所以选择termfield: brand, //参与聚合的字段,order: { # 排序_count: asc},size: 20 // 希望获取的聚合结果数量}}}
}3限定聚合范围
默认情况下Bucket聚合是对索引库的所有文档做聚合可以限定聚合的文档范围只要添加query条件。
GET /hotel/_search
{query: {range: {price: {lte: 200 # 只对200元以下的文档聚合}}}size: 0, // 设置size为0结果中不包含文档只包含聚合结果aggs: { // 定义聚合brandAgg: { // 给聚合起个名字terms: { // 聚合的类型按照品牌值聚合所以选择termfield: brand, //参与聚合的字段,order: { # 排序_count: asc},size: 20 // 希望获取的聚合结果数量}}}
}2、Metrics聚合
需求 要求获取每个品牌的用户评分的min、max、avg等值。
GET /hotel/_search
{size: 0,aggs: { // 定义聚合brandAgg: { // 给聚合起个名字terms: { // 聚合的类型按照品牌值聚合所以选择termfield: brand,order: { # 排序scoreAgg.avg: desc},size: 20},aggs: { #是brands聚合的子聚合也就是对分组后对每组分别计算score_stats: { #聚合名称“stats”: { #聚合类型这里的stats可以同时计算min、max、avg等field: score #聚合字段这里是score}}}}}
}三RestClient实现聚合
1、桶聚合
//1、创建request对象
SearchRequest request new SearchRequest(hotel);
//2、DSL组装
request.source().size(0);
request.source().aggregation(AggregationBuilders.term(brand_agg).field(brand).size(20)
);//3、发起请求
SearchResponse response client.search(request, RequestOptions.DEFAULT);//4、解析结果
Aggregations aggregations response.getAggregations();//5、根据名称获取聚合结果
Terms brandTerms aggregations.get(brand_agg);//6、获取桶
List? extends Terms.Bucket buckets brandTerms.getBuckets();//7、遍历
for (Terms.Bucket bucket : buckets) {//获取品牌信息String brandName bucket.getKeyAsString();
} 二、自动补全
一拼音分词器
1、离线安装拼音分词器 2、重启ES即可
二自定义分词器
1、直接使用拼音分词器的问题
拼音分词器不分词只分拼音每一个字都形成了拼音没有汉字
2、分词器的组成
character filters 在tokenizer之前对文本进行处理。例如删除字符、替换字符。tokenizer 将文本按照一定规则切割词条term。例如keyword、ik_smarttokenizer filter 将tokenizer输出的词条做进一步处理。例如大小写转换、同义词处理、拼音处理。
3、自定义实现结构
在创建索引库时 通过settings来配置自定义的analyzer分词器
PUT /test
{settings: { #设置配置analysis: { #解析组analyzer: { #自定义解析器my_analyzer: { #分词器名称按照character 》 tokenizer 》 filter 顺序进行配置tokenizer: ik_max_word,filter: pinyin}}}}
}拓展自定义分词器
PUT /test
{settings: { #设置配置analysis: { #解析组analyzer: { #自定义解析器my_analyzer: { #分词器名称按照character 》 tokenizer 》 filter 顺序进行配置tokenizer: ik_max_word,filter: py}},filter: { #自定义tokenizer filterpy: { #过滤器名称type: pinyin, # 过滤器类型设置为pinyinkeep_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 # 在搜索时使用中文分词器}}
}三自动补全查询
ES 提供 Completion Suggester 查询来实现自动补全功能。 这个查询会匹配以用户输入内容开头的词条并返回。 为了提高补全查询的效率对于文档中字段的类型有一些约束
参与补全查询的字段必须是completion类型字段的内容一般是用来补全多个词条形成的数组
#创建索引库
PUT test
{maapings: {properties: {title: {type: completion}}}
}# 示例数据
POST test/_doc
{title: [Sony, WH-1000XM3]
}
POST test/_doc
{title: [SK-II, PITERA]
}
POST test/_doc
{title: [Nintendo, switch]
}查询示例
GET /test/_search
{suggest: {title_suggest: {text: s, # 关键字completion: {field: title, # 补全查询的字段skip_duplicates: true, # 跳过重复的size: 10 # 获取前10条结果}}}
}四RestClient实现自动补全
//1、准备请求
SearchRequest request new SearchRequest(hotel);//2、请求参数
request.source().suggest(new SuggestBuilder().addSuggestion(mySuggestion, SuggestBuilders.completionSuggestion(title).prefix(h).skipDuplicates(true).size(10)
));//3、发送请求
client.search(request, RequestOptions.DEFAULT);//4、解析结果
Suggest suggest response.getSuggest();//5、根据名称获取补全结果
CompletionSuggestion suggestion suggest.getSuggestion(title_suggest);//6、获取options并遍历
for (CompletionSuggestion.Entry.Option option : suggestion.getOptions()){//获取option的textString text option.getText().string();
}三、数据同步
ES的数据来自数据库而数据库数据发生改变时ES也必须改变这个就是ES与数据库的数据同步。
在微服务中负责 数据操作业务 与 数据搜索业务 可能会出现在两个不同的微服务中数据同步如何实现
一数据同步思路
方式一同步调用
新增数据 》 数据管理业务直接写入数据库 》 调用更新索引库接口 》 数据搜索服务更新ES
优点 实现简单粗暴缺点 数据耦合业务耦合性能下降。
方式二异步通知现阶段最为推荐的一种方式
新增数据 》 数据管理业务直接写入数据库并给MQ发送消息 》 MQ搜索服务订阅 》 数据搜索服务更新ES
优点 低耦合实现难度一般缺点 依赖mq的可靠性
方式三监听binlog
新增数据 》 数据管理业务直接写入mysql数据库mysql数据库监听binlog库 》 canal中间件通知搜索服务数据变更 》 数据搜索服务更新ES
优点 完全解除服务间的耦合缺点 开启binlog增加数据库负担实现复杂度高
二实现ES与数据库数据同步
我们采用的是异步通知的方式进行数据同步
实现数据同步
声明交换机queueRoutingKey在admin中的增删改业务中完成消息发送完成消息监听并更新ES数据