DuckDB 的 AsOf 连接:模糊时态查找

news2024/12/28 22:22:05


概要

 

DuckDB 支持 AsOf Joins——一种匹配附近值的方法。 它们对于搜索事件表以进行时间分析特别有用。

有想要连接的时间序列数据但时间戳不太匹配? 或者想使用另一个表中的时间查找随时间变化的值? 最终是否编写了复杂(且缓慢)的不等值连接来获得结果? 那么这篇文章适合你!

什么是 AsOf 连接?

时间序列数据并不总是完全一致。 时钟可能略有偏差,或者原因和结果之间可能存在延迟。 这可能会给连接两组有序数据带来挑战。 AsOf Joins 是解决此问题和其他类似问题的工具。

AsOf Joins 用于解决的问题之一是查找特定时间点的变化属性的值。 这个用例非常常见,因此它的名字就来自于:

请告诉我目前property的值

然而,更一般地说,AsOf 连接体现了一些常见的时间分析语义,这些语义在标准 SQL 中实现起来可能很麻烦且缓慢。

投资组合示例

让我们从一个具体的例子开始。 假设我们有一个带有时间戳的股票价格表:

tickerwhenprice
APPL2001-01-01 00:00:001
APPL2001-01-01 00:01:002
APPL2001-01-01 00:02:003
MSFT2001-01-01 00:00:001
MSFT2001-01-01 00:01:002
MSFT2001-01-01 00:02:003
GOOG2001-01-01 00:00:001
GOOG2001-01-01 00:01:002
GOOG2001-01-01 00:02:003

我们还有另一个表,其中包含不同时间点的投资组合持有量:

tickerwhenshares
APPL2000-12-31 23:59:305.16
APPL2001-01-01 00:00:302.94
APPL2001-01-01 00:01:3024.13
GOOG2000-12-31 23:59:309.33
GOOG2001-01-01 00:00:3023.45
GOOG2001-01-01 00:01:3010.58
DATA2000-12-31 23:59:306.65
DATA2001-01-01 00:00:3017.95
DATA2001-01-01 00:01:3018.37

我们可以通过使用 AsOf Join 查找持有时间戳之前的最新价格来计算该时间点每个持有的价值:

SELECT h.ticker, h.when, price * shares AS value
FROM holdings h ASOF JOIN prices p
  ON h.ticker = p.ticker
 AND h.when >= p.when

这会将当时持有的价值附加到每一行:

tickerwhenvalue
APPL2001-01-01 00:00:302.94
APPL2001-01-01 00:01:3048.26
GOOG2001-01-01 00:00:3023.45
GOOG2001-01-01 00:01:3021.16

它本质上执行一个通过在价格表中查找附近值来定义的函数。 另请注意,缺失的股票代码值没有匹配项,并且不会出现在输出中。

外部 AsOf 连接

由于 AsOf 最多从右侧生成一个匹配项,因此左侧表不会因连接而增长,但如果右侧有缺失时间,左侧表可能会缩小。 为了处理这种情况可以使用外部 AsOf 连接:

SELECT h.ticker, h.when, price * shares AS value
FROM holdings h ASOF LEFT JOIN prices p
  ON h.ticker = p.ticker
 AND h.when >= p.when
ORDER BY ALL

正如所期望的,当没有股票行情或时间在价格开始之前时,这将产生 NULL 价格和值,而不是删除左侧行。

tickerwhenvalue
APPL2000-12-31 23:59:30
APPL2001-01-01 00:00:302.94
APPL2001-01-01 00:01:3048.26
GOOG2000-12-31 23:59:30
GOOG2001-01-01 00:00:3023.45
GOOG2001-01-01 00:01:3021.16
DATA2000-12-31 23:59:30
DATA2001-01-01 00:00:30
DATA2001-01-01 00:01:30

窗口替代方案

标准 SQL 可以实现这种连接,但需要使用窗口函数和不等式连接。 这些操作都可能相当昂贵,但查询如下所示:

WITH state AS (
  SELECT ticker, when, price,
    LEAD(when, 1, 'infinity') OVER (PARTITION BY ticker ORDER BY when) AS end
),
SELECT ticker, h.when, price * shares AS value
FROM holdings h INNER JOIN state s
  ON h.ticker = s.ticker
 AND h.when >= s.when
 AND h.when < s.end

默认值无穷大用于确保最后一行有一个可以比较的结束值。 对于我们的示例,状态 CTE 如下所示:

tickerpricewhenend
APPL12001-01-01 00:00:002001-01-01 00:01:00
APPL22001-01-01 00:01:002001-01-01 00:02:00
APPL32001-01-01 00:02:00infinity
GOOG12001-01-01 00:00:002001-01-01 00:01:00
GOOG22001-01-01 00:01:002001-01-01 00:02:00
GOOG32001-01-01 00:02:00infinity
MSFT12001-01-01 00:00:002001-01-01 00:01:00
MSFT22001-01-01 00:01:002001-01-01 00:02:00
MSFT32001-01-01 00:02:00infinity

在没有相等条件的情况下,规划器将不得不使用不等式连接,这可能非常昂贵。 即使在相等条件的情况下,生成的散列连接也可能最终得到相同的代码键的长链,这些键都将匹配并需要裁剪。

为什么是 AsOf?

如果 SQL 已经可以计算 AsOf 连接,为什么我们需要新的连接类型? 有两个重要原因:可表达性和性能。 窗口替代方案比 AsOf 语法更冗长且更难理解,因此更容易说出您正在做的事情可以帮助其他人(甚至您!)理解正在发生的事情。

该语法还使 DuckDB 更容易理解您想要的内容并更快地生成结果。 窗口和不等式连接版本丢失了间隔不重叠的有价值的信息。 它还可以防止查询优化器移动连接,因为 SQL 坚持在连接之后进行窗口化。 通过将操作视为具有已知数据约束的联接,DuckDB 可以移动联接以提高性能并使用定制的联接算法。 我们使用的算法是对右侧表进行排序,然后与左侧值进行某种合并连接。 但与标准合并联接不同,AsOf 可以在找到第一个匹配项时停止搜索,因为最多有一个匹配项。

状态表

可能想知道为什么WITH 子句中的公共表表达式被称为状态。 这是因为价格表实际上是时间分析中所谓的事件表的一个示例。 事件表的行包含时间戳和当时发生的事情(即事件)。 价格表中的事件是股票价格的变化。 事件表的另一个常见示例是结构化日志文件:日志的每一行记录“发生”某事的时间——通常是对系统一部分的更改。

事件表很难使用,因为每个事实只有开始时间。 为了知道事实是否仍然正确(或在特定时间正确),还需要结束时间。 具有开始时间和结束时间的表称为状态表。 将事件表转换为状态表是一项常见的时态数据准备任务,上面的窗口 CTE 显示了如何使用 SQL 来完成此任务。

哨兵值

窗口方法的一个限制是排序类型需要具有在不支持无穷大时可以使用的哨兵值(未使用的值或 NULL)。

这两种选择都可能存在问题。 在第一种情况下,确定上哨兵值可能并不容易(假设排序是字符串列?)在第二种情况下,您需要将条件编写为 h.when < s.end OR s.end IS NULL 并在连接条件中使用这样的 OR 会使比较变慢并且难以优化。 此外,如果排序列已使用 NULL 来指示缺失值,则此选项不可用。

对于大多数状态表,都有合适的选择(例如大日期),但 AsOf 的优点之一是,如果分析任务不需要状态表,它可以避免设计状态表。

事件表变体

到目前为止,我们一直在使用标准类型的事件表,其中时间戳被假定为状态转换的开始。 但 AsOf 现在可以使用任何不等式,这使其能够处理其他类型的事件表。

为了探索这一点,让我们使用两个非常简单的表,没有相等条件。 构建端只有四个带有字母值的整数“时间戳”:

TimeValue
1a
2b
3c
4d

探测表只是时间值加上中点,我们可以制作一个表来显示每个探测时间匹配的值大于或等于:

Probe>=
0.5
1.0a
1.5a
2.0b
2.5b
3.0c
3.5c
4.0d
4.5d

这表明探测值匹配的区间处于半开区间[Tn,Tn+1)内。

现在让我们看看如果使用严格大于作为不等式会发生什么:

Probe>
0.5
1.0
1.5a
2.0a
2.5b
3.0b
3.5c
4.0c
4.5d

现在我们可以看到探针值匹配的区间处于半开区间(Tn,Tn+1]。唯一的区别是该区间在末尾而不是在开头闭合。这意味着对于这种不等式类型 ,时间不是间隔的一部分。

如果不等式向另一个方向发展(例如小于或等于)怎么办?

Probe<=
0.5a
1.0a
1.5b
2.0b
2.5c
3.0c
3.5d
4.0d
4.5

同样,我们有半开间隔,但这次我们匹配前一个间隔 (Tn-1, Tn]。解释这一点的一种方法是构建表中的时间是间隔的结束时间,而不是开始时间 .此外,与大于或等于不同,间隔在末尾而不是在开始处闭合。将其添加到我们发现的严格大于的内容中,我们可以将其解释为意味着当非时查找时间是间隔的一部分 - 使用严格的不等式。

我们可以通过查看最后一个不等式来检查这一点:严格小于:

Probe<
0.5a
1.0b
1.5b
2.0c
2.5c
3.0d
3.5d
4.0
4.5

在这种情况下,匹配间隔是[Tn-1, Tn)。 这是一个严格的不等式,所以表时间不在区间内,而且是一个小于,所以时间是区间结束的时间。

总而言之,以下是完整列表:

InequalityInterval
>(Tn, Tn+1]
>=[Tn, Tn+1)
<=(Tn-1, Tn]
<[Tn-1, Tn)

现在我们对不平等的含义有两种自然的解释:

  • • 大于(或小于)不等式意味着该时间是间隔的开始(或结束)。

  • • 严格(或非严格)不等式意味着时间被排除在(或包含在)间隔之外。

因此,如果我们知道时间是事件的开始还是结束,以及时间是包含还是排除,我们就可以选择适当的 AsOf 不等式。

用法

到目前为止,我们已经明确指定 AsOf 的条件,但 SQL 还针对两个表中列名相同的常见情况提供了简化的连接条件语法。 此语法使用 USING 关键字列出应比较相等性的字段。 AsOf 也支持此语法,但有两个限制:

  • • 最后一个字段是不等式

  • • 不等式为 >= (最常见的情况)

我们的第一个查询可以写成:

SELECT ticker, h.when, price * shares AS value
FROM holdings h ASOF JOIN prices p USING(ticker, when)

请注意,如果您没有在 SELECT 中显式列出列,则排序字段值将是探测值,而不是构建值。 对于自然连接,这不是问题,因为所有条件都是相等的,但对于 AsOf,必须选择一侧。 由于 AsOf 可以被视为查找函数,因此返回“函数参数”比函数内部更自然。

原理

AsOf 连接真正做的事情是允许将事件表视为连接操作的状态表。 通过了解连接的语义,它可以避免创建完整的状态表,并且比一般的不等式连接更有效。

让我们首先看看窗口版本是如何工作的。 请记住,我们使用此查询将事件表转换为状态表:

WITH state AS (
  SELECT ticker, when, price,
    LEAD(when, 1, 'infinity') OVER(PARTITION BY ticker ORDER BY when) AS end
),

状态表 CTE 是通过在代码上对表进行哈希分区、按时间排序,然后计算恰好向下移动 1 的另一列来创建的。 然后通过股票上的散列连接和时间上的两次比较来实现连接。

如果没有股票行情列(例如,单个商品的价格),那么将使用我们的不等式连接运算符来实现连接,该运算符将实现并对两侧进行排序,因为它不知道范围是不相交的。

AsOf 运算符使用所有三个运算符管道 API 来合并和收集行。 在接收阶段,AsOf 哈希分区并对右侧进行排序以生成临时状态表。 (事实上,它使用与 Window 相同的代码,但没有不必要地具体化结束列。)在运算符阶段,它会过滤掉(或返回)由于谓词表达式中的 NULL 值而无法匹配的行,然后进行哈希分区和 将剩余的行排序到缓存中。 最后,在源阶段,它匹配哈希分区,然后合并连接每个哈希分区内的排序值。

基准测试

由于 AsOf 连接可以使用标准 SQL 查询以多种方式实现,因此基准测试实际上是比较各种替代方案。

一种替代方法是名为 debug_asof_iejoin 的 AsOf 调试 PRAGMA,它使用 Window 和 IEJoin 实现连接。 这使我们能够轻松地在实现之间切换并比较运行时间。

其他替代方案结合了等连接和窗口函数。 等值连接用于实现等式匹配条件,窗口用于选择最接近的不等式。 我们现在将研究两种不同的窗口技术并比较它们的性能。 最重要的是,虽然 AsOf 连接有时会更快一些,但 AsOf 连接具有所有算法中最一致的行为。

窗口作为状态表

第一个基准测试将哈希连接与状态表进行比较。 它使用自连接探测由 100K 时间戳和 50 个分区键构建的 5M 行值表,其中仅存在 50% 的键,并且时间戳已移动到原始时间戳的中间位置:

CREATE TABLE build AS (
  SELECT k, '2001-01-01 00:00:00'::TIMESTAMP + INTERVAL (v) MINUTE AS t, v
  FROM range(0,100000) vals(v), range(0,50) keys(k)
);

CREATE TABLE probe AS (
  SELECT k * 2 AS k, t - INTERVAL (30) SECOND AS t
  FROM build
);

构建表如下所示:

ktv
02001-01-01 00:00:000
02001-01-01 00:01:001
02001-01-01 00:02:002
02001-01-01 00:03:003

探测表如下所示(k 只有偶数值):

kt
02000-12-31 23:59:30
02001-01-01 00:00:30
02001-01-01 00:01:30
02001-01-01 00:02:30
02001-01-01 00:03:30

基准测试只是进行连接并对 v 列求和:

SELECT SUM(v)
FROM probe ASOF JOIN build USING(k, t);

调试PRAGMA不允许我们使用散列连接,但我们可以再次在CTE中创建状态表并使用内连接:

-- Hash Join implementation
WITH state AS (
  SELECT k, 
    t AS begin, 
    v, 
    LEAD(t, 1, 'infinity'::TIMESTAMP) OVER (PARTITION BY k ORDER BY t) AS end
  FROM build
)
SELECT SUM(v)
FROM probe p INNER JOIN state s 
  ON p.t >= s.begin AND p.t < s.end AND p.k = s.k

这是有效的,因为规划器假设相等条件比不等式更具选择性,并使用过滤器生成哈希连接。

运行基准测试,我们得到如下结果:

AlgorithmMedian of 5
AsOf0.425
IEJoin3.522
State Join192.460

AsOf 相对于 IEJoin 的运行时改进约为 9 倍。 Hash Join 糟糕的性能是由哈希表中的长(100K)桶链造成的。

第二个基准测试测试探针侧比构建侧小约 10 倍的情况:

CREATE TABLE probe AS
  SELECT k, 
    '2021-01-01T00:00:00'::TIMESTAMP + INTERVAL (random() * 60 * 60 * 24 * 365) SECOND AS t,
  FROM range(0, 100000) tbl(k);

CREATE TABLE build AS
  SELECT r % 100000 AS k, 
    '2021-01-01T00:00:00'::TIMESTAMP + INTERVAL (random() * 60 * 60 * 24 * 365) SECOND AS t,
    (random() * 100000)::INTEGER AS v
  FROM range(0, 1000000) tbl(r);

SELECT SUM(v)
FROM probe p
ASOF JOIN build b
  ON p.k = b.k
 AND p.t >= b.t

-- Hash Join Version
WITH state AS (
  SELECT k, 
    t AS begin, 
    v, 
    LEAD(t, 1, 'infinity'::TIMESTAMP) OVER (PARTITION BY k ORDER BY t) AS end
  FROM build
)
SELECT SUM(v)
FROM probe p INNER JOIN state s
  ON p.t >= s.begin AND p.t < s.end AND p.k = s.k
AlgorithmMedian of 5
State Join0.065
AsOf0.077
IEJoin49.508

现在,AsOf 相对 IEJoin 的运行时改进是巨大的(约 500 倍),因为它可以利用分区来消除几乎所有的等式不匹配。

哈希连接实现在这里做得更好,因为优化器注意到探测端较小,并在“探测”表上构建哈希表。 此外,这里的探测值是唯一的,因此哈希表链是最小的。

排名窗口

使用窗口运算符的另一种方法是:

  • • 根据相等谓词连接表

  • • 过滤到构建时间早于探测时间的对

  • • 根据等式键和探测时间戳对结果进行分区

  • • 按构建时间戳降序对分区进行排序

  • • 过滤掉除排名 1 之外的所有值(即最大构建时间 <= 探测时间)

查询如下所示:

WITH win AS (
SELECT p.k, p.t, v,
    rank() OVER (PARTITION BY p.k, p.t ORDER BY b.t DESC) AS r
FROM probe p INNER JOIN build b
  ON p.k = b.k
 AND p.t >= b.t
QUALIFY r = 1
) 
SELECT k, t, v
FROM win

此窗口查询的优点是它不需要哨兵值,因此它可以处理任何数据类型。 缺点是它会创建更多分区,因为它包含两个时间戳,这需要更复杂的排序。 此外,由于它在连接后应用窗口,因此可能会产生巨大的中间产物,从而导致外部排序和昂贵的内存不足操作。

对于此基准测试,我们将使用三个构建表和两个探测表,全部包含 10K 整数相等键。 探测表的每个键有 1 或 15 个时间戳:

CREATE TABLE probe15 AS
    SELECT k, purchase_timestamp
    FROM range(10000) cs(k), 
         range('2022-01-01'::TIMESTAMP, '2023-01-01'::TIMESTAMP, INTERVAL 26 DAY) ts(t);
CREATE TABLE probe1 AS
    SELECT k, '2022-01-01'::TIMESTAMP + INTERVAL (customer_id) HOUR purchase_timestamp
    FROM range(10000) cs(k);

构建表要大得多,条目数大约是 15 个元素表的 10/100/1000 倍:

-- 10:1
CREATE TABLE build10 AS
    SELECT k, t, (RANDOM() * 1000)::DECIMAL(7,2) AS v
    FROM range(10000) ks(k), 
         range('2022-01-01'::TIMESTAMP, '2023-01-01'::TIMESTAMP, INTERVAL 59 HOUR) ts(t);
-- 100:1
CREATE TABLE build100 AS
    SELECT k, t, (RANDOM() * 1000)::DECIMAL(7,2) AS v
    FROM range(10000) ks(k), 
         range('2022-01-01'::TIMESTAMP, '2023-01-01'::TIMESTAMP, INTERVAL 350 MINUTE) ts(t);
-- 1000:1
CREATE TABLE build1000 AS
    SELECT k, t, (RANDOM() * 1000)::DECIMAL(7,2) AS v
    FROM range(10000) ks(k), 
         range('2022-01-01'::TIMESTAMP, '2023-01-01'::TIMESTAMP, INTERVAL 35 MINUTE) ts(t);

AsOf 连接查询是:

-- AsOf/IEJoin
SELECT p.k, p.t, v
FROM probe p ASOF JOIN build b
  ON p.k = b.k
 AND p.t >= b.t
ORDER BY 1, 2
-- Rank
WITH win AS (
SELECT p.k, p.t, v,
    rank() OVER (PARTITION BY p.k, p.t ORDER BY b.t DESC)  AS r
FROM probe p INNER JOIN build b
  ON p.k = b.k
 AND p.t >= b.t
QUALIFY r = 1
) 
SELECT k, t, v
FROM win
ORDER BY 1, 2

结果如下所示:

(中位数为 5,排名/15/1000 除外)。

  • • 对于具有 15 个探针的所有比率,AsOf 是性能最好的。

  • • 对于具有 15 个探针的小比例,Rank 击败了 IEJoin(均带有窗口),但到了 100:1,它开始爆炸。

  • • 对于单元素探针,Rank 是最有效的,但即使如此,它在规模上相对于 AsOf 的优势也只有 50% 左右。

这表明 AsOf 可能会得到改进,但预测发生这种情况的位置会很棘手,而且出错会带来巨大的成本。

未来的工作

DuckDB 现在可以以合理的性能对所有不等式类型执行 AsOf 连接。 在某些情况下,即使使用我们的快速不等式连接运算符,性能增益也比标准 SQL 版本高出几个数量级。

虽然当前的 AsOf 运算符完全通用,但这里可以应用一些规划优化。

当存在选择性相等条件时,针对物化状态表进行过滤的哈希连接可能会明显更快。 如果我们能够检测到这一点并且有合适的哨兵值可用,则规划器可以选择使用散列连接而不是默认的 AsOf 实现。 还有一些用例,其中探测表比构建表小得多,并且具有相等条件,并且针对探测表执行哈希联接可以显着提高性能。 尽管如此,请记住 SQL 的优点之一是它是一种声明性语言: 指定想要的内容,然后将其留给数据库来确定如何进行。 现在我们已经定义了 AsOf 连接的语义,用户可以编写查询来说明这就是想要的 - 并且我们可以自由地不断改进方法!

DuckDB 工作中最有趣的部分之一是它扩展了无序数据的传统 SQL 模型。 DuckDB 可以轻松查询有序数据集(例如数据框和 parquet 文件),当拥有此类数据时希望能够进行有序分析! 实现快速排序、快速窗口化和快速 AsOf 连接是我们实现这一期望的方式。

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

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

相关文章

【uniapp】Dcloud的uni手机号一键登录,具体实现及踩过的坑,调用uniCloud.getPhoneNumber(),uni.login()等

一键登录Dcloud官网请戳这里&#xff0c;感兴趣的可以看看官网&#xff0c;有很详细的示例&#xff0c;选择App一键登录&#xff0c;可以看到一些常用的概述 比如&#xff1a; 1、调用uni.login就能弹出一键登录的页面 2、一键登录的流程&#xff0c;可以选择先预登录uni.prelo…

mybatis学习记录(四)-----MyBatis核心配置文件详解

目录 MyBatis核心配置文件详解 4.1 environment 4.2 transactionManager 4.3 dataSource 4.4 properties 4.5 mapper MyBatis核心配置文件详解 mybatis-config.xml : <?xml version"1.0" encoding"UTF-8" ?> <!DOCTYPE configurationPUB…

安防视频监控平台EasyNVR无法控制云台,该如何解决?

TSINGSEE青犀视频安防监控平台EasyNVR可支持设备通过RTSP/Onvif协议接入&#xff0c;并能对接入的视频流进行处理与多端分发&#xff0c;包括RTSP、RTMP、HTTP-FLV、WS-FLV、HLS、WebRTC等多种格式。在智慧安防等视频监控场景中&#xff0c;EasyNVR可提供视频实时监控直播、云端…

高云FPGA系列教程(6):ARM定时器使用

文章目录 [toc]1. ARM定时器简介2. FPGA配置3. 常用函数4. MCU程序设计5. 工程下载 本文是高云FPGA系列教程的第6篇文章。 本篇文章介绍片上ARM Cortex-M3硬核处理器定时器外设的使用&#xff0c;演示定时器溢出中断的配置方法&#xff0c;基于TangNano 4K开发板。 参考文档&a…

虚拟机(VM)监控工具

什么是虚拟机&#xff08;VM&#xff09;监控 虚拟机监控是监视在虚拟化环境中创建的各个虚拟机和 VM 的过程&#xff0c;使用虚拟机监控软件&#xff0c;您可以查看可用性状态、性能统计信息并管理连接到主机的虚拟机及其相应的来宾虚拟机。 虚拟机监控有什么作用 在主机上…

Python:函数和代码复用

嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 &#x1f447; &#x1f447; &#x1f447; 更多精彩机密、教程&#xff0c;尽在下方&#xff0c;赶紧点击了解吧~ python源码、视频教程、插件安装教程、资料我都准备好了&#xff0c;直接在文末名片自取就可 1、关于递归函…

通义千问杀疯了!首发Qwen-VL-Chat模型的A卡本地部署教程

阿里云最新开源的通义千问视觉语言模型&#xff1a;Qwen-VL Qwen-VL 是一款支持中英文等多种语言的视觉语言&#xff08;Vision Language&#xff0c;VL&#xff09;模型&#xff0c;相较于此前的 VL 模型&#xff0c;其除了具备基本的图文识别、描述、问答及对话能力之外&…

明星翻包视频的崛起:探究背后的驱动力

近年来&#xff0c;社交媒体上涌现出越来越多的明星翻包视频&#xff0c;成为广大粉丝和观众们的追捧对象。这个趋势的背后是什么原因&#xff1f;为什么现今的明星都热衷于分享自己的私人物品和生活片段&#xff1f; 在明星翻包视频的制作和推广过程中&#xff0c;媒介易作为专…

【CSP认证考试】202303-1:田地丈量解题思路+代码

问题描述 西西艾弗岛上散落着 n 块田地。每块田地可视为平面直角坐标系下的一块矩形区域&#xff0c;由左下角坐标 (x1,y1) 和右上角坐标 (x2,y2) 唯一确定&#xff0c;且满足 x1<x2、y1<y2。这 n 块田地中&#xff0c;任意两块的交集面积均为 0&#xff0c;仅边界处可能…

vcruntime140.dll文件下载安装方法以及一些注意事项

其实vcruntime140.dll文件是Microsoft Visual C Redistributable Packages for Visual Studio 2015中的一个重要组件。它包含了Windows操作系统和其他应用程序所需的函数和资源&#xff0c;以确保它们能够正常运行。本文将为你介绍vcruntime140.dll文件的下载、使用以及解决常见…

java boolean占用内存是多少

一&#xff0c;结论 关于boolean占用内存是多少&#xff0c;我在JVM规范中找到以下解释&#xff0c;但是怎么验证呢&#xff1f; 虚拟机没有给boolean(布尔)类型设置单独指令。boolean型的数据是有integer指令&#xff0c;包括interger返回来处理的。boolean型数组则是用byte…

嵌入式开发会成为下一个Java吗?

今日话题&#xff0c;嵌入式开发会成为下一个Java吗&#xff1f;答案是否定的。嵌入式开发岗位通常属于制造业&#xff0c;特别是电器、机械、装备、航空航天等“智能制造”领域&#xff0c;属于重资产行业&#xff0c;相对稳定&#xff0c;不像互联网那样灵活。如果你有兴趣进…

FastDFS修改文件存储目录

修改下面文件&#xff0c;相关参数为1&#xff0c;则最终只保留1个目录&#xff0c;目录为00/00。 vi /etc/fdfs/storage.conf vi /storage.conf vi /fastdfs-5.11/conf/storage.conf

【Java|golang】337. 打家劫舍 III---树上最大独立集

详细视频: link 除了 root 之外&#xff0c;每栋房子有且只有一个“父“房子与之相连。一番侦察之后&#xff0c;聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果 两个直接相连的房子在同一天晚上被打劫 &#xff0c;房屋将自动报警。 给定二叉树的 roo…

在线文件二维码制作技巧,支持多种文件格式

怎么把一个文件放到二维码中呢&#xff1f;在日常工作中&#xff0c;使用办公文件多以word、excel、ppt等格式的文件为主&#xff0c;那么怎么把这些格式的文件生成二维码使用是很多小伙伴关注的一个问题。那么就让小编来给大家分享一招&#xff0c;通过浏览器来在线制作二维码…

上传项目到github上

在github上先创建一个空仓库 在github上新建一个仓库&#xff0c;点击你的头像&#xff0c;然后在出来的侧边栏选择 Your repositories 点击New创建一个新的仓库&#xff0c;即repository 输入你的仓库名称&#xff0c;选择public 或者 private. 尽量不要勾选README 如果你的…

微信小程序环境搭建

一、微信开发者工具 1. 微信公众平台注册小程序 注册类型选择‘个人’即可&#xff0c;‘企业’需要公司相关信息&#xff08;企业信用代码、法人信息等&#xff09;。 若只是学习阶段&#xff0c;忽略这步&#xff0c;使用测试号即可。 注册成功后&#xff0c;在‘开发’-…

【任务调度框架】「分析技术指南」带你一同盘点一下常用的任务调度框架的方案和原理开发指南

带你一同盘点一下常用的任务调度框架的方案和开发指南 任务调度JDK原生任务调度Java.Util — Timer&#xff08;单线程&#xff09;/ TimerTask&#xff08;任务调度&#xff09;Java.Util.Concurrent — 任务调度线程池 Spring任务调度机制Quartz任务调度机制简单的使用流程Tr…

精品SpringCloud图书馆管理系统-微服务-分布式

《[含文档PPT源码等]精品基于SpringCloud实现的图书馆管理系统的设计与实现-微服务-分布式》该项目含有源码、文档、PPT、配套开发软件、软件安装教程、项目发布教程等 软件开发环境及开发工具&#xff1a; 开发语言&#xff1a;Java 框架&#xff1a;springcloud JDK版本&…

【力扣-每日一题】337. 打家劫舍 III

class Solution { public:pair<int,int> dfs_rob(TreeNode *root){//如果为根节点if(rootnullptr)return {0,0};auto [l,l_n]dfs_rob(root->left);auto [r,r_n]dfs_rob(root->right);int ol_nr_nroot->val;//当前节点偷&#xff0c;所获得的利益,子节点不能偷in…