@dazitech/cli 3.0.8 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/clis/dazi-app.js +1 -1
- package/dist/clis/dazi-flow.js +1 -1
- package/dist/clis/dazi-onto.js +7 -2
- package/dist/clis/dazi.js +1 -1
- package/dist/docs/flow/flow-project-guide.md +1 -1
- package/dist/docs/guides/troubleshooting.md +12 -1
- package/dist/docs/index.json +21 -2
- package/dist/docs/onto/dazi_script_sdk_reference.md +246 -178
- package/dist/docs/onto/function-guide.md +123 -95
- package/dist/docs/onto//346/234/254/344/275/223/345/210/206/347/261/273/350/247/204/345/210/222/344/270/216SDK/346/211/251/345/261/225/346/226/271/346/241/210.md +169 -0
- package/dist/docs/onto//346/234/254/344/275/223/345/221/275/345/220/215/350/247/204/350/214/203_/347/211/251/347/220/206/350/241/250Cube/344/270/216/345/257/271/350/261/241.md +402 -0
- package/dist/docs/onto//346/234/254/344/275/223/345/274/200/345/217/221/344/274/230/345/214/226/346/200/273/347/273/223.md +242 -0
- package/dist/docs/onto//346/234/254/344/275/223/350/204/232/346/234/254/347/274/226/345/206/231/346/214/207/345/215/227.md +339 -249
- package/dist/docs/onto//346/234/254/344/275/223/350/247/204/345/210/222/346/214/207/345/215/227.md +304 -173
- package/dist/docs/onto//350/204/232/346/234/254/350/277/220/350/241/214/345/270/270/350/247/201/351/224/231/350/257/257/345/244/204/347/220/206.md +242 -0
- package/dist/docs/onto//350/247/204/345/210/222/347/244/272/344/276/213_/344/272/247/345/223/201/351/224/200/345/224/256/346/234/254/344/275/223/350/247/204/345/210/222/346/226/271/346/241/210.md +361 -238
- package/dist/docs/onto//350/247/204/345/210/222/347/244/272/344/276/213_/345/210/251/346/266/246/345/210/206/346/236/220/346/234/254/344/275/223/346/226/271/346/241/210.md +385 -300
- package/dist/examples/index.json +22 -16
- package/dist/examples/onto/README.md +13 -5
- package/dist/examples/onto/_templates/ontology_function_template.py +50 -0
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/functions/profit_fn_account_breakdown.py +62 -0
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/functions/profit_fn_budget_vs_actual.py +69 -0
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/functions/profit_fn_cost_center_profit.py +64 -0
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/functions/profit_fn_get_summary.py +61 -0
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/functions/profit_fn_mom_analysis.py +82 -0
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/functions/profit_fn_top_accounts.py +61 -0
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/functions/profit_fn_yoy_analysis.py +79 -0
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/functions/save_test_arguments.ps1 +38 -0
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/functions/test_arguments/profit.fn.account_breakdown.json +1 -0
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/functions/test_arguments/profit.fn.budget_vs_actual.json +1 -0
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/functions/test_arguments/profit.fn.cost_center_profit.json +1 -0
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/functions/test_arguments/profit.fn.get_summary.json +1 -0
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/functions/test_arguments/profit.fn.mom_analysis.json +1 -0
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/functions/test_arguments/profit.fn.top_accounts.json +1 -0
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/functions/test_arguments/profit.fn.yoy_analysis.json +1 -0
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/setup/profit_category_mount.py +85 -0
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/setup/profit_ontology_init.py +169 -74
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/setup/profit_seed_data.py +16 -13
- package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/sales_fn_channel_mix.py +19 -16
- package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/sales_fn_customer_segmentation.py +48 -50
- package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/sales_fn_get_summary.py +3 -6
- package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/sales_fn_mom_analysis.py +11 -12
- package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/sales_fn_region_breakdown.py +6 -7
- package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/sales_fn_top_products.py +5 -8
- package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/sales_fn_yoy_analysis.py +3 -6
- package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/save_test_arguments.ps1 +32 -19
- package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/test_arguments/sales.fn.channel_mix.json +3 -6
- package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/test_arguments/sales.fn.customer_segmentation.json +2 -7
- package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/test_arguments/sales.fn.get_summary.json +2 -5
- package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/test_arguments/sales.fn.mom_analysis.json +2 -5
- package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/test_arguments/sales.fn.region_breakdown.json +2 -5
- package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/test_arguments/sales.fn.top_products.json +2 -7
- package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/test_arguments/sales.fn.yoy_analysis.json +2 -5
- package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/setup/sales_category_mount.py +82 -0
- package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/setup/sales_ontology_init.py +240 -155
- package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/setup/sales_seed_data.py +59 -20
- package/dist/prompts/index.json +8 -1
- package/dist/prompts/onto/function-design.md +73 -53
- package/dist/prompts/onto/planning-design.md +104 -0
- package/dist/prompts/onto/script-publish-run.md +229 -194
- package/package.json +1 -1
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/profit_fn_account_breakdown.py +0 -99
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/profit_fn_budget_vs_actual.py +0 -116
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/profit_fn_cost_center_profit.py +0 -85
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/profit_fn_get_summary.py +0 -76
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/profit_fn_mom_analysis.py +0 -86
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/profit_fn_top_accounts.py +0 -103
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/profit_fn_yoy_analysis.py +0 -86
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/save_test_arguments.ps1 +0 -27
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/test_arguments/profit.fn.account_breakdown.json +0 -10
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/test_arguments/profit.fn.budget_vs_actual.json +0 -10
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/test_arguments/profit.fn.cost_center_profit.json +0 -9
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/test_arguments/profit.fn.get_summary.json +0 -9
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/test_arguments/profit.fn.mom_analysis.json +0 -9
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/test_arguments/profit.fn.top_accounts.json +0 -11
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/test_arguments/profit.fn.yoy_analysis.json +0 -9
- package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/README.md +0 -25
- package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/setup/README.md +0 -5
|
@@ -1,32 +1,133 @@
|
|
|
1
|
-
"""产品销售本体初始化脚本 —
|
|
1
|
+
"""产品销售本体初始化脚本 — space__misc_01
|
|
2
2
|
|
|
3
3
|
初始化内容:
|
|
4
|
-
1. 创建物理表(
|
|
4
|
+
1. 创建物理表(dim_date + 3 维表 + 1 事实表)
|
|
5
5
|
2. 注册表到空间
|
|
6
|
-
3. 注册表间关系(
|
|
7
|
-
4. 注册 Cube(
|
|
6
|
+
3. 注册表间关系(4 条,含 fact → dim_date)
|
|
7
|
+
4. 注册 Cube(4 个)及派生度量
|
|
8
8
|
5. 定义对象类型(5 种)、绑定数据源、属性、链接
|
|
9
9
|
6. 同步指标引用
|
|
10
|
+
7. 配置 平台分类对齐分类(ads_categories + 桥表)
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
发布:dazi onto script publish
|
|
12
|
+
放置:资源/examples/onto/销售示例/setup/sales_ontology_init.py(复制到项目 ontos/<实现名>/setup/)
|
|
13
|
+
发布:dazi onto script publish <item-path>/setup/sales_ontology_init.py --space <space-id> --type setup
|
|
14
|
+
规划对照:资源/docs/onto/规划示例_产品销售本体规划方案.md
|
|
13
15
|
"""
|
|
14
16
|
|
|
15
17
|
import json
|
|
16
18
|
|
|
19
|
+
# 与 规划示例_产品销售本体规划方案.md §2.3、§3.x 对齐:display_name=侧栏显示名,description=业务说明
|
|
20
|
+
TABLE_REGISTRY = {
|
|
21
|
+
"dim_date": {
|
|
22
|
+
"display_name": "日期维表",
|
|
23
|
+
"description": "全空间共享日历,事实表通过 date_key 关联",
|
|
24
|
+
"columns": [
|
|
25
|
+
{"name": "date_key", "display_name": "日期键", "description": "YYYYMMDD,主键"},
|
|
26
|
+
{"name": "calendar_date", "display_name": "自然日"},
|
|
27
|
+
{"name": "year", "display_name": "公历年"},
|
|
28
|
+
{"name": "quarter", "display_name": "季度", "description": "1-4"},
|
|
29
|
+
{"name": "month", "display_name": "月", "description": "1-12"},
|
|
30
|
+
{"name": "week_of_year", "display_name": "周"},
|
|
31
|
+
{"name": "day_of_week", "display_name": "星期"},
|
|
32
|
+
{"name": "is_weekend", "display_name": "是否周末", "description": "0/1"},
|
|
33
|
+
{"name": "year_month", "display_name": "年月", "description": "如 2025-06"},
|
|
34
|
+
],
|
|
35
|
+
},
|
|
36
|
+
"dim_product": {
|
|
37
|
+
"display_name": "产品维表",
|
|
38
|
+
"description": "可售产品主数据",
|
|
39
|
+
"columns": [
|
|
40
|
+
{"name": "product_id", "display_name": "产品 ID", "description": "主键"},
|
|
41
|
+
{"name": "product_code", "display_name": "产品编码"},
|
|
42
|
+
{"name": "product_name", "display_name": "产品名称"},
|
|
43
|
+
{"name": "product_category", "display_name": "产品大类"},
|
|
44
|
+
{"name": "product_subcategory", "display_name": "产品小类"},
|
|
45
|
+
{"name": "brand", "display_name": "品牌"},
|
|
46
|
+
{"name": "unit", "display_name": "计量单位"},
|
|
47
|
+
{"name": "list_price", "display_name": "挂牌价"},
|
|
48
|
+
{"name": "cost_price", "display_name": "成本单价"},
|
|
49
|
+
{"name": "status", "display_name": "状态", "description": "在售/停售"},
|
|
50
|
+
{"name": "created_at", "display_name": "创建时间"},
|
|
51
|
+
{"name": "updated_at", "display_name": "更新时间"},
|
|
52
|
+
],
|
|
53
|
+
},
|
|
54
|
+
"dim_customer": {
|
|
55
|
+
"display_name": "客户维表",
|
|
56
|
+
"description": "购买方主数据",
|
|
57
|
+
"columns": [
|
|
58
|
+
{"name": "customer_id", "display_name": "客户 ID", "description": "主键"},
|
|
59
|
+
{"name": "customer_code", "display_name": "客户编码"},
|
|
60
|
+
{"name": "customer_name", "display_name": "客户名称"},
|
|
61
|
+
{"name": "customer_region", "display_name": "销售区域"},
|
|
62
|
+
{"name": "customer_type", "display_name": "客户类型"},
|
|
63
|
+
{"name": "industry", "display_name": "所属行业"},
|
|
64
|
+
{"name": "created_at", "display_name": "创建时间"},
|
|
65
|
+
],
|
|
66
|
+
},
|
|
67
|
+
"dim_channel": {
|
|
68
|
+
"display_name": "渠道维表",
|
|
69
|
+
"description": "销售渠道主数据",
|
|
70
|
+
"columns": [
|
|
71
|
+
{"name": "channel_id", "display_name": "渠道 ID", "description": "主键"},
|
|
72
|
+
{"name": "channel_code", "display_name": "渠道编码"},
|
|
73
|
+
{"name": "channel_name", "display_name": "渠道名称"},
|
|
74
|
+
{"name": "channel_type", "display_name": "渠道类型"},
|
|
75
|
+
],
|
|
76
|
+
},
|
|
77
|
+
"fact_sales_order_line": {
|
|
78
|
+
"display_name": "销售订单行事实表",
|
|
79
|
+
"description": "订单行粒度销售流水",
|
|
80
|
+
"columns": [
|
|
81
|
+
{"name": "order_id", "display_name": "订单 ID"},
|
|
82
|
+
{"name": "order_line_id", "display_name": "订单行 ID", "description": "主键组合"},
|
|
83
|
+
{"name": "date_key", "display_name": "日期键", "description": "关联 dim_date"},
|
|
84
|
+
{"name": "order_date", "display_name": "订单日期"},
|
|
85
|
+
{"name": "product_id", "display_name": "产品 ID", "description": "关联 dim_product"},
|
|
86
|
+
{"name": "product_category", "display_name": "产品大类", "description": "冗余"},
|
|
87
|
+
{"name": "customer_id", "display_name": "客户 ID", "description": "关联 dim_customer"},
|
|
88
|
+
{"name": "customer_region", "display_name": "销售区域", "description": "冗余"},
|
|
89
|
+
{"name": "customer_type", "display_name": "客户类型", "description": "冗余"},
|
|
90
|
+
{"name": "channel_id", "display_name": "渠道 ID", "description": "关联 dim_channel"},
|
|
91
|
+
{"name": "quantity", "display_name": "销售数量"},
|
|
92
|
+
{"name": "unit_price", "display_name": "成交单价"},
|
|
93
|
+
{"name": "discount_amount", "display_name": "折扣金额"},
|
|
94
|
+
{"name": "sales_amount", "display_name": "销售金额"},
|
|
95
|
+
{"name": "currency", "display_name": "币种"},
|
|
96
|
+
{"name": "order_status", "display_name": "订单状态"},
|
|
97
|
+
],
|
|
98
|
+
},
|
|
99
|
+
}
|
|
17
100
|
|
|
18
101
|
def main():
|
|
19
|
-
space_id = "
|
|
102
|
+
space_id = "space__misc_01"
|
|
20
103
|
s = space.get(space_id)
|
|
21
104
|
|
|
22
105
|
output.print("=== 产品销售本体初始化 ===")
|
|
23
106
|
output.print(f"空间: {space_id}")
|
|
24
107
|
|
|
25
108
|
# 1. 创建物理表
|
|
26
|
-
output.print("\n[1/
|
|
109
|
+
output.print("\n[1/10] 创建物理表...")
|
|
110
|
+
|
|
111
|
+
# dim_date(强制时间维)
|
|
112
|
+
s.sql.execute("""
|
|
113
|
+
CREATE TABLE IF NOT EXISTS dim_date (
|
|
114
|
+
date_key Int32,
|
|
115
|
+
calendar_date Date,
|
|
116
|
+
year Int16,
|
|
117
|
+
quarter Int8,
|
|
118
|
+
month Int8,
|
|
119
|
+
week_of_year Int8,
|
|
120
|
+
day_of_week Int8,
|
|
121
|
+
is_weekend UInt8,
|
|
122
|
+
year_month String
|
|
123
|
+
) ENGINE = MergeTree()
|
|
124
|
+
ORDER BY (date_key)
|
|
125
|
+
""")
|
|
126
|
+
output.print("OK dim_date")
|
|
27
127
|
|
|
128
|
+
# dim_product
|
|
28
129
|
s.sql.execute("""
|
|
29
|
-
CREATE TABLE IF NOT EXISTS
|
|
130
|
+
CREATE TABLE IF NOT EXISTS dim_product (
|
|
30
131
|
product_id String,
|
|
31
132
|
product_code String,
|
|
32
133
|
product_name String,
|
|
@@ -42,10 +143,11 @@ def main():
|
|
|
42
143
|
) ENGINE = MergeTree()
|
|
43
144
|
ORDER BY (product_id)
|
|
44
145
|
""")
|
|
45
|
-
output.print("OK
|
|
146
|
+
output.print("OK dim_product")
|
|
46
147
|
|
|
148
|
+
# dim_customer
|
|
47
149
|
s.sql.execute("""
|
|
48
|
-
CREATE TABLE IF NOT EXISTS
|
|
150
|
+
CREATE TABLE IF NOT EXISTS dim_customer (
|
|
49
151
|
customer_id String,
|
|
50
152
|
customer_code String,
|
|
51
153
|
customer_name String,
|
|
@@ -56,10 +158,11 @@ def main():
|
|
|
56
158
|
) ENGINE = MergeTree()
|
|
57
159
|
ORDER BY (customer_id)
|
|
58
160
|
""")
|
|
59
|
-
output.print("OK
|
|
161
|
+
output.print("OK dim_customer")
|
|
60
162
|
|
|
163
|
+
# dim_channel
|
|
61
164
|
s.sql.execute("""
|
|
62
|
-
CREATE TABLE IF NOT EXISTS
|
|
165
|
+
CREATE TABLE IF NOT EXISTS dim_channel (
|
|
63
166
|
channel_id String,
|
|
64
167
|
channel_code String,
|
|
65
168
|
channel_name String,
|
|
@@ -67,12 +170,14 @@ def main():
|
|
|
67
170
|
) ENGINE = MergeTree()
|
|
68
171
|
ORDER BY (channel_id)
|
|
69
172
|
""")
|
|
70
|
-
output.print("OK
|
|
173
|
+
output.print("OK dim_channel")
|
|
71
174
|
|
|
175
|
+
# fact_sales_order_line(含 date_key)
|
|
72
176
|
s.sql.execute("""
|
|
73
|
-
CREATE TABLE IF NOT EXISTS
|
|
177
|
+
CREATE TABLE IF NOT EXISTS fact_sales_order_line (
|
|
74
178
|
order_id String,
|
|
75
179
|
order_line_id String,
|
|
180
|
+
date_key Int32,
|
|
76
181
|
order_date Date,
|
|
77
182
|
product_id String,
|
|
78
183
|
product_category String,
|
|
@@ -87,60 +192,68 @@ def main():
|
|
|
87
192
|
currency String,
|
|
88
193
|
order_status String
|
|
89
194
|
) ENGINE = MergeTree()
|
|
90
|
-
ORDER BY (
|
|
195
|
+
ORDER BY (date_key, order_id, order_line_id)
|
|
91
196
|
""")
|
|
92
|
-
output.print("OK
|
|
93
|
-
|
|
94
|
-
# 2.
|
|
95
|
-
output.print("\n[2/
|
|
96
|
-
|
|
97
|
-
for
|
|
98
|
-
(
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
output.print(f"OK {
|
|
197
|
+
output.print("OK fact_sales_order_line")
|
|
198
|
+
|
|
199
|
+
# 2. 注册表(含 display_name / description)
|
|
200
|
+
output.print("\n[2/10] 注册表到空间...")
|
|
201
|
+
|
|
202
|
+
for tbl_name, meta in TABLE_REGISTRY.items():
|
|
203
|
+
s.tables.register_with_meta(
|
|
204
|
+
table_name=tbl_name,
|
|
205
|
+
display_name=meta["display_name"],
|
|
206
|
+
description=meta.get("description"),
|
|
207
|
+
columns=meta["columns"],
|
|
208
|
+
force_column_meta=True,
|
|
209
|
+
)
|
|
210
|
+
output.print(f"OK {tbl_name} ({meta['display_name']})")
|
|
106
211
|
|
|
107
|
-
# 3.
|
|
108
|
-
output.print("\n[3/
|
|
212
|
+
# 3. 注册表间关系(4 条,含 fact → dim_date)
|
|
213
|
+
output.print("\n[3/10] 注册表间关系...")
|
|
109
214
|
|
|
110
215
|
table_relationships = [
|
|
111
216
|
{
|
|
112
|
-
"from_table": "
|
|
113
|
-
"to_table": "
|
|
114
|
-
"join_sql": "
|
|
217
|
+
"from_table": "fact_sales_order_line",
|
|
218
|
+
"to_table": "dim_date",
|
|
219
|
+
"join_sql": "fact_sales_order_line.date_key = dim_date.date_key",
|
|
220
|
+
"join_keys": [{"from": "date_key", "to": "date_key"}],
|
|
221
|
+
"relationship_type": "many_to_one",
|
|
222
|
+
"description": "销售订单行关联日期",
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
"from_table": "fact_sales_order_line",
|
|
226
|
+
"to_table": "dim_product",
|
|
227
|
+
"join_sql": "fact_sales_order_line.product_id = dim_product.product_id",
|
|
115
228
|
"join_keys": [{"from": "product_id", "to": "product_id"}],
|
|
116
229
|
"relationship_type": "many_to_one",
|
|
117
|
-
"description": "
|
|
230
|
+
"description": "销售订单行关联产品",
|
|
118
231
|
},
|
|
119
232
|
{
|
|
120
|
-
"from_table": "
|
|
121
|
-
"to_table": "
|
|
122
|
-
"join_sql": "
|
|
233
|
+
"from_table": "fact_sales_order_line",
|
|
234
|
+
"to_table": "dim_customer",
|
|
235
|
+
"join_sql": "fact_sales_order_line.customer_id = dim_customer.customer_id",
|
|
123
236
|
"join_keys": [{"from": "customer_id", "to": "customer_id"}],
|
|
124
237
|
"relationship_type": "many_to_one",
|
|
125
238
|
"description": "销售订单行关联客户",
|
|
126
239
|
},
|
|
127
240
|
{
|
|
128
|
-
"from_table": "
|
|
129
|
-
"to_table": "
|
|
130
|
-
"join_sql": "
|
|
241
|
+
"from_table": "fact_sales_order_line",
|
|
242
|
+
"to_table": "dim_channel",
|
|
243
|
+
"join_sql": "fact_sales_order_line.channel_id = dim_channel.channel_id",
|
|
131
244
|
"join_keys": [{"from": "channel_id", "to": "channel_id"}],
|
|
132
245
|
"relationship_type": "many_to_one",
|
|
133
|
-
"description": "
|
|
246
|
+
"description": "销售订单行关联渠道",
|
|
134
247
|
},
|
|
135
248
|
]
|
|
136
249
|
for rel in table_relationships:
|
|
137
250
|
rid = s.tables.add_relationship(**rel)
|
|
138
251
|
output.print(f"OK {rel['from_table']} -> {rel['to_table']} ({rid})")
|
|
139
252
|
|
|
140
|
-
# 4. 注册 Cube
|
|
141
|
-
output.print("\n[4/
|
|
253
|
+
# 4. 注册 Cube(4 个)
|
|
254
|
+
output.print("\n[4/10] 注册 Cube...")
|
|
142
255
|
|
|
143
|
-
fact = "
|
|
256
|
+
fact = "fact_sales_order_line"
|
|
144
257
|
common_measures = [
|
|
145
258
|
{"name": "quantity", "col": "quantity", "agg": "sum", "title": "销售数量"},
|
|
146
259
|
{"name": "sales_amount", "col": "sales_amount", "agg": "sum", "title": "销售金额"},
|
|
@@ -149,6 +262,7 @@ def main():
|
|
|
149
262
|
{"name": "line_count", "col": "order_line_id", "agg": "uniq", "title": "订单行数"},
|
|
150
263
|
]
|
|
151
264
|
|
|
265
|
+
# SalesCube(Process · 销售分析主 Cube)
|
|
152
266
|
s.register_cube(
|
|
153
267
|
name="SalesCube",
|
|
154
268
|
table=fact,
|
|
@@ -157,16 +271,19 @@ def main():
|
|
|
157
271
|
dimensions=[
|
|
158
272
|
{"name": "order_id", "col": "order_id", "type": "string", "title": "订单ID"},
|
|
159
273
|
{"name": "order_line_id", "col": "order_line_id", "type": "string", "title": "订单行ID"},
|
|
274
|
+
{"name": "date_key", "col": "date_key", "type": "int32", "title": "日期键"},
|
|
160
275
|
{"name": "order_date", "col": "order_date", "type": "date", "title": "订单日期"},
|
|
161
276
|
{"name": "product_id", "col": "product_id", "type": "string", "title": "产品ID"},
|
|
162
277
|
{"name": "product_category", "col": "product_category", "type": "string", "title": "产品大类"},
|
|
163
278
|
{"name": "customer_id", "col": "customer_id", "type": "string", "title": "客户ID"},
|
|
164
279
|
{"name": "customer_region", "col": "customer_region", "type": "string", "title": "销售区域"},
|
|
280
|
+
{"name": "customer_type", "col": "customer_type", "type": "string", "title": "客户类型"},
|
|
165
281
|
{"name": "channel_id", "col": "channel_id", "type": "string", "title": "渠道ID"},
|
|
166
282
|
],
|
|
167
283
|
)
|
|
168
284
|
output.print("OK SalesCube")
|
|
169
285
|
|
|
286
|
+
# ProductSalesCube(Subject · 产品销售)
|
|
170
287
|
s.register_cube(
|
|
171
288
|
name="ProductSalesCube",
|
|
172
289
|
table=fact,
|
|
@@ -183,6 +300,7 @@ def main():
|
|
|
183
300
|
)
|
|
184
301
|
output.print("OK ProductSalesCube")
|
|
185
302
|
|
|
303
|
+
# CustomerSalesCube(Subject · 客户销售)
|
|
186
304
|
s.register_cube(
|
|
187
305
|
name="CustomerSalesCube",
|
|
188
306
|
table=fact,
|
|
@@ -200,6 +318,7 @@ def main():
|
|
|
200
318
|
)
|
|
201
319
|
output.print("OK CustomerSalesCube")
|
|
202
320
|
|
|
321
|
+
# ChannelSalesCube(Subject · 渠道销售)
|
|
203
322
|
s.register_cube(
|
|
204
323
|
name="ChannelSalesCube",
|
|
205
324
|
table=fact,
|
|
@@ -215,26 +334,8 @@ def main():
|
|
|
215
334
|
)
|
|
216
335
|
output.print("OK ChannelSalesCube")
|
|
217
336
|
|
|
218
|
-
s.register_cube(
|
|
219
|
-
name="TimeSalesCube",
|
|
220
|
-
table=fact,
|
|
221
|
-
title="时间维度销售Cube",
|
|
222
|
-
measures=[
|
|
223
|
-
{"name": "sales_amount", "col": "sales_amount", "agg": "sum", "title": "销售金额"},
|
|
224
|
-
{"name": "quantity", "col": "quantity", "agg": "sum", "title": "销售数量"},
|
|
225
|
-
{"name": "order_count", "col": "order_id", "agg": "uniq", "title": "订单数"},
|
|
226
|
-
],
|
|
227
|
-
dimensions=[
|
|
228
|
-
{"name": "order_date", "col": "order_date", "type": "date", "title": "订单日期"},
|
|
229
|
-
{"name": "year_month", "col": "order_date", "type": "string", "title": "年月"},
|
|
230
|
-
{"name": "quarter", "col": "order_date", "type": "string", "title": "季度"},
|
|
231
|
-
{"name": "year", "col": "order_date", "type": "date", "title": "年份"},
|
|
232
|
-
],
|
|
233
|
-
)
|
|
234
|
-
output.print("OK TimeSalesCube")
|
|
235
|
-
|
|
236
337
|
# 5. 派生度量
|
|
237
|
-
output.print("\n[5/
|
|
338
|
+
output.print("\n[5/10] 配置派生度量...")
|
|
238
339
|
|
|
239
340
|
s.upsert_derived_measures(
|
|
240
341
|
"SalesCube",
|
|
@@ -253,6 +354,8 @@ def main():
|
|
|
253
354
|
},
|
|
254
355
|
],
|
|
255
356
|
)
|
|
357
|
+
output.print("OK SalesCube 派生度量")
|
|
358
|
+
|
|
256
359
|
s.upsert_derived_measures(
|
|
257
360
|
"ProductSalesCube",
|
|
258
361
|
[
|
|
@@ -264,6 +367,8 @@ def main():
|
|
|
264
367
|
},
|
|
265
368
|
],
|
|
266
369
|
)
|
|
370
|
+
output.print("OK ProductSalesCube 派生度量")
|
|
371
|
+
|
|
267
372
|
s.upsert_derived_measures(
|
|
268
373
|
"CustomerSalesCube",
|
|
269
374
|
[
|
|
@@ -275,10 +380,10 @@ def main():
|
|
|
275
380
|
},
|
|
276
381
|
],
|
|
277
382
|
)
|
|
278
|
-
output.print("OK 派生度量")
|
|
383
|
+
output.print("OK CustomerSalesCube 派生度量")
|
|
279
384
|
|
|
280
385
|
# 6. 对象类型
|
|
281
|
-
output.print("\n[6/
|
|
386
|
+
output.print("\n[6/10] 定义对象类型...")
|
|
282
387
|
|
|
283
388
|
object_types = [
|
|
284
389
|
("Product", "产品", "可售产品业务对象"),
|
|
@@ -292,7 +397,7 @@ def main():
|
|
|
292
397
|
output.print(f"OK {code}")
|
|
293
398
|
|
|
294
399
|
# 7. 绑定数据源
|
|
295
|
-
output.print("\n[7/
|
|
400
|
+
output.print("\n[7/10] 绑定数据源...")
|
|
296
401
|
|
|
297
402
|
bindings = [
|
|
298
403
|
("Product", "ProductSalesCube"),
|
|
@@ -301,103 +406,83 @@ def main():
|
|
|
301
406
|
("SalesOrder", "SalesCube"),
|
|
302
407
|
("SalesAnalysis", "SalesCube"),
|
|
303
408
|
]
|
|
304
|
-
for
|
|
305
|
-
s.onto.bind_source(
|
|
306
|
-
output.print(f"OK {
|
|
307
|
-
|
|
308
|
-
# 8.
|
|
309
|
-
output.print("\n[8/
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
("
|
|
317
|
-
("
|
|
318
|
-
("
|
|
319
|
-
|
|
320
|
-
("
|
|
321
|
-
("
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
("
|
|
327
|
-
|
|
328
|
-
("
|
|
329
|
-
("
|
|
330
|
-
("
|
|
331
|
-
("
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
("
|
|
337
|
-
("sales_amount", "
|
|
338
|
-
("
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
("
|
|
344
|
-
("
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
(
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
define_props("SalesAnalysis", [
|
|
353
|
-
("date", "日期", "dimension", "SalesCube.order_date"),
|
|
354
|
-
("product_category", "产品大类", "dimension", "SalesCube.product_category"),
|
|
355
|
-
("customer_region", "销售区域", "dimension", "SalesCube.customer_region"),
|
|
356
|
-
("channel_id", "渠道", "dimension", "SalesCube.channel_id"),
|
|
357
|
-
("quantity", "销量", "measure", "SalesCube.quantity"),
|
|
358
|
-
("sales_amount", "销售额", "measure", "SalesCube.sales_amount"),
|
|
359
|
-
("order_count", "订单数", "measure", "SalesCube.order_count"),
|
|
360
|
-
("avg_order_value", "客单价", "measure", "SalesCube.avg_order_value"),
|
|
361
|
-
])
|
|
362
|
-
output.print("OK SalesAnalysis 属性 (8)")
|
|
363
|
-
|
|
364
|
-
# 9. 链接类型
|
|
365
|
-
output.print("\n[9/9] 定义链接与同步指标...")
|
|
409
|
+
for code, cube in bindings:
|
|
410
|
+
s.onto.bind_source(code, "dazi_cube", config={"cube": cube})
|
|
411
|
+
output.print(f"OK {code} -> {cube}")
|
|
412
|
+
|
|
413
|
+
# 8. 定义属性
|
|
414
|
+
output.print("\n[8/10] 定义属性...")
|
|
415
|
+
|
|
416
|
+
properties = [
|
|
417
|
+
# Product 属性
|
|
418
|
+
("Product", "id", "产品ID", "dimension", "ProductSalesCube.product_id"),
|
|
419
|
+
("Product", "category", "产品大类", "dimension", "ProductSalesCube.product_category"),
|
|
420
|
+
("Product", "quantity", "累计销量", "measure", "ProductSalesCube.quantity"),
|
|
421
|
+
("Product", "sales_amount", "累计销售额", "measure", "ProductSalesCube.sales_amount"),
|
|
422
|
+
("Product", "order_count", "订单数", "measure", "ProductSalesCube.order_count"),
|
|
423
|
+
("Product", "avg_unit_price", "平均单价", "measure", "ProductSalesCube.avg_unit_price"),
|
|
424
|
+
# Customer 属性
|
|
425
|
+
("Customer", "id", "客户ID", "dimension", "CustomerSalesCube.customer_id"),
|
|
426
|
+
("Customer", "region", "销售区域", "dimension", "CustomerSalesCube.customer_region"),
|
|
427
|
+
("Customer", "type", "客户类型", "dimension", "CustomerSalesCube.customer_type"),
|
|
428
|
+
("Customer", "quantity", "累计销量", "measure", "CustomerSalesCube.quantity"),
|
|
429
|
+
("Customer", "sales_amount", "累计销售额", "measure", "CustomerSalesCube.sales_amount"),
|
|
430
|
+
("Customer", "order_count", "订单数", "measure", "CustomerSalesCube.order_count"),
|
|
431
|
+
("Customer", "avg_order_value", "客单价", "measure", "CustomerSalesCube.avg_order_value"),
|
|
432
|
+
# SalesChannel 属性
|
|
433
|
+
("SalesChannel", "id", "渠道ID", "dimension", "ChannelSalesCube.channel_id"),
|
|
434
|
+
("SalesChannel", "quantity", "累计销量", "measure", "ChannelSalesCube.quantity"),
|
|
435
|
+
("SalesChannel", "sales_amount", "累计销售额", "measure", "ChannelSalesCube.sales_amount"),
|
|
436
|
+
("SalesChannel", "order_count", "订单数", "measure", "ChannelSalesCube.order_count"),
|
|
437
|
+
# SalesOrder 属性
|
|
438
|
+
("SalesOrder", "id", "订单ID", "dimension", "SalesCube.order_id"),
|
|
439
|
+
("SalesOrder", "line_id", "订单行", "dimension", "SalesCube.order_line_id"),
|
|
440
|
+
("SalesOrder", "date", "订单日期", "dimension", "SalesCube.order_date"),
|
|
441
|
+
("SalesOrder", "quantity", "数量", "measure", "SalesCube.quantity"),
|
|
442
|
+
("SalesOrder", "sales_amount", "销售金额", "measure", "SalesCube.sales_amount"),
|
|
443
|
+
("SalesOrder", "unit_price", "成交单价", "measure", "SalesCube.avg_unit_price"),
|
|
444
|
+
# SalesAnalysis 属性
|
|
445
|
+
("SalesAnalysis", "total_sales", "总销售额", "measure", "SalesCube.sales_amount"),
|
|
446
|
+
("SalesAnalysis", "total_quantity", "总销量", "measure", "SalesCube.quantity"),
|
|
447
|
+
("SalesAnalysis", "order_count", "订单数", "measure", "SalesCube.order_count"),
|
|
448
|
+
("SalesAnalysis", "avg_order_value", "客单价", "measure", "SalesCube.avg_order_value"),
|
|
449
|
+
("SalesAnalysis", "avg_unit_price", "平均单价", "measure", "SalesCube.avg_unit_price"),
|
|
450
|
+
]
|
|
451
|
+
for obj_code, prop_code, title, role, qualified_name in properties:
|
|
452
|
+
s.onto.define_property(obj_code, prop_code, title, semantic_role=role, qualified_name=qualified_name)
|
|
453
|
+
output.print(f"OK {len(properties)} 个属性")
|
|
454
|
+
|
|
455
|
+
# 9. 定义链接类型
|
|
456
|
+
output.print("\n[9/10] 定义链接类型...")
|
|
366
457
|
|
|
367
458
|
link_types = [
|
|
368
|
-
("order_contains_product", "订单包含产品", "SalesOrder", "Product"
|
|
369
|
-
("order_belongs_customer", "订单归属客户", "SalesOrder", "Customer"
|
|
370
|
-
("order_via_channel", "订单经渠道成交", "SalesOrder", "SalesChannel"
|
|
371
|
-
("product_has_orders", "产品有订单", "Product", "SalesOrder"
|
|
372
|
-
("customer_places_orders", "客户下单", "Customer", "SalesOrder"
|
|
373
|
-
("analysis_by_product", "分析归因产品", "SalesAnalysis", "Product"
|
|
374
|
-
("analysis_by_customer", "分析归因客户", "SalesAnalysis", "Customer"
|
|
375
|
-
("analysis_by_channel", "分析归因渠道", "SalesAnalysis", "SalesChannel"
|
|
459
|
+
("order_contains_product", "订单包含产品", "SalesOrder", "Product"),
|
|
460
|
+
("order_belongs_customer", "订单归属客户", "SalesOrder", "Customer"),
|
|
461
|
+
("order_via_channel", "订单经渠道成交", "SalesOrder", "SalesChannel"),
|
|
462
|
+
("product_has_orders", "产品有订单", "Product", "SalesOrder"),
|
|
463
|
+
("customer_places_orders", "客户下单", "Customer", "SalesOrder"),
|
|
464
|
+
("analysis_by_product", "分析归因产品", "SalesAnalysis", "Product"),
|
|
465
|
+
("analysis_by_customer", "分析归因客户", "SalesAnalysis", "Customer"),
|
|
466
|
+
("analysis_by_channel", "分析归因渠道", "SalesAnalysis", "SalesChannel"),
|
|
376
467
|
]
|
|
377
|
-
for code, name, from_obj, to_obj
|
|
378
|
-
s.onto.define_link_type(
|
|
379
|
-
code=code,
|
|
380
|
-
name=name,
|
|
381
|
-
from_object_type_code=from_obj,
|
|
382
|
-
to_object_type_code=to_obj,
|
|
383
|
-
description=desc,
|
|
384
|
-
)
|
|
468
|
+
for code, name, from_obj, to_obj in link_types:
|
|
469
|
+
s.onto.define_link_type(code, name, from_object_type_code=from_obj, to_object_type_code=to_obj)
|
|
385
470
|
output.print(f"OK {code}")
|
|
386
471
|
|
|
472
|
+
# 同步指标引用
|
|
387
473
|
s.sync_metric_refs()
|
|
388
474
|
output.print("OK sync_metric_refs")
|
|
389
475
|
|
|
390
476
|
summary = {
|
|
391
477
|
"ok": True,
|
|
392
478
|
"space_id": space_id,
|
|
393
|
-
"tables":
|
|
394
|
-
"table_relationships":
|
|
395
|
-
"cubes":
|
|
479
|
+
"tables": 5,
|
|
480
|
+
"table_relationships": 4,
|
|
481
|
+
"cubes": 4,
|
|
396
482
|
"object_types": 5,
|
|
397
|
-
"properties":
|
|
398
|
-
"link_types":
|
|
483
|
+
"properties": len(properties),
|
|
484
|
+
"link_types": len(link_types),
|
|
399
485
|
}
|
|
400
|
-
|
|
401
|
-
output.print("
|
|
402
|
-
output.
|
|
403
|
-
output.print("__JSON_SUMMARY__" + json.dumps(summary, ensure_ascii=True, default=str))
|
|
486
|
+
output.success("本体初始化完成")
|
|
487
|
+
output.print(f"space_id: {space_id}")
|
|
488
|
+
output.print("__JSON_SUMMARY__" + json.dumps(summary, ensure_ascii=False))
|