solr快速上手:聚合分组查询|嵌套分组指南(十二)

0. 引言

solr作为搜索引擎经常用于各类查询场景,我们之前讲解了solr的查询语法,而除了普通的查询语法,有时我们还需要实现聚合查询来统计一些指标,所以今天我们接着来查看solr的聚合查询语法

1. 常用聚合查询语法

以下演示我们基于之前创建的核心数据进行,可以参考专栏之前的文章

核心字段结构如下:

order_no : 订单号
address: 地址
product_name: 商品
status: 状态
labels: 标签
remarks: 备注

1.1 group 分组查询

1.1.1 简介

group用于实现简单的聚合分组查询、数值计算等

官网文档:https://solr.apache.org/guide/8_2/result-grouping.html

1.1.2 参数

  • group: 设置为true后,查询按分组显示,group:true
  • group.field: 根据哪个字段设置分组,配合group:true使用
q=*:*&group=true&group.field=product_name

在这里插入图片描述

  • group.limit:限制返回的docs条数,默认为1,如上所示的示例中,我们发现,每个分组不仅返回的分组数,也返回了命中的详细数据,有的时候我们不需要详细数据,这时就可以将group.limit设置为0来控制返回条数
q=*:*&group=true&group.field=product_name&group.limit=0

在这里插入图片描述

  • group.func: 根据函数计算出来的值进行分组,函数支持:求和sum,最小值min,最大值max
q=*:*&group=true&group.func=sum(status)

在这里插入图片描述

  • group.query:根据查询条件进行分组。比如将数据按照0<=id<=2, 3<=id<=5, 6<=id<=20进行分组
q=*:*&group=true&group.query=id:[0 TO 2]&group.query=id:[3 TO 5]&group.query=id:[6 TO 20]

在这里插入图片描述

  • group.format, 支持两个值:grouped和simple,默认为grouped, 按分组结果展示,如果设置为simple,则会将匹配的结果按平面列表展示,具体可见下图
q=*:*&group=true&group.field=product_name&group.format=simple
q=*:*&group=true&group.field=product_name&group.format=grouped

在这里插入图片描述

  • group.main,是否将第一个字段分组的结果作为返回数据的主结果集,有点类似于group.format=simple (以下解释暂为个人理解,待深入验证,可能存在误解,仅供参考)
q=*:*&group=true&group.field=product_name&group.main=true

在这里插入图片描述
多个分组条件时,显示的就是按照优先级排序后的第一个分组条件的结果详情列表

这里满足group.field=status分组的列表个数是10个,满足group.query:id[0 TO 4]的是4个,因为排序下来group.query:id[0 TO 4]是第一个分组结果集,所以返回的是4个
在这里插入图片描述

  • group.sort:每个分组内文档的排序方式,如下所示,根据status分组,每个分组内docs返回根据id逆序
q=*:*&group=true&group.field=status&group.sort=id desc&group.limit=5

在这里插入图片描述

  • group.offset:每个分组返回的docs的起点位位置,如下所示,设置group.offset=6,则从id>6后的数据开始显示
q=*:*&group=true&group.field=status&group.limit=4&group.offset=6

在这里插入图片描述

  • group.ngroups:是否显示分组数,默认为false
q=*:*&group=true&group.field=status&group.limit=4&group.ngroups=true

在这里插入图片描述

  • group.truncate,默认为false, 当为ture时,facet计数将基于每组中与查询条件相关度高的文档,而不是全部文档(研究中,暂未找到合适案例)
  • row:显示分桶数量,默认为10,有时我们分桶数据不止10个,需要增加显示,可以用row参数设置,相当于sql中的limit
  • start:从第几个开始,与row配合,共同组成分页显示
  • sort: 根据指定字段进行组间排序,有该字段的桶也将排序在前。与group.sort的区别是:sort用于控制组间排序,group.sort控制组内排序。
q=*:*&group=true&group.field=product_name&group.limit=10&rows=10&sort=status desc

在这里插入图片描述

  • group.cache.percent:分组搜索结果占用堆内存的百分比,当设置大于0时即开启搜索结果缓存,数值越大允许缓存占用的堆内存大小越大。根据官方的解释,该配置会提升布尔、通配符、模糊查询的效率,但却会降低普通查询效率

1.1.3 案例

  • 1、统计销量排行前5的商品

思路:在开始之前我们需要注意,单纯使用group实际上是无法完成此题的,因为group不支持按照各个桶数量进行排序,需要使用facet,我们将在下文讲解,但如果只使用group的话,排序需要借助java代码再来实现

DSL:

q=*:*&group=true&group.field=product_name&group.limit=0&rows=100

查询结果:
在这里插入图片描述

solrJ客户端代码:

@RestController
@RequestMapping("group")
@AllArgsConstructor
public class GroupSearchController {private final HttpSolrClient solrClient;@GetMapping("sellTopFive")public Map<String, Long> sellTopFive() {Map<String, Long> result = new HashMap<>();// 设置查询条件SolrQuery query = new SolrQuery().setQuery("*:*").setRows(100);// 设置分组条件query.set(GroupParams.GROUP, true).set(GroupParams.GROUP_FIELD, "product_name").set(GroupParams.GROUP_LIMIT, 0);try {QueryResponse response = solrClient.query("orders",query);GroupResponse groupResponse = response.getGroupResponse();List<GroupCommand> values = groupResponse.getValues();GroupCommand group = values.get(0);List<Group> productGroups = group.getValues();for (Group productGroup : productGroups) {result.put(productGroup.getGroupValue(), productGroup.getResult().getNumFound());}// 根据数量逆序排序,截取前5return result.entrySet().stream().sorted(Map.Entry.comparingByValue(Comparator.reverseOrder())).limit(5).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));} catch (SolrServerException | IOException e) {e.printStackTrace();return result;}}
}

spring-data-solr客户端代码:

@RestController
@RequestMapping("group")
@AllArgsConstructor
public class GroupSearchController {private final SolrTemplate solrTemplate;@GetMapping("sellTopFive2")public Map<String, Long> sellTopFive2() {Map<String, Long> result = new HashMap<>();// 设置分组条件Field field = new SimpleField("product_name");SimpleQuery groupQuery = new SimpleQuery(new SimpleStringCriteria("*:*")).setRows(100);GroupOptions groupOptions = new GroupOptions().addGroupByField(field).setLimit(0);groupQuery.setGroupOptions(groupOptions);try {GroupPage<Orders> page = solrTemplate.queryForGroupPage("orders", groupQuery, Orders.class);GroupResult<Orders> fieldGroup = page.getGroupResult(field);List<GroupEntry<Orders>> content = fieldGroup.getGroupEntries().getContent();for (GroupEntry<Orders> ordersGroupEntry : content) {result.put(ordersGroupEntry.getGroupValue(), ordersGroupEntry.getResult().getTotalElements());}// 根据数量逆序排序,截取前5return result.entrySet().stream().sorted(Map.Entry.comparingByValue(Comparator.reverseOrder())).limit(5).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));}catch (Exception e){e.printStackTrace();return result;}}
}

执行结果:
在这里插入图片描述

  • 2、各个标签的订单数

思路:此题与上述的区别,就在于分组的字段labels是Nested类型,但group分组不支持Nested字段的分组,因此使用group是无法实现的,我们将在Facet中讲解用法

在这里插入图片描述

1.2 facet 分组查询

1.2.1 简介

facet与group有些相近,都是做分组查询的,但是facet允许用户再对结果集进行二次处理,也就是支持嵌套聚合,也可以对分组数量进行排序、过滤等,group会返回每个分组详细的数据列表docs,而facet并不会返回每个分组的docs,只是返回一个统计指标。facet与group可以结合使用。

官方文档:https://solr.apache.org/guide/8_2/faceting.html

facet分组查询支持4大类型:
facet.query: 自定义查询分组
facet.field:按字段分组
facet.range: 范围查询分组
facet.date:日期分组

1.2.2 参数

  • facet: 设置为true则开启facet分组查询
  • facet.field:以什么字段作为分组统计字段,如下所示,可以看到与group明显的区别,是没有返回每个分组的docs了。
q=*:*&facet=true&facet.field=product_name

在这里插入图片描述
与group.field一样,也可以设置多个分组字段

q=*:*&facet=true&facet.field=product_name&facet.field=status

在这里插入图片描述

  • facet.pivot:多字段嵌套分组,如上所示的分组是分割开单独分组的,某些场景下我们需要嵌套分组,基于前一个分组结果继续做分组,这就需要用到facet.pivot, 比如,统计每种状态下各个商品的个数
q=*:*&facet=true&facet.pivot=status,product_name

在这里插入图片描述

  • facet.pivot.mincount,嵌套分组显示最小数量,有时我们希望显示的分组是具有一定数量的,数量比较小的就不要显示了,这就需要用到facet.pivot.mincount,默认值为1
q=*:*&facet=true&facet.pivot=status,product_name&facet.pivot.mincount=2

在这里插入图片描述

  • facet.mincount:分组最小数量,与facet.pivot.mincount不同的是,这个是控制facet.field产生的普通分组

  • facet.query: 根据查询条件来进行分类,可以设置多个facet.query,来实现自定义的分组统计

q=*:*&facet=true&facet.query=status:1&facet.query=status:2

在这里插入图片描述

  • facet.prefix:分组字段的值满足该前缀的才会被统计
q=*:*&facet=true&facet.field=product_name&facet.prefix=小米

在这里插入图片描述

  • facet.contains:分组字段包含该值的才会被分组统计
q=*:*&facet=true&facet.field=product_name&facet.contains=小米

在这里插入图片描述

  • facet.contains.ignoreCase: 与facet.contains的区别就是不区分大小写
  • facet.matches:分组字段值满足该正则表达式的才会被分组统计(未实际使用,待验证)
q=*:*&facet=true&facet.field=product_name&facet.matches=米*

facet.sort:分组排序条件,允许设置两个值:count 按照每个桶的数量逆序排序、index:按照各分组桶名字符排序,默认为count

q=*:*&facet=true&rows=0&facet.field=product_name&facet.sort=index

在这里插入图片描述

  • facet.limit:返回的桶数量,默认100
q=*:*&facet=true&rows=0&facet.field=product_name&facet.limit=5

在这里插入图片描述

  • facet.offset:从第几个桶开始显示
q=*:*&facet=true&rows=0&facet.field=product_name&facet.limit=5&facet.offset=2

在这里插入图片描述

  • facet.missing:文档数据(每一行数据)中分组字段facet.field没有值的是否统计,默认为false
  • facet.method:指定分组算法,支持三种分组算法:fc, enum, filterCache,默认为fc。详细解释可见官方文档
  • facet.threads:分组查询创建的线程数,最大值Integer.MAX_VALUE,最小值0,这时只会创建一个主线程

范围查询分组

  • facet.range: 定义范围查询的字段
  • facet.range.start:范围查询的最小值
  • facet.range.end:范围查询的最大值
  • facet.range.gap:范围查询的步长(每组间隔)
  • facet.range.hardend:是否将facet.range.end最为最后一组的上限,值为true/false,默认为false,false时将会把最后一组上限设置为大于facet.range.end的最小可能上限。比如facet.range.end=4,文档中大于4的还有5、6、7,则如果为false时会取5最为上限
q=*:*&facet=true&rows=0&facet.range=status&facet.range.start=1&facet.range.end=5&facet.range.gap=3&facet.range.hardend=true

在这里插入图片描述
也可以实现按日期月份分组的效果,%2B表示URL中的+

q=*:*&facet=true&rows=0&facet.range=create_time&facet.range.start=NOW/MONTH-12MONTH&facet.range.end=NOW/MONTH&facet.range.gap=%2B1MONTH

在这里插入图片描述

  • facet.range.include:指定每个区间中,是否包含上下限

lower:所有区间都包含其下限
upper:所有区间都包含其上限
edge:即使未指定相应的上限/下限选项,第一个和最后一个间隙范围也包括其边缘边界(第一个间隙范围较低,最后一个间隙范围较高)
outer:第一个或最后一个区间包含其边界
all:包含上述所有选项

  • facet.range.other:其他区间统计规则,值为before、after、between、none、all,默认为none

before:对start之前的值做统计
after:对end之后的值做统计
between:对start至end之间所有值做统计,如果hardend为true的话,那么该值就是各个时间段统计值的和
none:表示该项禁用
all:表示before,after,all都会统计

如果指定了多个范围字段的话,通过facet.<field_id>的形式区分

facet.range=price&facet.range=age&facet.range=lastModified_dt
&f.price.facet.range.end=1000.0
&f.age.facet.range.start=99
&f.lastModified_dt.facet.range.end=NOW/DAY+30DAYS

指定间隔分组

  • facet.interval:间隔统计字段
  • facet.interval.set:间隔统计指定区间
q=*:*&facet=true&rows=0&facet.interval=status&facet.interval.set=(0,1]&facet.interval.set=[1,3]

在这里插入图片描述
时间类型分组

  • facet.date:该参数表示需要进行按时间分组的字段名,与facet.field一样,该参数可以设置多个
  • facet.date.start:起始时间
  • facet.date.end:结束时间
  • facet.date.gap:时间间隔.如果start为2023-01-01,end为2024-01-01,gap设置为+1MONTH则表示间隔1个月,那么将会把这段时间划分为12个间隔段
  • facet.date.hardend :与facet.range.hardend类似
    facet.date.other 其他区间统计规则,与facet.range.other类似

1.2.3 案例

  • 1、统计销量排行前5的商品

facet中默认就根据每组桶数逆序排序,无需特殊指定,如果需要根据桶名排序的,修改facet.sort=index即可

q=*:*&facet=true&rows=0&facet.field=product_name&facet.limit=5

在这里插入图片描述
SolrJ实现代码:

@RestController
@RequestMapping("facet")
@AllArgsConstructor
public class FacetSearchController {private final HttpSolrClient solrClient;/*** 统计销量排行前5的商品* @return*/@GetMapping("sellTopFive")public Map<String, Long> sellTopFive(){Map<String, Long> result = new HashMap<>();// 设置查询条件SolrQuery query = new SolrQuery().setQuery("*:*").setRows(0);// 设置分组条件query.set(FacetParams.FACET, true).set(FacetParams.FACET_FIELD, "product_name").set(FacetParams.FACET_LIMIT, 5);try {QueryResponse response = solrClient.query("orders",query);FacetField facetFields = response.getFacetField("product_name");for (FacetField.Count value : facetFields.getValues()) {result.put(value.getName(), value.getCount());}// 根据value排序, 若无需排序则可删除此段return result.entrySet().stream().sorted(Map.Entry.comparingByValue(Comparator.reverseOrder())).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));} catch (SolrServerException | IOException e) {e.printStackTrace();}return result;}
}

spring-data-solr代码

@GetMapping("sellTopFive2")public Map<String, Long> sellTopFive2() {Map<String, Long> result = new HashMap<>();// 设置分组条件Field field = new SimpleField("product_name");SimpleFacetQuery query = new SimpleFacetQuery(new SimpleStringCriteria("*:*")).setRows(0);FacetOptions facetOptions = new FacetOptions().addFacetOnField(field).setFacetLimit(5);query.setFacetOptions(facetOptions);try {FacetPage<Orders> page = solrTemplate.queryForFacetPage("orders", query, Orders.class);Page<FacetFieldEntry> pageResult = page.getFacetResultPage("product_name");List<FacetFieldEntry> content = pageResult.getContent();for (FacetFieldEntry facetFieldEntry : content) {result.put(facetFieldEntry.getValue(), facetFieldEntry.getValueCount());}// 根据数量逆序排序return result.entrySet().stream().sorted(Map.Entry.comparingByValue(Comparator.reverseOrder())).limit(5).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));}catch (Exception e){e.printStackTrace();return result;}}

在这里插入图片描述

  • 2、各个标签的订单数

facet.field支持Nested类型的字段,直接查询即可,这里标签分类没超过10个,就未设置rows了

q=*:*&facet=true&rows=0&facet.field=labels

在这里插入图片描述
SolrJ代码:

@GetMapping("labelCount")public Map<String, Long> labelCount(){Map<String, Long> result = new HashMap<>();// 设置查询条件SolrQuery query = new SolrQuery().setQuery("*:*").setRows(0);// 设置分组条件query.set(FacetParams.FACET, true).set(FacetParams.FACET_FIELD, "labels").set(FacetParams.FACET_LIMIT, 100);try {QueryResponse response = solrClient.query("orders",query);FacetField facetFields = response.getFacetField("labels");for (FacetField.Count value : facetFields.getValues()) {result.put(value.getName(), value.getCount());}} catch (SolrServerException | IOException e) {e.printStackTrace();}return result;}
  • 3、统计近一年内每月的畅销商品TOP5

思路:我们要统计每月的商品中的TOP5,很明显要根据月份+商品进行分组,这属于嵌套分组,因此要使用到facet.pivot。我们有一个创建日期字段create_time。实现方式分为如下几种:
1、创建一个冗余一个月份字段month,用于此处的嵌套查询,这种要修改schema_manage且要重新加载索引,这里solr不支持类似es的动态字段还是不太方便,此方案如果索引数据量较大,重新加载索引影响线上使用,可以考虑直接新建一个核心,待同步完成,直接将查询核心切换到新的核心,然后删除旧核心
2、先按照年月份进行时间分组,然后客户端代码中循环对有值的年份月最为query条件,分别按商品进行分组,得到每个年月的商品分组详情,这种方式的弊端是网络IO较多,如果查询对耗时有较高要求可能不能满足
3、如果数据本身是按照天汇总的,及create_time格式是YYYY-MM-dd,没有到秒,或者一天的数据量并不大,那么可以先按照facet.pivot=create_time,product_name的形式按天把数据汇总出来,然后在java代码把数据再按月份进行二次计算得出,适用于本身按天数据量不大的场景,近一年的话按天分桶也就365个,相对还能接受
4、最友好的方式,就是能有将日期转换为月份的函数,类似month(create_time),然后facet.pivot=month(create_time),product_name来实现统计,但目前我还没有找到相关函数,solr本身好像也不支持这种操作,对于聚合上的支持还是和es有比较大的差距,如果后续大家有更好的方式可以留言告知,互相学习

这里因为我的数据量并不大,就直接采用方式3来实现了

q=*:*&facet=true&rows=0&facet.pivot=create_time,product_name&facet.sort=index

SolrJ客户端代码:

@GetMapping("productTopFiveMonthlyNearYear")public Map<String, Map<String, Integer>> productTopFiveMonthlyNearYear(){Map<String, Map<String, Integer>> result = new TreeMap<>();// 设置查询条件SolrQuery query = new SolrQuery().setQuery("*:*").setRows(0);// 设置分组条件query.set(FacetParams.FACET, true).set(FacetParams.FACET_PIVOT, "create_time,product_name").set(FacetParams.FACET_SORT, FacetParams.FACET_SORT_INDEX);try {QueryResponse response = solrClient.query("orders",query);List<PivotField> pivotFields = response.getFacetPivot().get("create_time,product_name");// 组装返回结果,按年月分组for (PivotField field : pivotFields) {SimpleDateFormat format = new SimpleDateFormat("yyyyMM");String month = format.format(field.getValue());if(!result.containsKey(month)){Map<String, Integer> monthMap = new LinkedHashMap<>();for (PivotField pivotField : field.getPivot()) {monthMap.put(pivotField.getValue().toString(), pivotField.getCount());}result.put(month, monthMap);}else{Map<String, Integer> monthMap = result.get(month);for (PivotField pivotField : field.getPivot()) {String productName = pivotField.getValue().toString();if(!monthMap.containsKey(productName)){monthMap.put(productName, pivotField.getCount());}else{// 重复的商品 叠加销量monthMap.put(productName,monthMap.get(productName) + pivotField.getCount());}}}}// 每月商品截取前5for (String month : result.keySet()) {Map<String, Integer> sortMap = result.get(month).entrySet().stream().sorted(Map.Entry.comparingByValue(Comparator.reverseOrder())).limit(5).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));result.put(month, sortMap);}} catch (SolrServerException | IOException e) {e.printStackTrace();}return result;}

### 1.3.3 案例![

1.3 拓展:stats 查询

当需要统计某字段的平均、最大、最小等统计值时,可以结合stats来查询,具体用法可查看官网文档

官网文档:https://solr.apache.org/guide/8_2/the-stats-component.html

在这里插入图片描述

2. 总结

如上,我们对于solr实现分组聚合查询的讲解就到此结束了,可以看出group适合与简单的分组查询,而facet则更加适合场景复杂的分组查询。具体选型还要根据大家的业务场景而定

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/43875.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

面试题-React(一):React是什么?它的主要特点是什么?

探索React&#xff1a;前端开发中的重要角色与主要特点 引言&#xff1a; 在现代前端开发领域&#xff0c;React已经成为最受欢迎和广泛使用的JavaScript库之一。它由Facebook开发并于2013年首次发布。随着时间的推移&#xff0c;React在开发社区中获得了强大的支持和认可。本…

画质提升+带宽优化,小红书音视频团队端云结合超分落地实践

随着视频业务和短视频播放规模不断增长&#xff0c;小红书一直致力于研究&#xff1a;如何在保证提升用户体验质量的同时降低视频带宽成本&#xff1f; 在近日结束的音视频技术大会「LiveVideoStackCon 2023」上海站中&#xff0c;小红书音视频架构视频图像处理算法负责人剑寒向…

基于注意力神经网络的深度强化学习探索方法:ARiADNE

ARiADNE:A Reinforcement learning approach using Attention-based Deep Networks for Exploration 文章目录 ARiADNE:A Reinforcement learning approach using Attention-based Deep Networks for Exploration机器人自主探索(ARE)ARE的传统边界法非短视路径深度强化学习的方…

Python | Package | Python的三种包安装方式(pip/whl/tar.gz)

文章目录 PIP 安装与卸载Source 安装与卸载Whell 安装与卸载 PIP 安装与卸载 pip install xxx pip install xxxversion_numberpip install captcha pip install captcha0.4# XXX/anaconda3/envs/py373/lib/python3.7/site-packages pip uninstall captchaSource 安装与卸载 p…

C++音乐播放系统

C音乐播放系统 音乐的好处c发出声音乐谱与赫兹对照把歌打到c上 学习c的同学们都知道&#xff0c;c是一个一本正经的编程语言&#xff0c;因该没有人用它来做游戏、做病毒、做…做…做音乐播放系统吧&#xff01;&#xff01; 音乐的好处 提升情绪&#xff1a;音乐能够影响我们…

java语言B/S架构云HIS医院信息系统源码【springboot】

医院云HIS全称为基于云计算的医疗卫生信息系统( Cloud- Based Healthcare Information System)&#xff0c;是运用云计算、大数据、物联网等新兴信息技术&#xff0c;按照现代医疗卫生管理要求&#xff0c;在一定区域范围内以数字化形式提供医疗卫生行业数据收集、存储、传递、…

动手学深度学习--基础知识上篇

&#x1f388;动手学deep learning ☁️本专栏会定期更新关于动手学深度学习的每章知识点的讲解&#xff0c;题目答案 &#x1f47b;如果喜欢&#xff0c;欢迎点赞&#xff0c;收藏 动手学深度学习-预备知识篇 线性代数篇 1-3题讲解 证明一个矩阵 A \mathbf{A} A的转置的转置…

安卓手机跑 vins slam (2)

既然选择把vins的代码移植到新工程&#xff0c;那么就需要先确定自己电脑的Android Studio的C开发环节是OK的&#xff0c;可以通过创建C的示例工程&#xff0c;能正常跑通做验证。 选择Native C 需要选择用C哪个版本&#xff0c; 这里通过百度搜索&#xff0c;slam 编译需要C 1…

电脑提示丢失(或找不到)msvcp120.dll解决办法

msvcp140.dll是Microsoft Visual C Redistributable的一部分&#xff0c;它是Windows操作系统中的一个动态链接库文件。这个文件包含了许多C标准库函数的实现&#xff0c;对于一些依赖C标准库的应用程序来说&#xff0c;msvcp140.dll是非常重要的。msvcp140.dll的主要用途是提供…

热电联产在综合能源系统中的选址定容研究(matlab代码)

目录 1 主要内容 目标函数 程序模型 2 部分代码 3 程序结果 1 主要内容 该程序参考《热电联产在区域综合能源系统中的定容选址研究》&#xff0c;主要针对电热综合能源系统进行优化&#xff0c;确定热电联产机组的位置和容量&#xff0c;程序以33节点电网和17节点热网为例…

CI/CD入门(二)

CI/CD入门(二) 目录 CI/CD入门(二) 1、代码上线方案 1.1 早期手动部署代码1.2 合理化上线方案1.3 大型企业上线制度和流程1.4 php程序代码上线的具体方案1.5 Java程序代码上线的具体方案1.6 代码上线解决方案注意事项2、理解持续集成、持续交付、持续部署 2.1 持续集成2.2 持续…

小白到运维工程师自学之路 第七十五集 (Kubernetes 企业级高可用部署)2

8、添加master节点 在k8s-master2和k8s-master3节点创建文件夹 mkdir -p /etc/kubernetes/pki/etcd在k8s-master1节点执行 从k8s-master1复制密钥和相关文件到k8s-master2和k8s-master3 scp /etc/kubernetes/admin.conf root192.168.77.15:/etc/kubernetes scp /etc/kubernet…

UAF释放后重引用原理

原地址&#xff1a;https://blog.csdn.net/qq_31481187/article/details/73612451 原作者代码是基于linux系统的演示代码&#xff0c;因为windows和Linux 内存管理机制上略有不同&#xff0c;该程序在Windows需要稍微做些改动。 Windows上执行free释放malloc函数分配的内存后…

Docker碎碎念

docker和虚拟机的区别 虚拟机&#xff08;VM&#xff09;是通过在物理硬件上运行一个完整的操作系统来实现的。 每个虚拟机都有自己的内核、设备驱动程序和用户空间&#xff0c;它们是相互独立且完全隔离的。 虚拟机可以在不同的物理服务器之间迁移&#xff0c;因为它们是以整…

淘宝搜索店铺列表API:关键字搜索店铺信息 获取店铺主页 店铺所在地 服务评级

接口名称&#xff1a;item_search_seller 基本功能介绍 该API可以通过传入关键字&#xff0c;获取到淘宝商城的店铺列表&#xff0c;支持翻页显示。指定参数page获取到指定页的数据。返回的店铺信息包括&#xff1a;店铺名、店铺ID、店铺主页、宝贝图片、掌柜名字、店铺所在地…

idea2023 springboot2.7.5+mybatisplus3.5.2+jsp 初学单表增删改查

创建项目 修改pom.xml 为2.7.5 引入mybatisplus 2.1 修改pom.xml <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.2</version></dependency><!--mysq…

11. Vuepress2.x 关闭夜间模式

修改 docs/.vuepress/config.ts 配置文件 设置 themeConfig.darkMode属性详见 官网 module.exports {host: localhost, // ipport: 8099, //端口号title: 我的技术站, // 设置网站标题description: 描述&#xff1a;我的技术站,base: /, //默认路径head: [// 设置 favor.ico&a…

聊聊看React和Vue的区别

Vue 更适合小项目&#xff0c;React 更适合大公司大项目&#xff1b; Vue 的学习成本较低&#xff0c;很容易上手&#xff0c;但项目质量不能保证...... 真的是这样吗&#xff1f;借助本篇文章&#xff0c;我们来从一些方面的比较来客观的去看这个问题。 论文档的丰富性 从两个…

源于传承,擎领未来,新架构、新工艺下的“换心工程”——金融电子化访中电金信副总经理、研究院院长况文川

当前&#xff0c;商业银行的经营环境正在发生着深刻而复杂的变化&#xff0c;在深化改革主旋律的指引下&#xff0c;数字化转型已成为我国商业银行普遍认同、广泛采用的战略性举措。核心系统作为承载银行业务的关键支柱系统&#xff0c;一直是各银行在金融科技建设中重点关注和…

每日一题——接雨水(单调栈)

接雨水——单调栈 题目链接 单调递增的栈还是单调递减的栈 我们常说的**”积水成洼“**&#xff0c;指的就是说&#xff1a;当两边地势高于中间的地势时&#xff0c;中间的区域就成了洼地&#xff0c;也就可以积水了。 这一题就是如此&#xff0c;我们需要通过一个栈来记录数…