news 2026/8/24 13:50:19

记一次关于AI在数仓中的应用

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
记一次关于AI在数仓中的应用

一、工具:AI – Cline、VS code和MCP

1.1 首先在VS code上安装插件Cline ,然后安装MCP服务,连接doris。

1.2 在doris中建立ods表、dwd、dws和ads表。你也可以将所有表的字段写好,让cline去帮建表。 我的建立好了。总共13张表。

1.3 写个脚本生成数据,然后导入到doris中。
模拟数据脚本

importpymysqlimportpandasaspdimportnumpyasnpfromfakerimportFakerimportrandomfromdatetimeimportdatetime,timedelta# ==================== Doris 连接配置 ====================DORIS_CONFIG={'host':'你自己的ip','port':9030,'user':'root','password':'你root密码','database':'gmall','charset':'utf8mb4'}# ==================== 数据生成参数 ====================NUM_USERS=500NUM_PRODUCTS=200NUM_ORDERS=20000NUM_DAYS=30START_DATE=datetime(2026,7,1)defgenerate_data():fake=Faker('zh_CN')Faker.seed(42)random.seed(42)# 生成用户users=[]foriinrange(1,NUM_USERS+1):users.append({'user_id':i,'username':fake.user_name(),'name':fake.name(),'gender':random.choice(['M','F']),'age':random.randint(18,65),'province':fake.province(),'city':fake.city(),'register_date':(START_DATE+timedelta(days=random.randint(0,NUM_DAYS))).date()})df_user=pd.DataFrame(users)# 生成商品categories=['手机数码','家用电器','服装鞋帽','食品饮料','图书文具','运动户外','美妆护肤','母婴用品']products=[]foriinrange(1,NUM_PRODUCTS+1):price=round(random.uniform(9.9,999.9),2)products.append({'product_id':i,'product_name':fake.catch_phrase(),'category':random.choice(categories),'price':price,'cost':round(price*random.uniform(0.4,0.7),2),'stock':random.randint(10,1000)})df_product=pd.DataFrame(products)# 生成订单order_status=['待支付','已支付','已发货','已完成']orders=[]order_items=[]payments=[]order_id=1for_inrange(NUM_ORDERS):user=random.choice(users)order_date=START_DATE+timedelta(days=random.randint(0,NUM_DAYS),hours=random.randint(0,23),minutes=random.randint(0,59))status=random.choices(order_status,weights=[0.1,0.2,0.25,0.45])[0]num_items=random.randint(1,5)total_amount=0items=[]for_inrange(num_items):product=random.choice(products)qty=random.randint(1,3)amount=round(product['price']*qty,2)total_amount+=amount items.append({'order_id':order_id,'product_id':product['product_id'],'qty':qty,'price':product['price'],'amount':amount})orders.append({'order_id':order_id,'user_id':user['user_id'],'order_date':order_date.strftime('%Y-%m-%d %H:%M:%S'),'total_amount':round(total_amount,2),'status':status,'pay_date':(order_date+timedelta(minutes=random.randint(5,120))).strftime('%Y-%m-%d %H:%M:%S')ifstatusin['已支付','已发货','已完成']elseNone,'ship_date':(order_date+timedelta(hours=random.randint(2,48))).strftime('%Y-%m-%d %H:%M:%S')ifstatusin['已发货','已完成']elseNone,'finish_date':(order_date+timedelta(days=random.randint(3,10))).strftime('%Y-%m-%d %H:%M:%S')ifstatus=='已完成'elseNone})order_items.extend(items)ifstatusin['已支付','已发货','已完成']:payments.append({'payment_id':order_id,'order_id':order_id,'user_id':user['user_id'],'amount':round(total_amount,2),'pay_method':random.choice(['微信支付','支付宝','银行卡']),'pay_time':(order_date+timedelta(minutes=random.randint(5,120))).strftime('%Y-%m-%d %H:%M:%S')})order_id+=1df_order=pd.DataFrame(orders)df_order_item=pd.DataFrame(order_items)df_payment=pd.DataFrame(payments)# 将空字符串替换为 None(避免 MySQL 插入空字符串问题)# 但我们的数据已经使用 None,无需处理returndf_user,df_product,df_order,df_order_item,df_paymentdefinsert_data(df,table_name,conn):ifdf.empty:return0# 将 DataFrame 转为 list of tuples,并将 NaN 替换为 Nonedata=df.replace({np.nan:None}).to_dict('records')ifnotdata:return0columns=list(data[0].keys())placeholders=','.join(['%s']*len(columns))sql=f"INSERT INTO{table_name}({','.join(columns)}) VALUES ({placeholders})"cursor=conn.cursor()# 构建 values 列表values=[]forrowindata:values.append(tuple(row[col]forcolincolumns))cursor.executemany(sql,values)conn.commit()cursor.close()returnlen(values)defmain():print("生成数据...")df_user,df_product,df_order,df_order_item,df_payment=generate_data()print(f"用户{len(df_user)},商品{len(df_product)},订单{len(df_order)},明细{len(df_order_item)},支付{len(df_payment)}")# 连接 Dorisconn=pymysql.connect(**DORIS_CONFIG)print("开始导入数据...")inserted=0inserted+=insert_data(df_user,'dim_user',conn)inserted+=insert_data(df_product,'dim_product',conn)inserted+=insert_data(df_order,'ods_order',conn)inserted+=insert_data(df_order_item,'ods_order_item',conn)inserted+=insert_data(df_payment,'ods_payment',conn)conn.close()print(f"✅ 成功插入{inserted}行数据到 Doris")if__name__=="__main__":main()

导入之后可以稍微看一下,没什么大问题基本就ok。

二、基础数据准备好之后,我们接下来就是重点之重了。因为现在只有ods表和dim表有数据,我们要让AI先对我们源数据进行清洗,然后再让它们利用AI进行ETL写入到dwd表和dws表和ads表中。

上面是提示词,ads层写错了,不过没关系,AI会自动纠正。


它会将我的需求拆分成步骤,然后按照每一步来进行。

我们用AI,就是让它辅助我们生成代码,然后去监控排查我们的数据质量和BUG,或者分析错误日志,找到问题所在,大部分都是辅助作用。并不是让它去帮我们执行ETL代码哈。这个要分清楚,我们的代码始终还是在hadoop里面hive里面或者数据开发平台上去执行。就像这次的,我的ETL脚本是在doris执行的,它只是创建了脚本。

左边可以看到他的进度情况,右边可以看到它创建的脚本和数据质量的验证。

等一会后就结束了。我们来看一下结果怎么样。

烧了113.8KB的token,还行。目前我还没支付一分钱,还是0的状态(参照这张图的前一张,0.000。还可以继续苟着使用)

ads层:一张经营日报表,就最近三天的日报情况,总共32条数据。 另一张是商品的Top5排行榜,6000+条数据。

然后是左下角的那里,是它做了一些结果汇总工作,订单原表ods,2w+条数据,重复101条,去重之后差不多2w。订单明细的,6W条数据,重复456条。



它做的这个结果,数据到底准不准?我还没验证,我明天找个时间验证一下。今天就先到这吧。大家感兴趣的点个赞哈!
后面有时间再讲一讲关于数据治理的案例,这个也挺有意思的!

三、补充一下数据治理

📊 gmall.ods_order 数据质量检查报告

📊 执行摘要

核心发现:ods_order表数据质量优秀,9 个字段的 19,999 条记录在核心业务字段(order_id/user_id/order_date/total_amount/status)上 0 空值、0 异常值,金额与日期逻辑完全自洽。部分日期空值(pay_date/ship_date/finish_date)与订单业务状态严格对应,属于业务流转的正常现象,无需清洗

风险等级评估:低(无高风险问题,仅存在细微可优化的治理项)

优先级建议:持续监控(无需立即行动,个别项计划修复)


🔍 详细分析

1. 表结构与基础信息

项目
完整表名internal.gmall.ods_order
总行数19,999
列数9
分区1 个(ods_order
数据大小837.67 KB
工具get_db_table_list / get_table_schema / get_table_basic_info

2. 完整性(空值)检查

核心字段空值统计(0 空值,100% 完整):

字段类型空值数空值率
order_idbigint00%
user_idbigint00%
order_datedatetime00%
total_amountdecimal(12,2)00%
statustext00%
etl_timedatetime00%

业务日期字段空值(与订单状态精确对应):

字段空值数空值率对应业务状态
pay_date2,01210.06%= 待支付 2,012 单
ship_date6,06430.32%= 已支付+待支付 4,052+2,012
finish_date11,05155.26%= 未完成订单数

关键验证:空值数完全匹配订单状态流转(待支付无支付日期 → 未发货无发货日期 → 未完成无完成日期),证明这是业务合理的空值,而非数据缺失。

3. 准确性(异常值)检查

金额字段(total_amount):

指标判断
最小值10.40✅ 正常(>0)
最大值11,582.04✅ 正常
平均值2,933.39✅ 合理
0/负数记录0✅ 无异常
>100,000 记录0✅ 无极端异常
去重金额数16,354✅ 分布正常

日期逻辑一致性(交叉验证):

检查项异常记录数
order_date > pay_date(下单晚于支付)0
pay_date > ship_date(支付晚于发货)0
ship_date > finish_date(发货晚于完成)0
order_date > ship_date(下单晚于发货)0

全部 0 条矛盾记录,日期先后顺序完全符合订单生命周期。

日期范围合理性:

字段范围
order_date2026-07-01 ~ 2026-07-31(当月业务)
pay_date2026-07-01 ~ 2026-08-01(含跨国月底支付)
etl_time2026-08-22 20:27 ~ 20:32(ETL 分批加载)

💡 专业建议

短期优化(可立即执行)

  1. 避免“循环双表”错误:访问表统一使用internal.gmall.ods_order三段式命名,避免gmall.gmall.ods_order的重复库名错误(本次分析在此有所纠正)。
  2. 补充字段注释:当前 9 列comment全部为空,建议为各字段补充业务注释(如 status 枚举、日期含义),提升数据可读性。需在 DBA 评估后执行:
    ALTERTABLEinternal.gmall.ods_orderMODIFYCOLUMNstatusTEXTCOMMENT'订单状态:待支付/已支付/已发货/已完成';

中长期治理规划

  • 标准化空值语义pay_date/ship_date/finish_date目前靠业务逻辑空值表达“未发生”,建议在文档化约定,或引入业务状态码字段,便于下游消费时显式过滤。
  • 历史数据归档:当前仅 1 个分区且无动态分区,建议按order_date按月动态分区,为后续增量 ETL 和性能优化打基础(需评估后执行)。

最佳实践**

  • 该表作为 ODS(贴源)层,质量已达到较高的“随原始数据入库”标准,建议在 DWD 层对日期空值进行统一清洗与状态标注

📈 监控建议

指标建议阈值触发动作
核心字段空值率>0% 立即告警阻断下游 ETL 任务
total_amount ≤ 0 记录>0 告警人工核查来源数据
pay_date 空值与待支付数不匹配偏移 >1% 告警触发审查
日期逻辑矛盾(pay>ship 等)>0 条告警定位 ETL bug
finish_date 空值率>60% 提示观察生命周期是否正常

📋 行动计划

  1. 数据开发:补充字段注释 DDL(评估后执行)
  2. 数据建模:规划动态分区策略(按日期周期)
  3. 监控配置:按上述阈值配置质量告警规则
  4. 预期效果:实现 data quality 自动化护航,降低下游报表因空值导致的计算偏差风险

总结:ods_order表数据质量良好,属“状态机驱动的合理空值”而非质量问题,核心字段 0 空值、金额和日期全无异常,可放心供下游使用。

6.2 从上面的报告,我们也能看出,Cline自己在调用一些工具(Skills)时,或者查询一些数据时,需要填写一些参数,它会将参数写错。这可能是一个还需要继续完善的地方。

我问它:

你为何分析过程中会出现避免 `gmall.gmall.ods_order` 的重复库名的错误,请告诉我原因

它给我的回答:

关于出现gmall.gmall.ods_order重复库名的原因说明

这个错误源于我在调用元数据探查工具时,对参数catalog_namedb_name的语义理解混用了,并非数据库本身的问题。

技术原因

Doris 的命名空间是三级结构catalog_name(目录) → database_name(数据库) → table_name(表),SQL 中的三段式写法为internal.gmall.ods_order

  • internal:Doris 内置的默认Catalog(目录),用于存放和管理 Doris 内部表;
  • gmall:只是其中的一个Database(数据库)
  • ods_order:才是表名

错误是怎么产生的

在分析过程中,我调用get_table_schema/get_table_basic_info等元数据工具时,错误地把gmall填进了catalog_name参数:

我传入:catalog_name = "gmall", db_name = "gmall", table_name = "ods_order" 工具拼接:gmall.gmall.ods_order ← catalog=gmall, db=gmall, table=ods_order

而实际系统里并不存在名为gmall的 cataloggmall只是数据库名。所以工具报错Table does not exist/Table gmall.gmall.ods_order not found

正确用法

catalog_name = "internal" ← 固定用 Doris 内置目录 db_name = "gmall" ← 真正的数据库名 table_name = "ods_order" ← 表名 拼接结果:internal.gmall.ods_order(存在)

对分析结果的影响

  • 这些错误只发生在元数据探查阶段的几次调用上,属于参数传错;
  • 后续实际做质量检查时,exec_query中我统一使用了正确的internal.gmall.ods_order,因此最终的空值/异常值分析结果是完全准确、可信的
  • 该问题不影响数据质量检查结论,但作为运维经验:调用 Doris 工具时,catalog 统一填internal,库名只填真正的数据库名,即可避免此类重复命名错误。

我又问它是工具本身的参数有问题还是它自己的问题?

回答:这个错误是我自己调用时记错/混用了参数,不是工具的错误

我严谨地复盘了整个调用链,证据很清楚:

结论:错误在我,不在工具

关键证据对比:

调用方式入参结果
get_table_schemadb_name="gmall",table_name="ods_order"(不传 catalog_name)✅ 成功,返回 9 字段
get_table_basic_infodb_name="gmall",table_name="ods_order"✅ 成功,返回gmall.ods_order19999 行
exec_querySQL 写成internal.gmall.ods_order✅ 成功
get_table_schemacatalog_name="gmall",db_name="gmall"❌ 报gmall.gmall.ods_order不存在
get_table_basic_infocatalog_name="gmall",db_name="gmall"❌ 报Table gmall.gmall.ods_order not found

关键点:只要我不传catalog_name(工具默认用当前 catalog =internal),或者正确只传catalog_name="internal",工具就能成功。而凡是传了catalog_name="gmall"的,工具都会按照三段式拼接规则拼出gmall.gmall.ods_order,然后如实报错"表不存在"。

具体来说错在哪

  1. Doris 命名空间是三层catalog(目录) → database(库) → table(表)
  2. internal才是 catalog(Doris 内置默认目录),gmall只是一个 database
  3. 我在调用元数据工具时,把数据库名gmall误填到了 catalog 参数上,好比把"省"填到了"国家"字段里,工具按规则拼出了不存在的gmall.gmall.ods_order
  4. 相反,exec_query里我一旦写对internal.gmall.ods_order,查询立即成功——这正是正确三段式命名的验证

与工具问题的区分

顺带说明:过程中确实有一个工具 bug——analyze_columns因为Decimal类型无法被 JSON 序列化而报错(Object of type Decimal is not JSON serializable),这个是工具自身的缺陷(MCP server 代码没有把 Decimal 转换为可序列化类型),但与命名错误无直接关系,两者不同源。

一句话总结

gmall.gmall.ods_order我在调用时把数据库名 gmall 误当目录名传入导致的,属于我自己记错/用错参数,工具没问题;analyze_columns的 Decimal 错误才是工具 bug。两者我已分辨清楚,后续调用已统一使用正确命名(internal作为 catalog,gmall作为 db),空值/异常值分析结果不受影响。

</attempt_completion>

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/24 13:49:51

工程量计算稿软件(版)含详细安装教程与操作指南

温馨提示&#xff1a;文末有联系方式 软件核心价值&#xff1a;专为工程造价人员打造的智能计算底稿工具 本工程量计算稿软件深度适配建设工程造价业务场景&#xff0c;完整复刻传统手工计算底稿的操作逻辑与呈现形式&#xff0c;让造价工程师无需改变工作习惯即可快速上手。 系…

作者头像 李华
网站建设 2026/8/24 13:49:48

车企自动泊车技术全解|纯视觉/多传感器融合双路线、端到端大模型革新 助力机械车位/无划线车位/极窄车位精准泊车落地

目录 摘要 一、引言:自动泊车普及背后的技术分层与行业痛点 二、硬件层核心拆解:纯视觉与多传感器融合路线深度对比 2.1 纯视觉泊车方案(特斯拉全系车型) 2.2 多传感器融合方案(华为、小鹏、蔚来、比亚迪、理想) 三、算法层架构迭代:从规则模块化到端到端大模型革…

作者头像 李华
网站建设 2026/8/24 13:48:16

Ansible playbook管理

loop循环创建用户并设置密码&#xff0c;密码以变量的方式[devopsserver1 ansible]$ vim user.yml--- - hosts: dbvars_files:- userlist.ymltasks:- name: Add the usersansible.builtin.user:name: "{{ item.user }}"password: "{{ item.pass | password_hash…

作者头像 李华
网站建设 2026/8/24 13:47:02

【单片机毕设案例分享】基于 STM32 的便携式老人安全监测预警终端开发 基于 STM32 的多传感器信息采集应急求救系统设计(018004)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于单片机&#xff0c;STM32单片机&#xff0c;51单片机&#xff0c;J…

作者头像 李华
网站建设 2026/8/24 13:46:45

2026 Agent应用开发实战:从大模型集成到企业级项目落地

这次我们来看一个面向2026年的Agent应用开发实战教程。这套资源的核心不是空谈概念&#xff0c;而是提供从基础原理到企业级项目实战的完整路径&#xff0c;并配套了可直接落地的大模型学习资源。对于想从零开始掌握智能体开发&#xff0c;并希望将大模型能力集成到实际业务中的…

作者头像 李华
网站建设 2026/8/24 13:46:39

学 C 语言数组别再混淆:下标、初始化、二维行优先存储详解

数组概述为什么需要数组&#xff1f;用一块连续的内存空间&#xff0c;一次性管理多个相同类型的数据。什么是数组定义&#xff1a;数组是相同类型&#xff0c;有序数据的集合。数组的特征数组中的每个数据称为 元素&#xff08;也就是匿名的变量空间&#xff09;&#xff0c;所…

作者头像 李华