Apache atlas 元数据管理治理平台使用和架构

news2024/11/16 22:50:57

1、前言

Apache Atlas 是托管于 Apache 旗下的一款元数据管理和治理的产品,目前在大数据领域应用颇为广泛,可以很好的帮助企业管理数据资产,并对这些资产进行分类和治理,为数据分析,数据治理提供高质量的元数据信息。

随着企业业务量的逐渐膨胀,数据日益增多,不同业务线的数据可能在多种类型的数据库中存储,最终汇集到企业的数据仓库中进行整合分析,这个时候如果想要追踪数据来源,理清数据之间的关系将会是一件异常头疼的事情,倘若某个环节出了问题,追溯的成本将是巨大的,于是 Atlas 在这种背景下应运而生了,通过它,我们可以非常方便的管理元数据,并且可以追溯表级别,列级别之间的关系(血缘关系),为企业的数据资产提供强有力的支撑和保障。Atlas 支持从 HBase 、Hive、Sqoop、Storm、Kafka 中提取和管理元数据,同时也可以通过 Rest Api 的方式自行定义元数据模型,生成元数据。

本文我们着重介绍一下 Atlas 的相关概念,帮助大家更好的理解 Atlas,同时详细讲解如何通过 Rest Api 的方式自定义数据模型,生成血缘关系,以便开发自己的个性化需求。

2、Atlas 原理及相关概念

元数据

元数据其实就是描述数据的数据,比如表,字段,视图等,每个业务系统可能都会自己定义表,字段,视图,这些数据从哪来到往哪去,数据之间是否存在关联,和其他系统的数据是否存在重复和矛盾字段,这些就是元数据管理要解决的问题,也是 Atlas 要解决的问题。

运行原理

Atlas 的原理其实并不难理解,主要是通过内部提供的脚本读取数仓中的数据库结构,生成数据模型,存储到 Atlas的 Hbase 中,同时通过 hook 的方式监听数仓中的数据变化,分析执行的 sql 语句,从而生成表与表,列与列的血缘关系依赖,在前台展示给用户查看。

数仓支持

Atlas 对 Hive 支持最好,我们都知道,Hive 是依赖于 Hadoop 的,数据存储在 HDFS 中,Atlas 有专门的 shell 脚本可以直接运行读取 Hive 的表结构等元数据信息同步到 Atlas 的存储库中,自动生成元数据模型,同时 Atlas 提供的 HiveHook 可以监听 Hive 的数据变化,根据 Hive 执行的 sql 推断出数据与数据之间的关系,生成血缘关系图,如果我们想要分析其他数据存储介质的元数据和血缘关系,Atlas 的支持并不是很理想。但通常情况下,我们会定时把业务库如 mysql,oracle 中的数据定时同步到数仓中整合分析,而数仓我们一般都会采用 Hadoop 的生态体系,所以这一点并不是问题。

架构图解

以下是 Atlas 的架构图解,可以看出,Atlas 所依赖的生态体系是异常庞大的,这也直接导致了它部署起来十分繁琐,本文不再讲解 Atlas 的部署,网上相关的教程有很多,感兴趣的朋友可以自己搜索尝试。
在这里插入图片描述

核心组件概念

Atlas 中主要有以下核心组件,这些需要我们着重了解,接下来我们通过 Rest Api 自定义建模其实就是对以下组件的增删查改操作。

1. Type

元数据类型定义,这里可以是数据库,表,列等,还可以细分 mysql 表( mysql_table ),oracle 表( oracle_table )等,atlas自带了很多类型,如 DataSet,Process 等,一般情况下,数据相关的类型在定义类型的时候都会继承 DataSet,而流程相关的类型则会继承 Process,便于生成血缘关系。我们也可以通过调用 api 自定义类型。这是一切的起点,定义完类型之后,才能生成不同类型的元数据实体,生成血缘关系,我个人更喜欢把元数据类型称之为建模。

2. Classification

分类,通俗点就是给元数据打标签,分类是可以传递的,比如 A 视图是基于 A 表生成的,那么如果 A 表打上了 a 这个标签,A 视图也会自动打上 a 标签,这样的好处就是便于数据的追踪。

3. Entity

实体,表示具体的元数据,Atlas 管理的对象就是各种 Type 的 Entity。

4. Lineage

数据血缘,表示数据之间的传递关系,通过 Lineage 我们可以清晰的知道数据的从何而来又流向何处,中间经历了哪些操作,这样一旦数据出现问题,可以迅速追溯,定位是哪个环节出现错误。

3、Altas安装

(参考链接,请结合实际情况使用)
1、https://blog.csdn.net/hshudoudou/article/details/123899947
2、https://blog.csdn.net/javaThanksgiving/article/details/130505251

4、Altas使用

Altas 成功部署之后,使用还是很简单的,这是登录界面,用户名密码默认是 admin,admin:
在这里插入图片描述进入主页,点击右上角 switch to new ,使用新版界面,更直观:
在这里插入图片描述
在这里插入图片描述
页面左侧便是 Atlas 的类型树,点击树节点的某个类型,可以查看下面的实体,这里我们点击 mysql_table:
在这里插入图片描述可以看到下面有很多表,这些都是我之前自己利用 Rest Api 上传定义的。

下面我们来讲解一下如何通过 Rest Api 的方式自定义类型,生成实体,创建血缘关系。

5、Atlas Rest Api 详解及示例

我们点击主页上方的 Help-》API Documentation,便可以查看 Atlas 所有的开放接口:
在这里插入图片描述在这里插入图片描述
有一点我们需要注意,Atlas 的接口在使用的时候是需要鉴权的,所以我们构建 http 请求的时候需要带上用户名和密码认证信息,本次示例中我们使用 atlas-client-v2 开源组件来进行 Atlas 的 api 调用。

本次示例我们定义一个 my_db 类型,my_table 类型,并且让 my_db 一对多 my_table,然后创建 test_db 实体到 my_db 下,创建 test_table_source 和 test_table_target 实体到 my_table 下,并且定义 test_table_target 的数据来自 test_table_source,生成两个实体的血缘关系依赖。

自定义 my_db 和 my_table 类型

我们对 my_db 和 my_table 类型进行定义,在 Atlas 的Rest Api 中,允许一个请求定义多种类型,在这里我们先构建 json 请求体,然后再通过编码方式实现,二者对比,更容易理解,json 请求体如下(关键地方有注释):

{
  "enumDefs": [],
  "structDefs": [],
  "classificationDefs": [],
  //类型定义
  "entityDefs": [
    {
      "name": "my_db",
      //数据类型的定义,约定俗成,继承Atlas自带的DataSet
      "superTypes": [
        "DataSet"
      ],
      //服务类型(便于在界面分组显示类型)
      "serviceType": "my_type",
      "typeVersion": "1.1",
      "attributeDefs": []
    },
    {
      "name": "my_table",
      "superTypes": [
        "DataSet"
      ],
      "serviceType": "my_type",
      "typeVersion": "1.1",
      "attributeDefs": []
    }
  ],
  //定义类型之间的关系
  "relationshipDefs": [
    {
      "name": "my_table_db",
      "serviceType": "my_type",
      "typeVersion": "1.1",
      //关系类型:ASSOCIATION:关联关系,没有容器存在,1对1 
      //AGGREGATION:容器关系,1对多,而且彼此可以相互独立存在 
      //COMPOSITION:容器关系,1对多,但是容器中的实例不能脱离容器存在
      "relationshipCategory": "AGGREGATION",
      //节点一
      "endDef1": {
        "type": "my_table",
        //表中关联的属性名称,对应下面的 my_db
        "name": "db",
        //代表这头是不是容器
        "isContainer": false,
        //cardinality: 三种类型SINGLE, LIST, SET
        "cardinality": "SINGLE"
      },
      // 节点2
      "endDef2": {
        "type": "my_db",
        "name": "tables",
        "isContainer": true,
        // db 包含 table,table不能重复,所以类型设置为 SET
        "cardinality": "SET"
      },
      // 推导tag NONE 不推导
      "propagateTags": "NONE"
    }
  ]
}

编码实现:

引入 pom 依赖,注意,如果要集成到自己的业务系统之中,业务系统如果使用了其他的日志框架,需要去除 slf4j-log4j12 依赖,否则日志框架会起冲突,导致启动失败,另外 atlas-client-common 中依赖了 commons-configuration 1.10,如果业务系统中有低版本依赖,记得排除,不然二者会冲突,导致 client 初始化失败。

<dependencies>
        <!-- Apache Atlas -->
        <dependency>
            <groupId>org.apache.atlas</groupId>
            <artifactId>atlas-client-common</artifactId>
            <version>2.1.0</version>
            <exclusions>
                <exclusion>
                    <artifactId>slf4j-log4j12</artifactId>
                    <groupId>org.slf4j</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- Apache Atlas Client  Version2 -->
        <dependency>
            <groupId>org.apache.atlas</groupId>
            <artifactId>atlas-client-v2</artifactId>
            <version>2.1.0</version>
            <exclusions>
                <exclusion>
                    <artifactId>slf4j-log4j12</artifactId>
                    <groupId>org.slf4j</groupId>
                </exclusion>
                <exclusion>
                    <artifactId>log4j</artifactId>
                    <groupId>log4j</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>${fastjson.version}</version>
        </dependency>
    </dependencies>

引入 atlas-application.properties(必须得有,否则会初始化失败):

atlas.rest.address=http://127.0.0.1:21000

代码实现如下(对照json非常容易理解):

		AtlasClientV2 atlasClientV2 = new AtlasClientV2(new String[]{"http://127.0.0.1:21000"}, new String[]{"admin", "admin"});
		//父类集合
		Set<String> superTypes = new HashSet<>();
		superTypes.add(AtlasBaseTypeDef.ATLAS_TYPE_DATASET);
		//定义myType
		AtlasTypesDef myType = new AtlasTypesDef();
		//定义myDb
		AtlasEntityDef myDb = new AtlasEntityDef();
		myDb.setName("my_db");
		myDb.setServiceType("my_type");
		myDb.setSuperTypes(superTypes);
		myDb.setTypeVersion("1.1");
		//定义mytable
		AtlasEntityDef myTable = new AtlasEntityDef();
		myTable.setName("my_table");
		myTable.setServiceType("my_type");
		myTable.setSuperTypes(superTypes);
		myTable.setTypeVersion("1.1");
		//定义relationshipDef
		AtlasRelationshipDef relationshipDef = new AtlasRelationshipDef();
		relationshipDef.setName("my_table_db");
		relationshipDef.setServiceType("my_type");
		relationshipDef.setTypeVersion("1.1");
		relationshipDef.setRelationshipCategory(AtlasRelationshipDef.RelationshipCategory.AGGREGATION);
		relationshipDef.setPropagateTags(AtlasRelationshipDef.PropagateTags.NONE);
		//定义endDef1
		AtlasRelationshipEndDef endDef1 = new AtlasRelationshipEndDef();
		endDef1.setType("my_table");
		endDef1.setName("db");
		endDef1.setIsContainer(false);
		endDef1.setCardinality(AtlasStructDef.AtlasAttributeDef.Cardinality.SINGLE);
		relationshipDef.setEndDef1(endDef1);
		//定义endDef2
		AtlasRelationshipEndDef endDef2 = new AtlasRelationshipEndDef();
		endDef2.setType("my_db");
		endDef2.setName("tables");
		endDef2.setIsContainer(true);
		endDef2.setCardinality(AtlasStructDef.AtlasAttributeDef.Cardinality.SET);
		relationshipDef.setEndDef2(endDef2);
		//entityDefs
		List<AtlasEntityDef> entityDefs = new ArrayList<>(2);
		entityDefs.add(myDb);
		entityDefs.add(myTable);
		myType.setEntityDefs(entityDefs);
		//relationshipDefs
		List<AtlasRelationshipDef> relationshipDefs = new ArrayList<>(1);
		relationshipDefs.add(relationshipDef);
		myType.setRelationshipDefs(relationshipDefs);
		//查询是否已有my_db类型,没有则创建
		SearchFilter filter = new SearchFilter();
		filter.setParam("name", "my_db");
		AtlasTypesDef allTypeDefs = atlasClientV2.getAllTypeDefs(filter);
		if (allTypeDefs.getEntityDefs().isEmpty()) {
			//请求 rest api
			atlasClientV2.createAtlasTypeDefs(myType);
		}

执行以上代码,执行完毕后,前往 Atlas 主页查看,类型已成功创建:
在这里插入图片描述查看类型模型图:
在这里插入图片描述类型创建完毕,接下来我们进行实体的创建。

创建实体 test_db,test_table_source 和 test_table_target

json 如下:

//my_db 实体
{
	"typeName": "my_db",
	"attributes": {
		"qualifiedName": "test_db",
		"name": "test_db",
		"description": "测试创建db"
	}
}
//test_table_source 实体
{
	"typeName": "my_table",
	"attributes": {
		"qualifiedName": "test_table_source",
		"name": "test_table_source",
		"description": "测试创建test_table_source"
	},
	"relationshipAttributes": {
		"db": {
			"typeName": "my_db",
			//my_db的guid(创建完my_db后会返回)
			"guid": "xxxx"
		}
	}
}
//test_table_target 实体
{
	"typeName": "my_table",
	"attributes": {
		"qualifiedName": "test_table_target",
		"name": "test_table_target",
		"description": "测试创建test_table_target"
	},
	"relationshipAttributes": {
		"db": {
			"typeName": "my_db",
			"guid": "xxx"
		}
	}
}

代码实现如下:

		//创建实体 test_db
		AtlasEntity testDb = new AtlasEntity();
		testDb.setTypeName("my_db");
		Map<String, Object> attributes = new HashMap<>();
		attributes.put("qualifiedName", "test_db");
		attributes.put("name", "test_db");
		attributes.put("description", "测试创建db");
		testDb.setAttributes(attributes);
		Map<String, String> queryAttributes = new HashMap<>();
		queryAttributes.put("qualifiedName", "test_db");
		String myDbGuid = null;
		try {
			//查询不到会报错
			AtlasEntity.AtlasEntityWithExtInfo extInfo = atlasClientV2.getEntityByAttribute("my_db", queryAttributes);
			myDbGuid = extInfo.getEntity().getGuid();
		} catch (AtlasServiceException e) {
			if (ClientResponse.Status.NOT_FOUND.equals(e.getStatus())) {
				AtlasEntity.AtlasEntityWithExtInfo extInfo = new AtlasEntity.AtlasEntityWithExtInfo(testDb);
				//请求
				EntityMutationResponse response = atlasClientV2.createEntity(extInfo);
				myDbGuid = response.getGuidAssignments().values().toArray(new String[]{})[0];
			}
		}
		//创建与db的关系
		Map<String, Object> relationShipAttr = new HashMap<>();
		Map<String, String> dbMap = new HashMap<>();
		dbMap.put("guid", myDbGuid);
		dbMap.put("typeName", "my_db");
		relationShipAttr.put("db", dbMap);
		//创建实体 test_table_source
		AtlasEntity testTableSource = new AtlasEntity();
		testTableSource.setTypeName("my_table");
		attributes.put("qualifiedName", "test_table_source");
		attributes.put("name", "test_table_source");
		attributes.put("description", "测试创建test_table_source");
		testTableSource.setAttributes(attributes);
		testTableSource.setRelationshipAttributes(relationShipAttr);
		queryAttributes.put("qualifiedName", "test_table_source");
		try {
			//atlasClientV2.updateEntity(new AtlasEntity.AtlasEntityWithExtInfo(testTableSource));
			AtlasEntity.AtlasEntityWithExtInfo extInfo = atlasClientV2.getEntityByAttribute("my_table", queryAttributes);
			testTableSource = extInfo.getEntity();
		} catch (AtlasServiceException e) {
			if (ClientResponse.Status.NOT_FOUND.equals(e.getStatus())) {
				AtlasEntity.AtlasEntityWithExtInfo extInfo = new AtlasEntity.AtlasEntityWithExtInfo(testTableSource);
				//请求
				EntityMutationResponse response = atlasClientV2.createEntity(extInfo);
				testTableSource.setGuid(response.getGuidAssignments().values().toArray(new String[]{})[0]);
			}
		}
		//创建实体 test_table_target
		AtlasEntity testTableTarget = new AtlasEntity();
		testTableTarget.setTypeName("my_table");
		attributes.put("qualifiedName", "test_table_target");
		attributes.put("name", "test_table_target");
		attributes.put("description", "测试创建test_table_target");
		testTableTarget.setAttributes(attributes);
		testTableTarget.setRelationshipAttributes(relationShipAttr);
		queryAttributes.put("qualifiedName", "test_table_target");
		try {
			//atlasClientV2.updateEntity(new AtlasEntity.AtlasEntityWithExtInfo(testTableTarget));
			AtlasEntity.AtlasEntityWithExtInfo extInfo = atlasClientV2.getEntityByAttribute("my_table", queryAttributes);
			testTableTarget = extInfo.getEntity();
		} catch (AtlasServiceException e) {
			if (ClientResponse.Status.NOT_FOUND.equals(e.getStatus())) {
				AtlasEntity.AtlasEntityWithExtInfo extInfo = new AtlasEntity.AtlasEntityWithExtInfo(testTableTarget);
				//请求
				EntityMutationResponse response = atlasClientV2.createEntity(extInfo);
				testTableTarget.setGuid(response.getGuidAssignments().values().toArray(new String[]{})[0]);
			}
		}

执行代码完毕后,查看类的树形图,发现已经产生了实体:

在这里插入图片描述我们点击右侧的 test_db 实体,可以看到它的基本信息,也可以看到它的 relationship 信息,包含了 test_table_source 和 test_table_target 两个实体:
在这里插入图片描述查看 relationship 信息,包含 test_table_source 和 test_table_target:

在这里插入图片描述创建 test_table_source 和 test_table_target 的血缘关系依赖

前面我们提到,定义 test_table_target 的数据来自 test_table_source,血缘关系依赖在 Atlas 中其实也是作为实体 Entity 存在,只不过继承的父类是 Process,这样可以定义 inputs 和 outputs 属性,构建血缘关系,json 如下:

{
	"typeName": "Process",
	"attributes": {
		"name": "test_process",
		"qualifiedName": "test_process",
		"description": "test_table_target 的数据来自 test_table_source",
		"inputs": [{
			"typeName": "my_table",
			//test_table_source的guid,创建实体从返回的信息中获取
			"guid": "xxx"
		}],
		"outputs": [{
			"typeName": "my_table",
			test_table_target的guid,创建实体从返回的信息中获取
			"guid": "xxx"
		}]
	}
}

代码实现如下:

		AtlasEntity lineage = new AtlasEntity();
		//设置为process类型构建血缘
		lineage.setTypeName(AtlasBaseTypeDef.ATLAS_TYPE_PROCESS);
		attributes.put("qualifiedName", "test_process");
		attributes.put("name", "test_process");
		attributes.put("description", "test_table_target 的数据来自 test_table_source");
		attributes.put("inputs", getLineAgeInfo(testTableSource));
		attributes.put("outputs", getLineAgeInfo(testTableTarget));
		lineage.setAttributes(attributes);
		queryAttributes.put("qualifiedName", "test_process");
		System.out.println(SingletonObject.OBJECT_MAPPER.writeValueAsString(lineage));
		try {
			//查询是否存在
			atlasClientV2.getEntityByAttribute(AtlasBaseTypeDef.ATLAS_TYPE_PROCESS, queryAttributes);
		} catch (AtlasServiceException e)  {
			if (ClientResponse.Status.NOT_FOUND.equals(e.getStatus())) {
				//创建
				AtlasEntity.AtlasEntityWithExtInfo extInfo = new AtlasEntity.AtlasEntityWithExtInfo(lineage);
				atlasClientV2.createEntity(extInfo);
			}
		}
		
	//构建inputs和outputs
	private static List<Map<String, String>> getLineAgeInfo(AtlasEntity entity) {
		List<Map<String, String>> list = new ArrayList<>();
		Map<String, String> map = new HashMap<>();
		map.put("guid", entity.getGuid());
		map.put("typeName", entity.getTypeName());
		list.add(map);
		return list;
	}

执行以上代码,然后打开主页,点击 my_table 中的 test_table_source,查看 lineage 标签,血缘关系已成功构建:
在这里插入图片描述至此,我们通过 Atlas Rest Api 的方式自行建模,创建实体,构建血缘关系就完成了。

元数据管理,数据治理,在当下仍然是一个热门的话题,同时,它也可以帮助我们更好的支撑企业的数据资产,更好的分析数据,为企业的发展决策提供有效的帮助。

引用链接:
1、https://blog.csdn.net/hshudoudou/article/details/123899947
2、https://blog.csdn.net/javaThanksgiving/article/details/130505251
3、原文 https://blog.csdn.net/m0_37719874/article/details/124245209

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

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

相关文章

远控项目02:项目的创建以及git的配置

&#x1f482; 个人主页:pp不会算法v &#x1f91f; 版权: 本文由【pp不会算法v】原创、在CSDN首发、需要转载请联系博主 &#x1f4ac; 如果文章对你有帮助、欢迎关注、点赞、收藏(一键三连)和订阅专栏哦 c/MFC远程控制项目系列文章 1、在github创建仓库 2、在本地创建一个空文…

Vue-2.3v-model原理

原理&#xff1a;v-model本质上是一个语法糖&#xff0c;例如应用在输入框上&#xff0c;就是value属性和input事件的合写。 作用&#xff1a;提供数据的双向绑定 1&#xff09;数据变&#xff0c;视图跟着变:value 2&#xff09;视图变&#xff0c;数据跟着变input 注意&a…

PostMan环境变量、全局变量、动态参数使用

一、环境准备 postmanmoco [{"description": "登录认证","request": {"uri": "/login","method": "post","forms": {"user": "admin","password": "a123…

CentOS 7下JumpServer安装及配置(超详细版)

前言 Jumpserver是一种用于访问和管理远程设备的Web应用程序&#xff0c;通常用于对服务器进行安全访问。它基于SSH协议&#xff0c;提供了一个安全和可管理的环境来管理SSH访问。Jumpserver是基于Python开发的一款开源工具&#xff0c;其提供了强大的访问控制功能&#xff0c;…

Qt应用开发(基础篇)——表格视图 QTableView

一、前言 QTableView类继承于QAbstractItemView类&#xff0c;提供了一个表格视图的模型。 视图基类 QAbstractItemView QTableView默认为Model/View实现。 //绑定view和model QStandardItemModel *model new QStandardItemModel(); ui->tableView->setModel(model);//…

手把手教你写一个JSON在线解析的前端网站1

前言 作为一名Android开发&#xff0c;经常要跟后端同事联调接口&#xff0c;那么总避免不了要格式化接口返回值&#xff0c;将其转换为清晰直观高亮的UI样式以及折叠部分内容&#xff0c;方便我们查看定位关键的信息。 一直以来都是打开Google 搜索json格式化关键字&#xf…

【无标题】期权交易的实际操作流程是什么?

期权可以进行双向交易&#xff0c;即投资者认为期权后期会上涨&#xff0c;则可以通过交易软件进行做多买入认购操作&#xff0c;如果认为它后期会下跌&#xff0c;则可以通过交易软件件进行做空买入认沽操作&#xff0c;下文介绍期权交易的实际操作流程是什么&#xff1f; 期权…

2023年中国手机回收量、手机回收价值及行业细分现状分析[图]

手机回收的主要去向包括再销售及环保降解两类。其中进行再交易的二手手机多为9成新及以上手机。二手手机最终去向主要为再销售及环保降解。 2016年以来&#xff0c;我国手机总体出货量持续下滑&#xff0c;2022年全年&#xff0c;国内市场手机总体出货量累计2.72亿部&#xff0…

【代码随想录】算法训练营 第一天 第一章 数组 Part 1

数组基础知识补充 1. 在leecode中&#xff0c;数组一般是以vector容器的形式出现的&#xff0c;虽然vector的底层实现是array&#xff0c;但严格来讲vector是容器&#xff0c;不是数组&#xff1b; 2. 数组元素的删除和增添都需要移动后续元素&#xff0c;而且在实现的角度上…

C++初阶 入门

目录 1.用C的方式写一个Hello World 2.命名空间 2.1什么是命名空间&#xff1f; 2.2使用命名空间 3.C的输入输出 前言&#xff1a;C初阶系列&#xff0c;每一期博主都会使用简单朴素的语言将对应的知识分享给大家&#xff0c;争取让所有人都可以听懂&#xff0c;C初阶系列…

跨境电商迎来全球5日达革命?菜鸟全球化再提速!

近年来&#xff0c;随着全球化进程的加速和跨境电商的蓬勃发展&#xff0c;物流速度成为了电商行业的竞争制高点之一。消费者不再满足于等待数周&#xff0c;甚至数月的国际快递&#xff0c;他们期望能够像本地购物一样迅速收到国际包裹。 在这一背景下&#xff0c;跨境电商物…

众佰诚:开一家抖音小店需要交押金不?

随着电商行业的不断发展&#xff0c;越来越多的商家开始尝试在不同的平台上开设自己的店铺。抖音作为国内最热门的短视频平台之一&#xff0c;也吸引了众多商家的目光。那么&#xff0c;开一家抖音小店需要交押金吗?接下来&#xff0c;我们就来详细了解一下。 首先&#xff0c…

山西电力市场日前价格预测【2023-10-13】

日前价格预测 预测说明&#xff1a; 如上图所示&#xff0c;预测明日&#xff08;2023-10-13&#xff09;山西电力市场全天平均日前电价为228.86元/MWh。其中&#xff0c;最高日前价格为396.88元/MWh&#xff0c;预计出现在18: 30。最低日前电价为0.00元/MWh&#xff0c;预计出…

TCP/IP(十二)TCP的确认、超时、重传机制

一 TCP的确认应答机制 确认应答机制: 每次收到数据 都会 给对端发送一个应答报文(ACK) ① 带重传的肯定确认 确认机制: 超时 重传的 肯定 确认 --> 完成了两个作用,或者说有两个含义1、肯定[正确] 确认小结&#xff1a; 我的确认信息是针对正确数据做确认,而不是错误…

YOLOv5算法改进(2)— 注意力机制介绍(SE、CBAM和CA)

前言:Hello大家好,我是小哥谈。注意力机制是近年来深度学习领域内的研究热点,可以帮助模型更好地关注重要的特征,从而提高模型的性能。注意力机制可被应用于模型的不同层级,以便更好地捕捉图像中的细节和特征,这种模型在计算资源有限的情况下,可以实现更好的性能和效率。…

免费SSL证书

在当今数字化时代&#xff0c;保护用户数据和建立安全连接至关重要。对于网站管理员和拥有者来说&#xff0c;SSL证书&#xff08;Secure Sockets Layer&#xff09;是确保安全的关键工具之一。但是&#xff0c;传统上购买和维护SSL证书可能会带来昂贵的成本和繁琐的流程。幸运…

百度车牌识别AI Linux使用方法-armV7交叉编译

1、获取百度ai的sdk 百度智能云-登录 (baidu.com) 里面有两个版本的armV7和armV8架构。v7架构的性能比较低往往需要交叉编译&#xff0c;v8的板子性能往往比较好&#xff0c;可以直接在板子上编译。 解压到ubuntu里面。这里介绍v7架构的。 2、ubuntu环境配置 ubuntu下安装软件…

学生静态HTML网页作品下载后如何导入到HBuilderX中编辑修改及运行

很多同学编辑网页要求使用HBuilder X软件&#xff0c;下载学生网页设计作品后&#xff0c;不知道如何打开&#xff0c;很多同学反应把HTML中的代码复制到HBuilder X后不显示图片或者跑版。今天STU网页为大家讲解下静态HTML网页作品如何导入HBuilder X中运行。 HBuilder X 导入…

『PyQt5-Qt Designer篇』| 13 Qt Designer中如何给工具添加菜单和工具栏?

13 Qt Designer中如何给工具添加菜单和工具栏? 1 创建默认窗口2 添加菜单栏3 查看和调用1 创建默认窗口 当新创建一个窗口的时候,默认会显示有:菜单栏和状态栏,如下: 可以在菜单栏上右键-移除菜单栏: 可以在菜单栏上右键-移除状态栏: 2 添加菜单栏 在窗口上,右键-创建…

城市排水管网监测方案(新型排水管网智能监测技术)

随着我国城市化进程不断加快,城市的排水管网也日益增长并变得复杂,对其进行实时监测以确保正常运行变得极为重要。针对此需求,基于工业物联网技术的新型智能排水管网监测系统为城市排水管网的运行与维护提供了有效手段。 该智能排水管网监测系统以无线通讯功能强大的SG600工业…