微服务实战——ElasticSearch(保存)

商品上架——ElasticSearch(保存)

0.商城架构图

1.商品Mapping

分析:商品上架在 es 中是存 sku 还是 spu ?

  1. 检索的时候输入名字,是需要按照 sku 的 title 进行全文检索的
  2. 检索使用商品规格,规格是 spu 的公共属性,每个 spu 是一样的
  3. 按照分类 id 进去的都是直接列出 spu 的,还可以切换。
  4. 我们如果将 sku 的全量信息保存到 es 中(包括 spu 属性)就太多量字段了。
  5. 我们如果将 spu 以及他包含的 sku 信息保存到 es 中,也可以方便检索。但是 sku 属于spu 的级联对象,在 es 中需要 nested 模型,这种性能差点。
  6. 但是存储与检索我们必须性能折中。
  7. 如果我们分拆存储,spu 和 attr 一个索引,sku 单独一个索引可能涉及的问题。
    1. 检索商品的名字,如“手机”,对应的 spu 有很多,我们要分析出这些 spu 的所有关联属性,再做一次查询,就必须将所有 spu_id 都发出去。假设有 1 万个数据,数据传输一次就10000*4=4MB;并发情况下假设 1000 检索请求,那就是 4GB 的数据,传输阻塞时间会很长,业务更加无法继续。
    2. 所以,我们如下设计,这样才是文档区别于关系型数据库的地方,宽表设计,不能去考虑数据库范式。
    3. 向ES添加商品属性映射

向ES添加商品属性映射

PUT product
{"mappings":{"properties": {"skuId":{"type": "long"},"spuId":{"type": "keyword"},"skuTitle": {"type": "text","analyzer": "ik_smart"},"skuPrice": {"type": "keyword"},"skuImg":{"type": "keyword","index": false,"doc_values": false},"saleCount":{"type":"long"},"hasStock": {"type": "boolean"},"hotScore": {"type": "long"},"brandId": {"type": "long"},"catalogId": {"type": "long"},"brandName": {"type": "keyword","index": false,"doc_values": false},"brandImg":{"type": "keyword","index": false,"doc_values": false},"catalogName": {"type": "keyword","index": false,"doc_values": false},"attrs": {"type": "nested","properties": {"attrId": {"type": "long"},"attrName": {"type": "keyword","index": false,"doc_values": false},"attrValue": {"type": "keyword"}}}}}
}

index :

默认 true ,如果为 false ,表示该字段不会被索引,但是检索结果里面有,但字段本身不能

当做检索条件。

doc_values :

默认 true ,设置为 false ,表示不可以做排序、聚合以及脚本操作,这样更节省磁盘空间。

还可以通过设定 doc_values 为 true , index 为 false 来让字段不能被搜索但可以用于排序、聚合以及脚本操作:

spu在es中的存储模型分析总结

如果每个sku都存储规格参数,会有冗余存储,因为每个spu对应的sku的规格参数都一样。但是如果将规格参数单独建立索引会出现检索时出现大量数据传输的问题,会阻塞网络因此我们选用第一种存储模型,以空间换时间。

2.上架细节

上架是将后台的商品放在 es 中可以提供检索和查询功能:

  1. hasStock:代表是否有库存。默认上架的商品都有库存。如果库存无货的时候才需要更新一下 es
  2. 库存补上以后,也需要重新更新一下 es
  3. hotScore 是热度值,我们只模拟使用点击率更新热度。点击率增加到一定程度才更新热度值。
  4. 下架就是从 es 中移除检索项,以及修改 mysql 状态

商品上架步骤:

  1. 先在 es 中按照之前的 mapping 信息,建立 product 索引。
  2. 点击上架,查询出所有 sku 的信息,保存到 es 中
  3. es 保存成功返回,更新数据库的上架状态信息

3.数据一致性

  1. 商品无库存的时候需要更新 es 的库存信息
  2. 商品有库存也要更新 es 的信息

4.ES中的数组扁平化

关于“nested”,Nested datatype | Elasticsearch Guide [7.6] | Elastic

ES中数组的扁平化处理:

对象数组的扁平化:

内部对象字段数组的工作方式与您预期的不同。Lucene没有内部对象的概念,所以Elasticsearch将对象层次结构简化为字段名和值的简单列表。例如,以下文件:

PUT my_index/_doc/1
{"group" : "fans","user" : [ {"first" : "John","last" :  "Smith"},{"first" : "Alice","last" :  "White"}]
}

在内部将转换成一个文档,看起来是这样的:

{"group" :        "fans","user.first" : [ "alice", "john" ],"user.last" :  [ "smith", "white" ]
}

查询my_index的映射

GET my_index/_mapping
{"my_index" : {"mappings" : {"properties" : {"group" : {"type" : "text","fields" : {"keyword" : {"type" : "keyword","ignore_above" : 256}}},"user" : {"properties" : {"first" : {"type" : "text","fields" : {"keyword" : {"type" : "keyword","ignore_above" : 256}}},"last" : {"type" : "text","fields" : {"keyword" : {"type" : "keyword","ignore_above" : 256}}}}}}}}
}

user.first和user.last字段被平铺成多值字段,alice和white之间的关联也丢失了。在查询alice和smith时,这个文档将将发生错误的匹配

GET my_index/_search
{"query": {"bool": {"must": [{ "match": { "user.first": "Alice" }},{ "match": { "user.last":  "Smith" }}]}}
}

所想要的只是user.first="Alice",user.last="Smith",本身是查询不到的,但是却查询出来了两条结果:

{"took" : 49,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 1,"relation" : "eq"},"max_score" : 0.5753642,"hits" : [{"_index" : "my_index","_type" : "_doc","_id" : "1","_score" : 0.5753642,"_source" : {"group" : "fans","user" : [{"first" : "John","last" : "Smith"},{"first" : "Alice","last" : "White"}]}}]}
}

删除“my_index”索引

DELETE my_index

重新创建my_index索引

PUT my_index
{"mappings": {"properties": {"user": {"type": "nested" }}}
}

重新插入数据

PUT my_index/_doc/1
{"group" : "fans","user" : [ {"first" : "John","last" :  "Smith"},{"first" : "Alice","last" :  "White"}]
}

再次查询user.first="Alice",user.last="Smith"时,查询不到数据

GET my_index/_search
{"query": {"bool": {"must": [{ "match": { "user.first": "Alice" }},{ "match": { "user.last":  "Smith" }}]}}
}

查询结果:

{"took" : 1,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 0,"relation" : "eq"},"max_score" : null,"hits" : [ ]}
}

5.商品上架接口实现

商品上架需要在es中保存spu信息并更新spu的状态信息,由于SpuInfoEntity与索引的数据模型并不对应,所以我们要建立专门的vo进行数据传输

1、商品上架接口

接口文档:商品系统 - 20、商品上架

POST /product/spuinfo/{spuId}/up

请求参数

分页数据

响应数据

{
"msg": "success",
"code": 0
}

功能效果

新增“com.cwh.common.to.es.SkuEsModel”类,代码如下:

package com.cwh.common.to.es;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
@Data
public class SkuEsModel {private Long skuId;private Long spuId;private String skuTitle;private BigDecimal skuPrice;private String skuImg;private Long saleCount;private boolean hasStock;private Long hotScore;private Long brandId;private Long catalogId;private String brandName;private String brandImg;private String catalogName;private List attrs;@Datapublic static class Attr{private Long attrId;private String attrName;private String attrValue;}
}

编写商品上架的接口

修改“com.cwh.gulimall.product.controller.SpuInfoController”类,代码如下:

@PostMapping("spuinfo/{spuId}/up")
public R spuUp(@PathVariable("spuId") Long spuId){spuInfoService.up(spuId);return R.ok();
}

修改“com.cwh.gulimall.product.service.SpuInfoService”类,代码如下:

/*** 商品上架** @param spuId*/
void up(Long spuId);

由于每个spu对应的各个sku的规格参数相同,因此我们要将查询规格参数提前,只查询一次

修改“com.cwh.gulimall.product.service.impl.SpuInfoServiceImpl”类,代码如下:

@Override
public void up(Long spuId) {// 1、查出当前spuId对应的sku信息,品牌名字List<SkuInfoEntity> skus = skuInfoService.getSkuBySpuId(spuId);List<Long> skuIdList = skus.stream().map(SkuInfoEntity::getSkuId).collect(Collectors.toList());// 2.1、发送远程调用,库存系统查询是否有库存Map<Long, Boolean> stockMap = null;try {R r = wareFeignService.getSkusHasStock(skuIdList);TypeReference<List<SkuHasStockVo>> typeReference = new TypeReference<List<SkuHasStockVo>>() {};stockMap = r.getData(typeReference).stream().collect(Collectors.toMap(SkuHasStockVo::getSkuId, SkuHasStockVo::getHasStock));} catch (Exception e) {log.error("库存服务查询异常,原因:", e);}// 2.4、查询当前sku的所有可以被用来检索的规格属性List<ProductAttrValueEntity> baseAttrs = productAttrValueService.baseAttrListForSpu(spuId);List<Long> attrIds = baseAttrs.stream().map(attr -> attr.getAttrId()).collect(Collectors.toList());List<Long> searchAttrIds = attrService.selectSearchAttrs(attrIds);Set<Long> idSet = new HashSet<>(searchAttrIds);List<SkuEsModel.Attrs> attrsList = baseAttrs.stream().filter(item -> idSet.contains(item.getAttrId())).map(item -> {SkuEsModel.Attrs attrs1 = new SkuEsModel.Attrs();BeanUtils.copyProperties(item, attrs1);return attrs1;}).collect(Collectors.toList());// 2、封装每个sku的信息Map<Long, Boolean> finalStockMap = stockMap;List<SkuEsModel> upProducts = skus.stream().map(sku -> {// 组装需要的数据SkuEsModel esModel = new SkuEsModel();BeanUtils.copyProperties(sku, esModel);esModel.setSkuPrice(sku.getPrice());esModel.setSkuImg(sku.getSkuDefaultImg());// 2.1、是否有库存 hasStock,hotScoreif (finalStockMap == null) {esModel.setHasStock(true);} else {esModel.setHasStock(finalStockMap.get(sku.getSkuId()));}// 2.2、热度评分。0esModel.setHotScore(0L);// 2.3、查询品牌和分类的名字信息BrandEntity brand = brandService.getById(esModel.getBrandId());esModel.setBrandName(brand.getName());esModel.setBrandImg(brand.getLogo());CategoryEntity category = categoryService.getById(esModel.getCatalogId());esModel.setCatalogName(category.getName());// 2.4、设置检索属性esModel.setAttrs(attrsList);System.out.println("======================esModel" + esModel);return esModel;}).collect(Collectors.toList());// 3、将数据发送给es进行保存R r = searchFeignService.productStatusUp(upProducts);System.out.println("=========================" + r);if (r.getCode() == 0) {//远程调用成功// 3.1、修改当前spu的状态System.out.println("修改当前spu的状态");baseMapper.updateSpuStatus(spuId, ProductConstant.StatusEnum.SPU_UP.getCode());} else {// 远程调用失败// TODO 3.2、重复调用?接口幂等性;重试机制/*** Feign调用流程:* 1、构造请求数据,将对象转为json*      RequestTemplate template = buildTemplateFromArgs.create(argv);* 2、发送请求进行执行(执行成功会解码响应数据)*      executeAndDecode(template)* 3、执行请求会有重试机制*      while(true){*          try{*              executeAndDecode(template);*          }catch(){*              retryer.continueOrPropagate(e);*              throw ex;*              continue;*          }*      }*/}
}
2、查出当前spuId对应的sku信息,品牌名字

修改“com.cwh.gulimall.product.service.SkuInfoService”类,代码如下:

/*** 查出当前spuId对应的sku信息** @param spuId* @return*/
List<SkuInfoEntity> getSkuBySpuId(Long spuId);

修改“com.cwh.gulimall.product.service.impl.SkuInfoServiceImpl”类,代码如下:

@Override
public List<SkuInfoEntity> getSkuBySpuId(Long spuId) {List<SkuInfoEntity> list = this.list(new QueryWrapper<SkuInfoEntity>().eq("spu_id", spuId));return list;
}
3、封装每个sku的信息
3.1、发送远程调用,库存系统查询是否有库存

修改“com.cwh.gulimall.product.feign.WareFeignService”类,代码如下:

package com.cwh.gulimall.product.feign;
import com.cwh.common.utils.R;
import com.cwh.gulimall.product.vo.SkuHasStockVo;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.List;@FeignClient("gulimall-ware")
public interface WareFeignService {/*** 1、R设计的时候可以加上泛型* 2、直接返回我们想要的结果* 3、自己封装返回结果* @param skuIds* @return*/@PostMapping("/ware/waresku/hasStock")R getSkusHasStock(@RequestBody List<Long> skuIds);
}

修改”com.cwh.gulimall.ware.controller.WareSkuController”,代码如下:

/*** 查询sku是否有库存*/
@PostMapping("hasStock")
public R getSkusHasStock(@RequestBody List<Long> skuIds){// sku_id, stockList<SkuHasStockVo> vos = wareSkuService.getSkusHasStock(skuIds);return R.ok().setData(vos);
}

修改”com.cwh.gulimall.ware.service.WareSkuService”类,代码如下:

List getSkusHasStock(List skuIds);  

修改”com.cwh.gulimall.ware.service.WareSkuService”类,代码如下:

@Override
public List<SkuHasStockVo> getSkusHasStock(List<Long> skuIds) {List<SkuHasStockVo> collect = skuIds.stream().map(skuId -> {SkuHasStockVo vo = new SkuHasStockVo();// 查询sku的总库存量Long count = baseMapper.getSkuStock(skuId);vo.setSkuId(skuId);vo.setHasStock(count == null ? false : count > 0);return vo;}).collect(Collectors.toList());return collect;
}

修改“com.cwh.gulimall.ware.dao.WareSkuDao”类,代码如下

 Long getSkuStock(Long skuId);

修改“com.cwh.gulimall.ware.dao.WareSkuDao.xml”类,代码如下

<select id="getSkuStock" resultType="java.lang.Long">select sum(stock - stock_locked) from wms_ware_sku where sku_id=#{sku_id}
</select>

2.2、查询当前sku的所有可以被用来检索的规格属性

修改“com.cwh.gulimall.product.service.AttrService”类,代码如下:

/*** 在指定的所有属性集合里面,挑出检索属性** @param attrIds* @return*/
List<Long> selectSearchAttrs(List<Long> attrIds);

修改“com.cwh.gulimall.product.service.impl.AttrServiceImpl”类,代码如下:

@Override
public List<Long> selectSearchAttrs(List<Long> attrIds) {return baseMapper.selectSearchAttrIds(attrIds);
}
4、将数据发送给es进行保存

修改“com.cwh.gulimall.product.feign.SearchFeignService”类,代码如下:


package com.cwh.gulimall.product.feign;
import com.cwh.common.to.es.SkuEsModel;
import com.cwh.common.utils.R;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.List;@FeignClient("gulimall-search")
public interface SearchFeignService {
@PostMapping("search/save/product")
public R productStatusUp(@RequestBody List<SkuEsModel> skuEsModels);
}
4.1、创建gulimall-search

1、添加pom

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.5.RELEASE</version><relativePath/> <!-- lookup parent from repository -->
</parent><groupId>com.cwh.gulimall</groupId><artifactId>gulimall-search</artifactId><version>0.0.1-SNAPSHOT</version><name>gulimall-search</name><description>ElasticSearch检索服务</description><properties><java.version>1.8</java.version><elasticsearch.version>7.4.2</elasticsearch.version></properties><dependencies><!--导入es的rest-high-level-client--><dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifactId><version>7.4.2</version></dependency><dependency><groupId>com.auguigu.gulimall</groupId><artifactId>gulimall-commom</artifactId><version>0.0.1-SNAPSHOT</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope><exclusions><exclusion><groupId>org.junit.vintage</groupId><artifactId>junit-vintage-engine</artifactId></exclusion></exclusions></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>

2、修改yml

spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848 
spring.application.name=gulimall-search 
server.port=12000 

3、添加主配置类

package com.cwh.gulimall.search;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;@EnableDiscoveryClient
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
public class GulimallSearchApplication {public static void main(String[] args) {SpringApplication.run(GulimallSearchApplication.class, args);}}

4、配置ElaseaticSearch

修改“com.cwh.gulimall.search.config.GulimallElasticSearchConfig”类,代表如下:

package com.cwh.gulimall.search.config;import org.apache.http.HttpHost;
import org.elasticsearch.client.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestOperations;/*** 1、导入依赖* 2、编写配置,给容器中注入一个RestHighLevelClient* 3、参照API操作*/@Configuration
public class GulimallElasticSearchConfig {public static final RequestOptions COMMON_OPTIONS;static {RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder();
//        builder.addHeader("Authorization", "Bearer " + TOKEN);
//        builder.setHttpAsyncResponseConsumerFactory(
//                new HttpAsyncResponseConsumerFactory
//                        .HeapBufferedResponseConsumerFactory(30 * 1024 * 1024 * 1024));COMMON_OPTIONS = builder.build();}@Beanpublic RestHighLevelClient restHighLevelClient() {RestClientBuilder builder = RestClient.builder(new HttpHost("192.168.43.125", 9200, "http"));return new RestHighLevelClient(builder);}
}

修改“com.cwh.gulimall.search.controller.ElasticSaveController”类,代表如下:

package com.cwh.gulimall.search.controller;import com.cwh.common.constant.ProductConstant;
import com.cwh.common.exception.BizCodeEnume;
import com.cwh.common.to.es.SkuEsModel;
import com.cwh.common.utils.R;
import com.cwh.gulimall.search.service.ProductSaveService;
import lombok.extern.slf4j.Slf4j;
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;@RequestMapping("/search/save")
@RestController
@Slf4j
public class ElasticSaveController {@AutowiredProductSaveService productSaveService;/*** 上架商品*/@PostMapping("/product")public R productStatusUp(@RequestBody List<SkuEsModel> skuEsModels) {boolean b;try {b = productSaveService.productStatusUp(skuEsModels);} catch (Exception e) {log.error("ElasticSaveController商品上架错误:{}", e);return R.error(BizCodeEnume.PRODUCT_UP_EXCEPTION.getCode(), BizCodeEnume.PRODUCT_UP_EXCEPTION.getMsg());}if (!b) {return R.ok();} else {return R.error(BizCodeEnume.PRODUCT_UP_EXCEPTION.getCode(), BizCodeEnume.PRODUCT_UP_EXCEPTION.getMsg());}}
}

修改“com.cwh.gulimall.search.service.ProductSaveService”类,代表如下:

public class EsConstant {public static final String PRODUCT_INDEX = "product"; //sku数据在es中的索引
}

修改“com.cwh.gulimall.search.service.impl.ProductSaveServiceImpl”类,代表如下:

package com.cwh.gulimall.search.service.impl;import com.alibaba.fastjson.JSON;
import com.cwh.common.to.es.SkuEsModel;
import com.cwh.gulimall.search.config.GulimallElasticSearchConfig;
import com.cwh.gulimall.search.constant.EsConstant;
import com.cwh.gulimall.search.service.ProductSaveService;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;@Slf4j
@Service
public class ProductSaveServiceImpl implements ProductSaveService {@AutowiredRestHighLevelClient restHighLevelClient;@Overridepublic boolean productStatusUp(List<SkuEsModel> skuEsModels) throws IOException {// 保存到es// 1、给es中建立索引。product,建立好映射关系// 2、给es中保存这些数据// BulkRequest bulkRequest, RequestOptions optionsBulkRequest bulkRequest = new BulkRequest();for (SkuEsModel model : skuEsModels) {// 1、构造保存请求IndexRequest indexRequest = new IndexRequest(EsConstant.PRODUCT_INDEX);indexRequest.id(model.getSkuId().toString());String jsonString = JSON.toJSONString(model);indexRequest.source(jsonString, XContentType.JSON);bulkRequest.add(indexRequest);}BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, GulimallElasticSearchConfig.COMMON_OPTIONS);// TODO 如果批量错误boolean b = bulk.hasFailures();List<String> collect = Arrays.stream(bulk.getItems()).map(item -> item.getId()).collect(Collectors.toList());log.info("商品上架完成:{},返回数据:{}", collect, bulk.toString());return b;}}
4.2、修改当前spu的状态

修改"com.cwh.gulimall.product.dao.SpuInfoDao"类,代码如下:

void updateSpuStatus(@Param("spuId") Long spuId,@Param("code") int code);

修改"com.cwh.gulimall.product.dao.SpuInfoDao.xml"类,代码如下:

<update id="updateSpuStatus">update pms_spu_info set publish_status=#{code},update_time=NOW() where id =#{spuId}
</update>

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

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

相关文章

服务器使用frp做内网穿透详细教程,请码住

目录 1.内网穿透的定义 2.前提条件 3.frp下载地址 4.配置服务器端的frps.toml文件 5. 配置客户端&#xff0c;即物理服务器或者是电脑本机地址 6.添加服务端启动命令startServerFrp.sh 7.添加客户端启动命令startClientFrp.sh 8. 查看服务端启动日志 9.查看客户端启…

C++平台跳跃游戏

目录 开头程序Game.cpp源文件Player.h头文件Player.cpp源文件 程序的流程图程序游玩的效果下一篇博客要说的东西 开头 大家好&#xff0c;我叫这是我58。 程序 Game.cpp源文件 #include <iostream> #include "Player.h" using namespace std; void printma…

picgo + typora + gitee图床

Picgo打造个人图床&#xff0c;稳定又安全 解决Typora笔记上传到CSDN图片无法显示的问题 typora中

Opencv第十一章——视频处理

1. 读取并显示摄像头视频 1.1 VideoCapture类 VideoCapture类提供了构造方法VideoCapture(),用于完成摄像头的初始化工作&#xff0c;其语法格式如下&#xff1a; capture cv2.VideoCapture(index) 参数说明&#xff1a; capture:要打开的摄像头视频。 index:摄像头设备索引。…

《动手学深度学习》笔记2.2——神经网络从基础→进阶 (参数管理-每层的权重/偏置)

目录 0. 前言 正文&#xff1a;参数管理 1. 参数访问 1.1 [目标参数] 1.2 [一次性访问所有参数] 1.3 [从嵌套块收集参数] 2. 参数初始化 2.1 [内置初始化] 2.2 [自定义初始化] 2.3 [参数绑定-共享参数] 3. 小结&#xff08;第2节&#xff09; 4. 延后初始化 (原书第…

Qt6.7开发安卓程序间接连接到MySQL的方法

本文主要描述一种通过间接的方法&#xff0c;使得Qt开发的安卓程序可以直连到Mysql数据库的方法。本文章的方案是通过JAVA代码去连接MySQL数据库&#xff0c;然后C代码去调用JAVA的方法&#xff0c;从而实现QT开发的安卓程序去直连到MySQL数据库。 本文使用 JDBC 结合 JNI&…

《深度学习》OpenCV 图像拼接 拼接原理、参数解析、案例实现

目录 一、图像拼接 1、直接看案例 图1与图2展示&#xff1a; 合并完结果&#xff1a; 2、什么是图像拼接 3、图像拼接步骤 1&#xff09;加载图像 2&#xff09;特征点检测与描述 3&#xff09;特征点匹配 4&#xff09;图像配准 5&#xff09;图像变换和拼接 6&am…

【深度学习】05-Rnn循环神经网络-01- 自然语言处理概述/词嵌入层/循环网络/文本生成案例精讲

循环神经网络&#xff08;RNN&#xff09;主要用于自然语言处理的。 循环神经网络&#xff08;RNN&#xff09;、卷积神经网络&#xff08;CNN&#xff09;和全连接神经网络&#xff08;FCN&#xff09;是三种常见的神经网络类型&#xff0c;各自擅长处理不同类型的数据。下面…

【数据库差异研究】update与delete使用表别名的研究

目录 ⚛️总结 ☪️1 Update ♋1.1 测试用例UPDATE users as a SET a.age 111 WHERE a.name Alice; ♏1.2 测试用例UPDATE users as a SET a.age 111 WHERE name Alice; ♐1.3 测试用例UPDATE users as a SET age 111 WHERE a.name Alice; ♑1.4 测试用例UPDATE us…

ubuntu 安装k8s

#关闭 Swap 内存&#xff0c;配置完成建议重启一下 nano /etc/fstab #注释下面相似的一行 #/swapfile none swap sw 0 0 #重启 reboot#部属k8s apt update && apt install -y apt-transport-https 下载 gpg 密钥 curl https://mi…

Python安装流程(Windows + MAC)

目录 Windows 版 1.下载Python 2.开始安装 3.配置环境变量 4.测试python是否成功安装 MAC版 1.下载Python 2.开始安装 Windows 版 1.下载Python 进入Python官网下载&#xff1a;&#xff08;Python更新频繁&#xff0c;下载最新版即可&#xff0c;安装流程一致&#x…

【Bug】STM32F1的PB3和PB4无法正常输出

Bug 使用标准库配置STM32F103C8T6的PB3和PB4引脚输出控制LED灯时&#xff0c;发现引脚电平没有变化无法正常输出高低电平&#xff0c;配置代码如下&#xff1a; GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE ); GPIO_InitStruc…

C语言+单片机

今天内容有点水哈哈&#xff08;忙着练焊铁技术了嘻嘻&#xff09; C语言 简单学习了while语言以及其与for语言的区别和适用方法 .循环结构&#xff1a; 初始化语句条件判断句条件控制句 for语句 for(int1;i<100;i){执行条件} for (int i 1; i < 100; i) {printf(&quo…

stm32四足机器人(标准库)

项目技术要求 PWM波形的学习 参考文章stm32 TIM输出比较(PWM驱动LED呼吸灯&&PWM驱动舵机&&PWM驱动直流电机)_ttl pwm 驱动激光头区别-CSDN博客 舵机的学习 参考文章 stm32 TIM输出比较(PWM驱动LED呼吸灯&&PWM驱动舵机&&PWM驱动直流电机)…

发布:ultralytics-yolo-webui :Detect 目标检测 工具-先行版本 >> DataBall

通过webui 方式对ultralytics 的 detect 检测任务 进行&#xff1a; 1&#xff09;数据预处理&#xff0c;2&#xff09;模型训练&#xff0c;3&#xff09;模型推理。 本项目提供了 示例数据集&#xff0c;用 labelImage标注&#xff0c;标注文件为 xml 文件。 项目地址&…

css的背景background属性

CSS的background属性是一个简写属性&#xff0c;它允许你同时设置元素的多个背景相关的子属性。使用这个属性可以简化代码&#xff0c;使其更加清晰和易于维护。background属性可以设置不同的子属性。 background子属性 定义背景颜色 使用background-color属性 格式&#x…

【AI绘画】Midjourney进阶:景别详解

博客主页&#xff1a; [小ᶻZ࿆] 本文专栏: AI绘画 | Midjourney 文章目录 &#x1f4af;前言&#x1f4af;为什么要学习景别景别的作用景别在Midjourney中的应用实例 &#x1f4af;大景别&#x1f4af;远景特点提示词书写技巧测试 &#x1f4af;全景特点提示词书写技巧测试…

三、数据链路层(下)

目录 3.6以太网 以太网的分类 Mac地址 以太网数据格式 3.7互联网 数据是如何传输的&#xff1f; 3.8以太网、局域网、互联网的区别 总结&#xff1a; 3.9 vlan基本概念与基本原理 Vlan实现 划分 VLAN 例题 3.10广域网及相关协议 ppp协议 PPP协议所满足的要求 P…

防sql注入的网站登录系统设计与实现

课程名称 网络安全 大作业名称 防sql注入的网站登录系统设计与实现 姓名 学号 班级 大 作 业 要 求 结合mysql数据库设计一个web登录页面密码需密文存放&#xff08;可以采用hash方式&#xff0c;建议用sha1或md5加盐&#xff09;采用服务器端的验证码&#…

C(十)for循环 --- 黑神话情景

前言&#xff1a; "踏过三界宝刹&#xff0c;阅过四洲繁华。笑过五蕴痴缠&#xff0c;舍过六根牵挂。怕什么欲念不休&#xff0c;怕什么浪迹天涯。步履不停&#xff0c;便是得救之法。" 国际惯例&#xff0c;开篇先喝碗鸡汤。 今天&#xff0c;杰哥写的 for 循环相…