利用DuckDB的嵌套递归CTE实现动态规划

『AI先锋杯·14天征文挑战第8期』 10w+人浏览 328人参与

加粗样式

用Python实现的动态规划求解字符串分解函数如下:
其中a是待分解字符串,b是可分解为的子字符串集合。

def count_composition_ways_optimized(a: str, b: set) -> int:
    """
    优化版本:限制子串最大长度,提高效率
    """
    n = len(a)
    if n == 0:
        return 1
    
    # 计算集合中字符串的最大长度
    max_len = max(len(word) for word in b) if b else 0
    
    dp = [0] * (n + 1)
    dp[0] = 1
    
    for i in range(1, n + 1):
        # 只检查可能的子串长度,避免不必要的检查
        for length in range(1, min(i, max_len) + 1):
            start = i - length
            if a[start:i] in b:
                dp[i] += dp[start]
            #print(i, length,start,dp)
        print(i, dp)
    return dp[n]

a,b='bike', ['bi', 'l','ike']

print(count_composition_ways_optimized(a, b))

python dppy.txt" 
#a=bill
1 [1, 0, 0, 0, 0]
2 [1, 0, 1, 0, 0]
3 [1, 0, 1, 1, 0]
4 [1, 0, 1, 1, 1]
1

#a=bike
1 [1, 0, 0, 0, 0]
2 [1, 0, 1, 0, 0]
3 [1, 0, 1, 0, 0]
4 [1, 0, 1, 0, 0]
0

改写有如下几个难点:
1.python有两个循环,在内循环会多次修改dp[i]的值,而且要读取dp[start]的值,而CTE查询要在下一轮才能读到上次改后的值,通过保持完整的dp解决
2.python的字符串和数组索引都是从0开始,DuckDB的字符串和列表都是从1开始,用dp[0]访问返回NULL,与其他值运算后会把运算结果也变成NULL,需要单独判断0下标,然后用字面值代替。
3.平常的CTE终止条件都是<某个值,迭代次数不够,dp的值还未更改,需要改成<=才能取到更改后的dp。
最后形成的语句如下,

with recursive test as (select 'bill' a, ['bi', 'l','ike']b) --(select 'bike' a, ['bi', 'l','ike']b)-- 
, n as(select length(a) n from test)
, maxlen as(select array_aggr([len(word) for word in b], 'max') maxlen from test)
, dp as(select repeat([0], n)dp from n)
, t as(
    select True l,a,a a1,b, 1 i, dp from dp,test
    union all
    (with recursive d as( 
      select l lo,a,a1,b,i, 1 le, dp d from t
      union all
      select a[i-le+1:i] in b and i-(le) =0,a,a[i-le+1:i],b,i, le+1, d[1:i-1]||
                 [case when a[i-le+1:i] in b then d[i]+case when i-(le) >0 then d[i-(le)] else 1 end else d[i] end]
               ||d[i+1:] from  n, maxlen,d where le<=i --least(i, maxlen)
      )
    select lo,a,a1,b,d.i+1 lv, d from d  where d.i<=4 and le=d.i+1
    )
)
select a,b,dp[4]from t where i=5;

执行结果

.read dp1.txt
┌─────────┬──────────────┬───────┐
│    a    │      b       │ dp[4] │
│ varchar │  varchar[]   │ int32 │
├─────────┼──────────────┼───────┤
│ bike    │ [bi, l, ike] │     0 │
└─────────┴──────────────┴───────┘
.read dp1.txt
┌─────────┬──────────────┬───────┐
│    a    │      b       │ dp[4] │
│ varchar │  varchar[]   │ int32 │
├─────────┼──────────────┼───────┤
│ bill    │ [bi, l, ike] │     1 │
└─────────┴──────────────┴───────┘

可以把上述查询最后一条语句修改为select i,a,b,a1,dp from t查看中间结果,可见,除了dp[0]不存在,其他和python的结果一致。

┌───────┬─────────┬──────────────┬─────────┬──────────────┐
│   i   │    a    │      b       │   a1    │      dp      │
│ int32 │ varcharvarchar[]varchar │   int32[]    │
├───────┼─────────┼──────────────┼─────────┼──────────────┤
│     1 │ bill    │ [bi, l, ike] │ bill    │ [0, 0, 0, 0] │
│     2 │ bill    │ [bi, l, ike] │ b       │ [0, 0, 0, 0] │
│     3 │ bill    │ [bi, l, ike] │ bi      │ [0, 1, 0, 0] │
│     4 │ bill    │ [bi, l, ike] │ bil     │ [0, 1, 1, 0] │
│     5 │ bill    │ [bi, l, ike] │ bill    │ [0, 1, 1, 1] │
└───────┴─────────┴──────────────┴─────────┴──────────────┘
┌───────┬─────────┬──────────────┬─────────┬──────────────┐
│   i   │    a    │      b       │   a1    │      dp      │
│ int32 │ varcharvarchar[]varchar │   int32[]    │
├───────┼─────────┼──────────────┼─────────┼──────────────┤
│     1 │ bike    │ [bi, l, ike] │ bike    │ [0, 0, 0, 0] │
│     2 │ bike    │ [bi, l, ike] │ b       │ [0, 0, 0, 0] │
│     3 │ bike    │ [bi, l, ike] │ bi      │ [0, 1, 0, 0] │
│     4 │ bike    │ [bi, l, ike] │ bik     │ [0, 1, 0, 0] │
│     5 │ bike    │ [bi, l, ike] │ bike    │ [0, 1, 0, 0] │
└───────┴─────────┴──────────────┴─────────┴──────────────┘

这个实现还很初步,还不能对多行数据分解,需要进一步研究。

03-19
<think>嗯,用户让我介绍一下DuckDB。首先,我需要回忆一下DuckDB的基本信息。DuckDB是一个嵌入式的关系型数据库管理系统,对吧?它主要针对分析型查询,也就是OLAP场景。这点和SQLite有点像,不过SQLite更适合事务处理(OLTP),而DuckDB则是为分析优化的。 接下来,用户可能想知道DuckDB的特点。比如,它不需要单独的服务器,直接嵌入到应用程序中,这样部署起来很方便。另外,它支持标准的SQL,这对用户来说很重要,因为不需要学习新的查询语言。还有,它的列式存储引擎,这对分析查询来说性能更好,因为通常分析需要处理大量数据,列式存储可以更快地扫描和聚合数据。 然后,我应该提到它的应用场景。比如,数据科学中的数据分析,DuckDB可以处理CSV、Parquet等格式,方便数据科学家进行快速分析。还有嵌入式分析,适合在应用程序内部做实时分析,不需要依赖外部数据库。另外,教育和研究领域,因为安装简单,适合教学和小型项目。 用户可能还会关心DuckDB的优势。高性能是一个关键点,特别是向量化查询执行引擎,利用现代CPU的SIMD指令,提升处理速度。零管理,不需要复杂的配置,开箱即用。轻量级,适合资源有限的环境,比如边缘设备或者移动应用。 另外,使用方式部分需要详细说明。用户可以通过命令行交互,或者直接在Python、R等语言中使用,这对数据科学家来说非常方便。比如在Python中用pip安装,然后直接查询Parquet文件或者Pandas DataFrame,这样的例子能帮助用户快速上手。 可能用户还会想知道DuckDB和其他数据库的区别,比如和SQLite、PostgreSQL的区别。这时候需要强调DuckDB的OLAP优化,而SQLite是OLTP。和PostgreSQL相比,DuckDB更轻量,适合嵌入式场景,而PostgreSQL是功能更全面的服务器数据库。 最后,给出一个简单的代码示例,展示如何在Python中使用DuckDB,这样用户可以直接看到实际应用的例子,更容易理解。同时提醒用户访问官网和文档获取更多信息,这样他们可以自行深入学习。 需要注意的是,用户可能没有提到但潜在的问题是性能对比,或者适用场景的具体案例,所以在介绍时可以适当举例说明。另外,确保使用正确的中文术语,避免技术术语翻译错误,比如“列式存储”、“向量化执行引擎”等,保持专业性和易懂性之间的平衡。</think>DuckDB 是一款开源的**嵌入式关系型数据库管理系统**,专为**分析型查询(OLAP)**场景设计。其核心目标是提供高性能、轻量级的数据分析能力,尤其适合在本地环境或资源受限的场景中处理数据密集型任务。 --- ### 一、核心特性 1. **嵌入式设计** - 无需独立的服务器进程,直接嵌入到应用程序中,类似 SQLite 但针对分析优化。 - 支持通过 Python、R、Java 等语言直接调用,适合集成到数据分析流程中。 2. **高性能分析** - **列式存储引擎**:优化扫描与聚合操作,适合处理大规模数据分析。 - **向量化查询执行**:利用现代 CPU 的 SIMD 指令并行处理数据,提升计算效率。 - 支持并行查询,充分利用多核 CPU。 3. **标准 SQL 兼容** - 支持完整的 SQL 语法(包括窗口函数、复杂子查询等),降低学习成本。 - 提供扩展功能如 `JSON` 处理、空间数据类型等。 4. **零管理依赖** - 无需复杂配置,单文件存储数据(默认扩展名 `.ddb`),便于迁移和共享。 --- ### 二、典型应用场景 1. **数据科学分析** - 直接读取 CSV、Parquet 等格式数据,替代传统文件处理工具(如 pandas)。 - 示例:在 Python 中快速查询 10GB 的 Parquet 文件: ```python import duckdb result = duckdb.sql("SELECT COUNT(*) FROM 'data.parquet'").fetchall() ``` 2. **嵌入式分析** - 集成到应用程序中实现实时分析,如日志分析、用户行为统计等。 3. **教育与研究** - 轻量级部署,适合教学演示或小型研究项目。 --- ### 三、与其他数据库对比 | 特性 | DuckDB | SQLite | PostgreSQL | |---------------------|----------------|----------------|----------------| | **设计目标** | OLAP | OLTP | 通用型 | | **存储引擎** | 列式存储 | 行式存储 | 行/列扩展 | | **部署模式** | 嵌入式 | 嵌入式 | 客户端-服务器 | | **适用场景** | 数据分析 | 事务处理 | 复杂业务系统 | --- ### 四、快速上手示例(Python) ```python # 安装:pip install duckdb import duckdb # 连接数据库(内存模式) conn = duckdb.connect() # 直接查询 Parquet 文件 conn.sql("CREATE TABLE sales AS SELECT * FROM 'sales.parquet'") # 执行分析查询 query = """ SELECT region, SUM(revenue) AS total FROM sales GROUP BY region ORDER BY total DESC """ result = conn.sql(query).fetchdf() # 返回 pandas DataFrame ``` --- ### 五、优势与局限 - **优势**: - 分析性能卓越,尤其在聚合、过滤等操作上。 - 轻量级且易于集成,适合资源受限环境。 - **局限**: - 不适合高并发写入场景(OLTP)。 - 暂不提供分布式架构,需结合其他工具扩展集群能力。 --- 如需深入探索,可访问 [DuckDB 官网](https://duckdb.org/) 或查阅其详细文档。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值