【Ne4j图数据库入门笔记1】图形数据建模初识

1.1 图形建模指南

图形数据建模是用户将任意域描述为节点的连接图以及与属性和标签关系的过程。Neo4j 图数据模型旨在以 Cypher 查询的形式回答问题,并通过组织图数据库的数据结构来解决业务和技术问题。

1.1.1 图形数据模型介绍

图形数据模型通常被称为对白板友好的模型。通常,在设计数据模型时,人们在白板上绘制示例数据,并将其连接到绘制的其他数据,以显示不同项目如何连接。然后,对白板模型进行重新格式化和结构化,以适合关系模型的规范化表。

图数据建模中也存在类似的过程。但是,图形数据模型不会修改数据模型以适应规范化的表结构,而是完全保持在白板上绘制的状态。这就是图形数据模型因对白板友好而得名的地方。

让我们看一个例子来证明这一点。在下面的白板图中,我们有一个关于电影《黑客帝国》的数据集。
在这里插入图片描述

接下来,我们对实体进行一些形式化,并匹配关系类型的预期语法,以创建属性图模型的节点/关系视图。

在这里插入图片描述

下一步,我们将添加标签并确定节点的属性以及属性图模型的关系。

在这里插入图片描述

最后,您可以在 Neo4j 浏览器中查看此数据模型,并确保它与白板上绘制的内容相匹配。另外,请注意它与我们最初设计的白板模型几乎相同。

在这里插入图片描述

为了更好地理解设计图数据模型的过程,以一小组数据为例,并逐步了解如何从中创建图数据模型的每个步骤。请考虑以下描述示例数据实体和连接的方案。

两个人,Sally 和John,是朋友。John 和 Sally 都读过《图形数据库》一书。

我们可以使用此语句中的信息通过将组件标识为标签、节点和关系来构建我们的模型。让我们将场景分成几部分,并将它们定义为属性图模型的一部分。但是,首先,我们简化了模型。

在这里插入图片描述

可以看到:

  • Nodes (circles) : 表示对象。
  • 节点可以具有属性(名称/值对)。
  • 关系(箭头)连接节点并表示操作。
  • 关系是定向的,可以具有属性(名称/值对)。

1.1.2 节点Nodes

在域中标识的第一个实体是节点。节点是构成图形的两个基本单元之一(另一个基本单元是关系 )。

可以通过识别域中的名词来查找图模型的节点。汽车、个人、客户、公司、资产和其他类似实体可以定义为良好起点的节点。

可以将节点识别为具有唯一概念标识的实体。在我们的场景中,我们从 Sally 和 John 开始,这些实体在下面以粗体列出。

两个人,Sally 和John,是朋友。JohnSally 都读过**《Graph Databases》**一书。

可以提取出以下节点

  • John
  • Sally
  • Graph Databases

请记住,图形数据库将实体的每个实例视为一个单独的节点(John 和 Sally 将是两个独立的节点,即使他们都是人),而图形数据库将是与另一本书不同的节点。

在这里插入图片描述

1.1.3 标签Labels

现在,当我们了解我们的节点是什么时,我们可以决定将哪些标签(如果有的话)分配给我们的节点来对它们进行分组或分类。让我们提醒一下标签的作用以及它们在图数据模型中的使用方式的定义。

标签是一种命名的图形构造,用于将节点分组为集合。所有标有相同标签的节点都属于同一集合。

许多数据库查询可以使用这些集合而不是整个图形,从而使查询更易于编写和更高效。一个节点可以用任意数量的标签进行标记,包括无标签,使标签成为图形的可选补充。

类似于我们通过识别场景中的名词来查找图模型的节点,您可以通过通用名词或人员、地点或事物组来识别标签。适合项目组(如车辆、人员、客户、公司、资产)和类似术语的通用名词可以用作图表中的标签。

为了确定我们是否可以在 Sally 和 John 场景中对对象进行分组,我们首先确定语句中提到的节点(John、Sally、图形数据库)的角色。我们可以在语句中找到两种不同类型的对象,下面将重点介绍它们。

两个人,Sally 和John,是朋友。JohnSally 都读过**《Graph Databases》**一书。

可以提取出以下标签

  • Person
  • Book

现在我们已经确定了节点和标签,我们可以更新我们的图形数据模型,将标签分配给它们所描述的节点。对于 John 和 Sally,我们应用了 Person 标签。对于图形数据库,我们应用标签 Book。

在这里插入图片描述

1.1.4 关系Relationships

我们现在有了我们的主要实体和一种对它们进行分组的方法,但我们仍然缺少图数据库模型的一个重要部分——数据之间的关系!

关系连接两个节点,并允许我们查找相关的数据节点。它有一个源节点和一个显示箭头方向的目标节点。虽然您必须在特定方向上存储关系,但 Neo4j 在任一方向上都具有相同的遍历性能,因此您可以在不指定方向的情况下查询关系。

图形数据库中一个核心的一致规则是“没有断开的链接”,确保现有关系永远不会指向不存在的端点。由于关系始终具有起始节点和结束节点,因此在不删除其关联关系的情况下,无法删除节点。

正如我们通过查找名词来找到节点和标签一样,您通常可以通过识别域中的动作或动词来找到图模型的关系。DRIVES、HAS_READ、MANAGES、ACTED_IN 等操作可以定义为节点之间存在的不同类型的关系。

让我们确定 John、Sally 和 Graph Database 节点之间的交互(在下面的方案中下划线)。

两个人,Sally 和John,是朋友。John 和 Sally 都读过《Graph Databases》一书。

节点之间的关系:

  • John是Sally的朋友
  • Sally是John的朋友
  • John读过Graph Databases
  • Sally读过Graph Databases

总结一下我们的发现,我们的 John 和 Sally 节点(标记为 Person)可以通过 is friends关系相互连接。John 和 Sally 都读过 Graph Databases 一书,因此我们可以将他们的每个节点(每个标记为 Person)连接到具有 has read 关系的 Graph Databases 节点(标记为 Book)。

在这里插入图片描述

1.1.5 属性Properties

属性是可以存储在节点或关系上的名称/值数据对。大多数标准数据类型都支持作为属性,您可以在图形数据库概念部分找到有关此类型的信息。

属性允许您存储有关节点或与其描述的实体的关系的相关数据。通常可以通过了解您的用例需要对数据提出什么样的问题来找到它们。

对于 John 和 Sally 的场景,我们可以列出一些我们可能想要回答的有关数据的问题。

关于我们的 John 和 Sally 数据模型的问题:

  • 约翰和莎莉什么时候成为朋友的?或者他们做朋友多久了?
  • 谁是《Graph Databases》一书的作者?
  • Graph Databases 这本书的平均评分是多少?
  • 约翰和莎莉几岁了?
  • 谁年长,莎莉还是约翰?
  • 谁先读了《Graph Databases》这本书,Sally 还是 John?

从此问题列表中,您可以确定我们需要存储在数据模型中实体上的属性,以便回答这些问题。
在这里插入图片描述

1.1.6 实现模型

可以使用 Cypher 语句创建图形。有很多方法可以将数据加载到图形中。在这里,我们使用 MERGE 子句来创建数据模型。

运行以下代码,为此数据模型创建图形:

MERGE (j:Person {name: 'John'})ON CREATE set j.age = 27
MERGE (s:Person {name: 'Sally'})         ON CREATE set s.age = 32
MERGE (b:Book {title: 'Graph Databases'})ON CREATE set b.authors = ['Jim Webber', 'Ian Robinson']
MERGE (j)-[rel1:IS_FRIENDS_WITH]->(s)ON CREATE SET rel1.since = '01/09/2013'
MERGE (j)-[rel2:HAS_READ]->(b)ON CREATE SET rel2.on = '02/03/2013', rel2.rated = 5
MERGE (s)-[rel3:HAS_READ]->(b)ON CREATE SET rel3.on = '02/09/2013', rel3.rated = 4

创建图形后,可以使用以下 Cypher 语句查看它:

MATCH (n) RETURN n

在 Neo4j 浏览器中,您可以将鼠标悬停在图中的每个节点和关系上以查看其属性。

在这里插入图片描述

1.2 建模:关系数据到图数据

1.2.1 介绍

关系数据库依赖于索引查找和表join来连接不同的实体。这很快就会成为性能问题,尤其是当连接了多个表、表上有数百万行或通过子查询遍历各个级别的复杂查询时。

在示例中,要查找 Alice 为哪些部门工作,您需要查询 Person 表以查找表示 Alice 的行,该行绑定到作为主键的唯一 ID。然后,您的查询将转到关联实体表 ( Person_Dept ),以查找其 ID 与一个或多个部门 ID 绑定的位置。最后,查询将检查 Department 表,以查找在关联实体表中找到的那些部门 ID 的实际值。

在这里插入图片描述

在图形中,您无需担心表连接和索引查找,因为图形数据是由每个单个实体及其与其他单个实体的关系构成的。

1.2.2 数据模型转换技巧

让我们看一下关系数据模型中的一些关键组件,并将它们转换为图数据模型的组件。下面列出了帮助您转换关系图的步骤。

  • 表到节点标签: 关系模型中的每个实体表都成为图形模型中节点上的标签。
  • 行到节点: 关系实体表中的每一行都将成为图形中的一个节点
  • 列到节点属性:关系表上的列(字段)成为图形中的节点属性。
  • 仅限业务主键:删除技术主键,保留业务主键。
  • 添加约束/索引:为业务主键添加唯一约束,为频繁查找的属性添加索引。
  • 外键到关系:将另一个表的外键替换为关系,然后删除它们。
  • 无默认值:删除具有默认值的数据,无需存储这些值。
  • 清理数据:可能需要将非规范化表中的重复数据拉出到单独的节点中,以获得更清晰的模型。
  • 列索引到数组 :索引列名称(如 email1、email2、email3)可能指示数组属性。
  • 关联表到关系:关联表转换为关系,这些表上的列将成为关系属性

如果您将上面列表中的项目应用于我们查找 Alice 部门的示例,我们可以得出如下所示的图表。

在这里插入图片描述

尽管这两个模型具有相似之处,例如使用表结构或标签对数据进行分类,但图形模型不会将数据限制在预定义的严格表/列布局中。我们将在下一节中查看另一个示例。

为了给我们另一个练习的机会,我们将使用一个标准的组织域,并展示如何在关系数据库和图形数据库中对其进行建模。为了给自己一个额外的挑战,请尝试自己创建图形数据模型,然后看看它有多紧密。

在这里插入图片描述

首先,我们可以按主域表对表进行分类,按颜色对关联实体表进行分类。然后,我们可以将表名转换为节点标签。在本例中, Project 、Person、 Department 和 Organization 成为图模型中的标签。

表上的行成为它们自己的节点,这些行中的列成为这些节点上的属性。例如, Person 表上的行将成为一个节点,姓名和出生日期作为节点上的属性。任何允许多个相似值的索引列都将成为数组(例如 skill1、skill2、skill3 列转换为存储在节点上的数组属性中的三个值)。

如果存在任何技术主键(换言之,创建主键只是为了使行唯一,例如project_id,以防有多个具有相同标题的项目),则删除这些主键,仅保留业务需求所需的属性。您还需要为业务主键添加唯一的约束,以确保数据库不允许重复。

有助于关系联接查找的外键被转换为关系,因为它们显示了节点之间的链接。关联实体表也将成为关系,关联实体表的列都转换为关系的属性。

由于您在 Neo4j 中存储所需的属性,因此不需要存储 null 值和空值,因此可以删除可能在关系模型中创建的任何默认值。

最后,为了简单起见,为规范化表或反规范化而创建的任何重复数据都需要删除,因为在图形中不需要这些数据。

完成此过程后,图形数据模型应如下图所示。

在这里插入图片描述

1.2.3 图模型重构

1.2.3.1 初始模型

本指南使用包含 2008 年 1 月美国机场之间连接的机场数据集。数据以 CSV 文件的形式显示。下面你可以看到数据库的图模型:

在这里插入图片描述

在导入任何数据之前,应在 Airport 标签和 code 属性上创建唯一约束,以确保不会意外导入重复的机场。以下查询创建约束:

CREATE CONSTRAINT airport_id  
FOR (airport:Airport) REQUIRE airport.code IS UNIQUE

以下查询使用该 LOAD CSV 工具从 CSV 文件加载数据:

LOAD CSV WITH HEADERS FROM "https://raw.githubusercontent.com/neo4j-contrib/training/master/modeling/data/flights_1k.csv" AS row   
MERGE (origin:Airport {code: row.Origin})
MERGE (destination:Airport {code: row.Dest})
MERGE (origin)-[connection:CONNECTED_TO {airline: row.UniqueCarrier,flightNumber: row.FlightNum,date: date({year: toInteger(row.Year), month: toInteger(row.Month), day: toInteger(row.DayofMonth)}),cancelled: row.Cancelled,diverted: row.Diverted}]->(destination)
ON CREATE SET connection.departure = localtime(apoc.text.lpad(row.CRSDepTime, 4, "0")),connection.arrival = localtime(apoc.text.lpad(row.CRSArrTime, 4, "0"))

上述查询:

  • 创建一个带有 Airport 标签的节点,该 code 标签的属性具有 CSV 文件中列 Origin 中的值。
  • 创建一个带有 Airport 标签的节点,该 code 标签的属性具有 CSV 文件中列 Dest 中的值。
  • 根据 CSV 文件中的列创建具有多个属性的类型 CONNECTED_TO 关系。

这是一个起始模型,但您可以进行一些改进。

1.2.3.2 将属性转换为布尔值

CONNECTED_TO 关系的 diverted and cancelled 属性包含 和 01 字符串值。由于这些值表示布尔值,因此可以使用该 apoc.refactor.normalizeAsBoolean 程序将值从字符串转换为布尔值。

以下查询对 diverted 属性进行转换:

MATCH (:Airport)-[connectedTo:CONNECTED_TO]->(:Airport) 
CALL apoc.refactor.normalizeAsBoolean(connectedTo, "diverted", ["1"], ["0"])
RETURN count(*)

apoc.refactor.normalizeAsBoolean(entity ANY, propertyKey STRING, trueValues LIST<ANY>, falseValues LIST<ANY>) 将给定属性重构为 BOOLEAN

在这里插入图片描述

以下查询执行 cancelled 属性的转换:

MATCH (origin:Airport)-[connectedTo:CONNECTED_TO]->(departure)  
CALL apoc.refactor.normalizeAsBoolean(connectedTo, "cancelled", ["1"], ["0"])
RETURN count(*)

如果要更新大量关系,则在尝试在一个事务中重构所有关系时可能会遇到 OutOfMemory 异常。因此,您可以使用该 apoc.periodic.iterate 过程批量处理关系。以下查询对同一查询中的 cancelled and reverted 属性执行此操作:

UNWIND ["cancelled", "reverted"] AS propertyToDelete
CALL apoc.periodic.iterate("MATCH (:Airport)-[connectedTo:CONNECTED_TO]->(:Airport) RETURN connectedTo",     "CALL apoc.refactor.normalizeAsBoolean(connectedTo, $propertyToDelete, ['1'], ['0'])RETURN count(*)",{params: {propertyToDelete: propertyToDelete}, batchSize: 100})
YIELD batches
RETURN propertyToDelete, batches

apoc.periodic.iterate(cypherIterate STRING, cypherAction STRING, config MAP) :为第一条语句返回的每个项目运行第二条语句。此过程返回批数和已处理行总数。

完成此操作后,可以编写以下查询以返回所有已取消的连接:

MATCH (origin:Airport)-[connectedTo:CONNECTED_TO]->(destination)  
WHERE connectedTo.cancelled
RETURN origin.code AS origin,destination.code AS destination,connectedTo.date AS date,connectedTo.departure AS departure,connectedTo.arrival AS arrival
1.2.3.3 从关系创建节点

使用现有数据模型,编写查找特定航班的查询可能会成为一项复杂的任务。那是因为这里的航班表示为关系。但是,您可以通过从 CONNECTED_TO 存储在关系上的属性创建 Flight 节点来更改模型:

在这里插入图片描述

以下查询执行此重构:

CALL apoc.periodic.iterate("MATCH (origin:Airport)-[connected:CONNECTED_TO]->(destination:Airport) RETURN origin, connected, destination",     "CREATE (flight:Flight {date: connected.date,airline: connected.airline,number: connected.flightNumber,departure: connected.departure,arrival: connected.arrival,cancelled: connected.cancelled,diverted: connected.diverted})MERGE (origin)<-[:ORIGIN]-(flight)MERGE (flight)-[:DESTINATION]->(destination)DELETE connected",{batchSize: 100})

此查询使用 apoc.periodic.iterate 程序,以便批量执行重构,而不是在单个事务中执行重构。该过程采用三个参数:

  • 一个外部 Cypher 查询,用于查找并返回关系流 CONNECTED_TO ,以及需要处理的始发地和目的地机场。
  • 处理这些实体的内部 Cypher 查询,创建带有标签 Flight 的节点,并创建从该节点到始发地和目的地机场的关系。
  • batchSize 配置,设置为 100 在单个事务中运行的内部语句数。

您也可以使用该 apoc.refactor.extractNode 过程执行此重构。

CALL apoc.periodic.iterate("MATCH (origin:Airport)-[connected:CONNECTED_TO]->(destination:Airport)  RETURN origin, connected, destination","CALL apoc.refactor.extractNode([connected], ['Flight'], 'DESTINATION', 'ORIGIN')YIELD input, output, errorRETURN input, output, error",{batchSize: 100});

apoc.refactor.extractNode(rels ANY, labels LIST, outType STRING, inType STRING):将给定 RELATIONSHIP 的 VALUES 扩展为中间 NODE 值。中间 NODE 值由给定 outType 的 和 inType 连接。

这与上一个查询相同,但外部 Cypher 查询使用该 apoc.refactor.extractNode 过程创建 Flight 节点并创建与始发地和目的地机场的关系。如果我们运行此查询,我们将看到以下输出:

1.2.3.4 从属性创建节点

目前,航空公司名称存储在 Flight 节点上的 airline 属性中。这意味着,如果您想返回所有航空公司的流,您必须扫描每个航班并检查每个航班上的 airline 属性。

您可以通过为每个航空公司创建一个带有 Airline 标签的节点来使此任务更简单、更高效:

在这里插入图片描述

首先,在 Airline 标签和 name 属性上创建约束,以避免重复的航空公司节点:

CREATE CONSTRAINT airline_id
FOR (airline:Airline) REQUIRE airline.name IS UNIQUE

现在,可以运行以下查询来执行重构:

CALL apoc.periodic.iterate('MATCH (flight:Flight) RETURN flight','MERGE (airline:Airline {name:flight.airline})   MERGE (flight)-[:AIRLINE]->(airline)REMOVE flight.airline',{batchSize:10000, iterateList:true, parallel:false}
)

上述查询同样使用具有以下参数的程序 apoc.periodic.iterate

  • 一个外部 Cypher 语句,返回要处理的Flight节点流。
  • 一个内部 Cypher 语句,用于处理 Flight 节点并基于 airline 属性创建 Airline 节点。它还创建从 Flight 节点到 Airline 节点 AIRLINE 的关系。然后从 Flight 节点中删除该 airline 属性。

然后,您可以编写以下查询来查找涉及每个航空公司的航空公司和航班数:

MATCH (airline:Airline)<-[:AIRLINE]-(:Flight)
RETURN airline.name AS airline, count(*) AS numberOfFlights

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

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

相关文章

【大模型】大模型时代的语音合成:音频的离散化表示

&#x1f512;文章目录 &#x1f4ca;什么是音频离散化&#x1f3ac;音频离散化是什么 &#x1f308;SoundStream、Encodec&#x1f302; SoundStream&#x1f680;Encodec &#x1f4ca;什么是音频离散化 &#x1f3ac;音频离散化是什么 在自然语言处理&#xff08;NLP&…

Amazon云计算AWS之[2]弹性计算云EC2

文章目录 说明EC2基本架构Amazon机器映象&#xff08;AMI&#xff09;实例&#xff08;Instance&#xff09;弹性块存储&#xff08;EBS&#xff09; EC2关键技术地理区域和可用区域EC2通信机制弹性负载均衡监控服务自动缩放服务管理控制台 EC2安全及容错机制EC2弹性IP地址 说明…

KingbaseES数据库copy导入导出

数据库版本&#xff1a;KingbaseES V008R006C008B0014 文章目录如下 1. 语法说明 2. 导出数据 2.1. 基本用法 2.2. 只导出某列 2.3. 指定分隔符 2.4. 导出为二进制格式 2.5. 替换导出的NULL数据 2.6. 导出SELECT查询结果 3. 导入数据 3.1. 基本用法 3.2. 只导入某列…

恒峰智慧科技—森林消防泵:既可灭除火灾,又可清理水患

在广袤的森林中&#xff0c;火灾与水患如同潜伏的猛兽&#xff0c;时刻威胁着生态的安全。然而&#xff0c;随着科技的进步&#xff0c;我们有了更强大的武器来对抗这些威胁——森林消防泵。这款神奇的设备不仅能迅速扑灭火灾&#xff0c;还能在雨季到来时清理水患&#xff0c;…

Linux:进程与计划任务

文章目录 Linux&#xff1a;进程与计划任务一、进程1、进程是什么2、进程状态 二、列出进程命令1、查看静态的进程统计信息——“ps”Play1&#xff1a;“ps aux”Play2:ps -elf 2、查看静态的进程统计信息——“top”段首解析进程信息区解释 三、运行与终止进程3.1、运行进程3…

spring的跨域问题

跨域问题 什么是跨域解决跨域 什么是跨域 跨域问题本质是浏览器的一种保护机制&#xff0c;它的初衷是为了保证用户的安全&#xff0c;防止恶意网站窃取数据。如果出现了以下情况中的任意一种&#xff0c;那么它就是跨域请求&#xff1a; 1、协议不同&#xff0c;如 http 和 h…

Redis入门到通关之Redis数据结构-List篇

文章目录 ☃️概述☃️数据结构☃️源码☃️其他 欢迎来到 请回答1024 的博客 &#x1f353;&#x1f353;&#x1f353;欢迎来到 请回答1024的博客 关于博主&#xff1a; 我是 请回答1024&#xff0c;一个追求数学与计算的边界、时间与空间的平衡&#xff0c;0与1的延伸的后端…

8、案例实战【处理百万级交易无压力】:支付系统JVM调优实战指南

8.1、前文回顾 本文将以一个日交易量达百万次的支付系统为背景,为大家深入分析在上线部署一个系统时,如何根据系统的业务量来合理设置JVM的堆内存大小。 通过阅读之前的文章,相信大家已经对编写的代码如何在JVM中运行的基本原理有了一定的了解,同时也知道如何通过参数来设…

数据结构(Wrong Question)

一、绪论 1.1 数据结构的基本概念 D 因为抽象数据类型&#xff08;ADT&#xff09;描述了数据的逻辑结构和抽象运算&#xff0c;通常用&#xff08;数据对象&#xff0c;数据对象&#xff0c;基本操作集&#xff09;这样的三元组来表示&#xff0c;从而可构成一个完整的数据结…

3节点ubuntu24.04服务器docker-compose方式部署高可用elk+kafka日志系统并接入nginx日志

一&#xff1a;系统版本: 二&#xff1a;部署环境&#xff1a; 节点名称 IP 部署组件及版本 配置文件路径 机器CPU 机器内存 机器存储 Log-001 10.10.100.1 zookeeper:3.4.13 kafka:2.8.1 elasticsearch:7.7.0 logstash:7.7.0 kibana:7.7.0 zookeeper:/data/zookeep…

(Oracle)SQL优化案例:组合索引优化

项目场景 项目上的ETL模型里有如下SQL语句。执行速度非常慢&#xff0c;每次只查询200条数据&#xff0c;但却需要20多秒的时间。再加上该SQL查询出的数据同步频率很高&#xff0c;这个速度是完全不能忍受的。 因为项目隐私&#xff0c;所以对表及字段做了改写。 SELECT ID…

DaVinci Fusion Studio 19 for Mac/win:影视后期特效合成的巅峰之作

在影视后期制作的广袤天地里&#xff0c;一款强大的特效合成软件如同一位技艺高超的魔法师&#xff0c;能够化腐朽为神奇&#xff0c;将普通的影像素材转变为震撼人心的视觉盛宴。而DaVinci Fusion Studio 19&#xff0c;正是这样一款备受影视从业者推崇的巅峰之作。 无论是Ma…

基于Python+Selenium+Pytest的Dockerfile如何写

使用 Dockerfile 部署 Python 应用程序与 Selenium 测试 在本文中&#xff0c;我们将介绍如何使用 Dockerfile 部署一个 Python 应用程序&#xff0c;同时利用 Selenium 进行自动化测试。我们将使用官方的 Python 运行时作为父镜像&#xff0c;并在其中安装所需的依赖项和工具…

Android视角看鸿蒙第十二课-鸿蒙的布局之相对布局RelativeContainer

Android视角看鸿蒙第十二课-鸿蒙的布局之相对布局RelativeContainer 导读 相对布局和线性、层叠布局一样都是类似于Android布局的&#xff0c;之前两篇文章已经了解线性、层叠布局的使用方法&#xff0c;这篇文章一起来学习下鸿蒙中的相对布局。 之前的文章中&#xff0c;我偶…

VNISEdit 制作安装包

1. 环境依赖 1.1. NSIS 下载 下载地址&#xff1a;https://nsis.sourceforge.io/Download 1.2. VNISEdit 下载 下载地址1&#xff1a;https://sourceforge.net/projects/hmne/ 下载 exe 安装。 下载地址2&#xff1a;https://hmne.sourceforge.net/ 可以下载 exe 安装。也…

centos 安装配置文件中心 nacos2.2.3 稳定版

安装mysql 8 参考文章 centos7搭建mysql5.6 && mysql 8.0_centos7 mysql5.6-CSDN博客 安装 jdk 17 官网下载 对应的版本 Java Downloads | Oracle wget https://download.java.net/java/GA/jdk17.0.2/dfd4a8d0985749f896bed50d7138ee7f/8/GPL/openjdk-17.0.2_l…

在excel中,如何在一个表中删除和另一个表中相同的数据?

现在有A表&#xff0c;是活动全部人员的姓名和学号&#xff0c;B表是该活动中获得优秀人员的姓名和学号&#xff0c; 怎么提取没有获得优秀人员的名单&#xff1f; 这里提供两个使用excel基础功能的操作方法。 1.条件格式自动筛选 1.1按住Ctrl键&#xff0c;选中全表中的姓…

Flutter 上架如何解决 ITMS-91053 问题

最近&#xff0c;我的 Flutter App 发布到 TestFlight 后&#xff0c;就会收到一封邮件&#xff1a;The uploaded build for YOUR APP has one or more issues. 上面的邮件主要是说&#xff0c;我的 App 缺少了调用 API 的声明&#xff0c;以前从来没看到过&#xff0c;上网一查…

SpringBoot+Vue开发记录(三)

说明&#xff1a;本篇文章的主要内容为需求分析。需求分析这一部分很重要&#xff0c;也稍微有点子难搞&#xff0c;所以本篇文章里的有些内容会有失偏颇。 一、准备步骤 我打算做一个刷题项目&#xff0c;但是具体这个项目该怎么做&#xff0c;我是一头雾水。 所以就要先进行…

消灭AI“耗电巨兽”?暴雨服务器推出液冷节能降耗算力方案

在科技飞速发展的今天&#xff0c;人工智能已成为驱动未来的重要力量。随着AI及大模型技术的进一步普及和应用场景的拓宽&#xff0c;相关算力需求呈指数级增长&#xff0c;大规模的AI训练和推理过程均需消耗大量电力&#xff0c;如同一个巨大的电力黑洞&#xff0c;吞噬着海量…