@dazitech/cli 3.0.8 → 3.0.9
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 +1 -1
- 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 +20 -1
- package/dist/docs/onto/dazi_script_sdk_reference.md +78 -12
- package/dist/docs/onto/function-guide.md +61 -33
- 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 +168 -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/350/204/232/346/234/254/347/274/226/345/206/231/346/214/207/345/215/227.md +63 -1
- package/dist/docs/onto//346/234/254/344/275/223/350/247/204/345/210/222/346/214/207/345/215/227.md +123 -15
- package/dist/docs/onto//350/204/232/346/234/254/350/277/220/350/241/214/347/272/240/351/224/231_/345/225/206/345/212/241/346/210/220/346/234/254/346/226/271/346/241/210/345/274/200/345/217/221/350/277/207/347/250/213.md +213 -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 +356 -233
- 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 +379 -296
- package/dist/examples/index.json +23 -17
- 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_ontology_init.py +232 -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_ontology_init.py +291 -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 +1 -1
- package/dist/prompts/onto/function-design.md +42 -22
- package/dist/prompts/onto/script-publish-run.md +15 -1
- 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,175 @@
|
|
|
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. 配置 347 对齐分类(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
|
+
}
|
|
100
|
+
|
|
101
|
+
# 与 347 + 附录 B 对齐;category 值必须是 347 标准中文名
|
|
102
|
+
CATEGORY_REGISTRY = {
|
|
103
|
+
"table": {
|
|
104
|
+
"时间维": ["dim_date"],
|
|
105
|
+
"维度表": ["dim_product", "dim_customer", "dim_channel"],
|
|
106
|
+
"事实表": ["fact_sales_order_line"],
|
|
107
|
+
},
|
|
108
|
+
"cube": {
|
|
109
|
+
"流程型": ["SalesCube"],
|
|
110
|
+
"主体型": ["ProductSalesCube", "CustomerSalesCube", "ChannelSalesCube"],
|
|
111
|
+
},
|
|
112
|
+
"object": {
|
|
113
|
+
"主数据": ["Product", "Customer"],
|
|
114
|
+
"参考": ["SalesChannel"],
|
|
115
|
+
"事务": ["SalesOrder"],
|
|
116
|
+
"分析": ["SalesAnalysis"],
|
|
117
|
+
},
|
|
118
|
+
"relation": {
|
|
119
|
+
"时间关联": [("fact_sales_order_line", "dim_date")],
|
|
120
|
+
"主数据关联": [
|
|
121
|
+
("fact_sales_order_line", "dim_product"),
|
|
122
|
+
("fact_sales_order_line", "dim_customer"),
|
|
123
|
+
("fact_sales_order_line", "dim_channel"),
|
|
124
|
+
],
|
|
125
|
+
},
|
|
126
|
+
"link": {
|
|
127
|
+
"归属关系": [
|
|
128
|
+
"order_contains_product",
|
|
129
|
+
"order_belongs_customer",
|
|
130
|
+
"order_via_channel",
|
|
131
|
+
"product_has_orders",
|
|
132
|
+
"customer_places_orders",
|
|
133
|
+
],
|
|
134
|
+
"分析归因": [
|
|
135
|
+
"analysis_by_product",
|
|
136
|
+
"analysis_by_customer",
|
|
137
|
+
"analysis_by_channel",
|
|
138
|
+
],
|
|
139
|
+
},
|
|
140
|
+
}
|
|
141
|
+
|
|
17
142
|
|
|
18
143
|
def main():
|
|
19
|
-
space_id = "
|
|
144
|
+
space_id = "space__misc_01"
|
|
20
145
|
s = space.get(space_id)
|
|
21
146
|
|
|
22
147
|
output.print("=== 产品销售本体初始化 ===")
|
|
23
148
|
output.print(f"空间: {space_id}")
|
|
24
149
|
|
|
25
150
|
# 1. 创建物理表
|
|
26
|
-
output.print("\n[1/
|
|
151
|
+
output.print("\n[1/10] 创建物理表...")
|
|
152
|
+
|
|
153
|
+
# dim_date(强制时间维)
|
|
154
|
+
s.sql.execute("""
|
|
155
|
+
CREATE TABLE IF NOT EXISTS dim_date (
|
|
156
|
+
date_key Int32,
|
|
157
|
+
calendar_date Date,
|
|
158
|
+
year Int16,
|
|
159
|
+
quarter Int8,
|
|
160
|
+
month Int8,
|
|
161
|
+
week_of_year Int8,
|
|
162
|
+
day_of_week Int8,
|
|
163
|
+
is_weekend UInt8,
|
|
164
|
+
year_month String
|
|
165
|
+
) ENGINE = MergeTree()
|
|
166
|
+
ORDER BY (date_key)
|
|
167
|
+
""")
|
|
168
|
+
output.print("OK dim_date")
|
|
27
169
|
|
|
170
|
+
# dim_product
|
|
28
171
|
s.sql.execute("""
|
|
29
|
-
CREATE TABLE IF NOT EXISTS
|
|
172
|
+
CREATE TABLE IF NOT EXISTS dim_product (
|
|
30
173
|
product_id String,
|
|
31
174
|
product_code String,
|
|
32
175
|
product_name String,
|
|
@@ -42,10 +185,11 @@ def main():
|
|
|
42
185
|
) ENGINE = MergeTree()
|
|
43
186
|
ORDER BY (product_id)
|
|
44
187
|
""")
|
|
45
|
-
output.print("OK
|
|
188
|
+
output.print("OK dim_product")
|
|
46
189
|
|
|
190
|
+
# dim_customer
|
|
47
191
|
s.sql.execute("""
|
|
48
|
-
CREATE TABLE IF NOT EXISTS
|
|
192
|
+
CREATE TABLE IF NOT EXISTS dim_customer (
|
|
49
193
|
customer_id String,
|
|
50
194
|
customer_code String,
|
|
51
195
|
customer_name String,
|
|
@@ -56,10 +200,11 @@ def main():
|
|
|
56
200
|
) ENGINE = MergeTree()
|
|
57
201
|
ORDER BY (customer_id)
|
|
58
202
|
""")
|
|
59
|
-
output.print("OK
|
|
203
|
+
output.print("OK dim_customer")
|
|
60
204
|
|
|
205
|
+
# dim_channel
|
|
61
206
|
s.sql.execute("""
|
|
62
|
-
CREATE TABLE IF NOT EXISTS
|
|
207
|
+
CREATE TABLE IF NOT EXISTS dim_channel (
|
|
63
208
|
channel_id String,
|
|
64
209
|
channel_code String,
|
|
65
210
|
channel_name String,
|
|
@@ -67,12 +212,14 @@ def main():
|
|
|
67
212
|
) ENGINE = MergeTree()
|
|
68
213
|
ORDER BY (channel_id)
|
|
69
214
|
""")
|
|
70
|
-
output.print("OK
|
|
215
|
+
output.print("OK dim_channel")
|
|
71
216
|
|
|
217
|
+
# fact_sales_order_line(含 date_key)
|
|
72
218
|
s.sql.execute("""
|
|
73
|
-
CREATE TABLE IF NOT EXISTS
|
|
219
|
+
CREATE TABLE IF NOT EXISTS fact_sales_order_line (
|
|
74
220
|
order_id String,
|
|
75
221
|
order_line_id String,
|
|
222
|
+
date_key Int32,
|
|
76
223
|
order_date Date,
|
|
77
224
|
product_id String,
|
|
78
225
|
product_category String,
|
|
@@ -87,60 +234,68 @@ def main():
|
|
|
87
234
|
currency String,
|
|
88
235
|
order_status String
|
|
89
236
|
) ENGINE = MergeTree()
|
|
90
|
-
ORDER BY (
|
|
237
|
+
ORDER BY (date_key, order_id, order_line_id)
|
|
91
238
|
""")
|
|
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 {
|
|
239
|
+
output.print("OK fact_sales_order_line")
|
|
240
|
+
|
|
241
|
+
# 2. 注册表(含 display_name / description)
|
|
242
|
+
output.print("\n[2/10] 注册表到空间...")
|
|
243
|
+
|
|
244
|
+
for tbl_name, meta in TABLE_REGISTRY.items():
|
|
245
|
+
s.tables.register_with_meta(
|
|
246
|
+
table_name=tbl_name,
|
|
247
|
+
display_name=meta["display_name"],
|
|
248
|
+
description=meta.get("description"),
|
|
249
|
+
columns=meta["columns"],
|
|
250
|
+
force_column_meta=True,
|
|
251
|
+
)
|
|
252
|
+
output.print(f"OK {tbl_name} ({meta['display_name']})")
|
|
106
253
|
|
|
107
|
-
# 3.
|
|
108
|
-
output.print("\n[3/
|
|
254
|
+
# 3. 注册表间关系(4 条,含 fact → dim_date)
|
|
255
|
+
output.print("\n[3/10] 注册表间关系...")
|
|
109
256
|
|
|
110
257
|
table_relationships = [
|
|
111
258
|
{
|
|
112
|
-
"from_table": "
|
|
113
|
-
"to_table": "
|
|
114
|
-
"join_sql": "
|
|
259
|
+
"from_table": "fact_sales_order_line",
|
|
260
|
+
"to_table": "dim_date",
|
|
261
|
+
"join_sql": "fact_sales_order_line.date_key = dim_date.date_key",
|
|
262
|
+
"join_keys": [{"from": "date_key", "to": "date_key"}],
|
|
263
|
+
"relationship_type": "many_to_one",
|
|
264
|
+
"description": "销售订单行关联日期",
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
"from_table": "fact_sales_order_line",
|
|
268
|
+
"to_table": "dim_product",
|
|
269
|
+
"join_sql": "fact_sales_order_line.product_id = dim_product.product_id",
|
|
115
270
|
"join_keys": [{"from": "product_id", "to": "product_id"}],
|
|
116
271
|
"relationship_type": "many_to_one",
|
|
117
|
-
"description": "
|
|
272
|
+
"description": "销售订单行关联产品",
|
|
118
273
|
},
|
|
119
274
|
{
|
|
120
|
-
"from_table": "
|
|
121
|
-
"to_table": "
|
|
122
|
-
"join_sql": "
|
|
275
|
+
"from_table": "fact_sales_order_line",
|
|
276
|
+
"to_table": "dim_customer",
|
|
277
|
+
"join_sql": "fact_sales_order_line.customer_id = dim_customer.customer_id",
|
|
123
278
|
"join_keys": [{"from": "customer_id", "to": "customer_id"}],
|
|
124
279
|
"relationship_type": "many_to_one",
|
|
125
280
|
"description": "销售订单行关联客户",
|
|
126
281
|
},
|
|
127
282
|
{
|
|
128
|
-
"from_table": "
|
|
129
|
-
"to_table": "
|
|
130
|
-
"join_sql": "
|
|
283
|
+
"from_table": "fact_sales_order_line",
|
|
284
|
+
"to_table": "dim_channel",
|
|
285
|
+
"join_sql": "fact_sales_order_line.channel_id = dim_channel.channel_id",
|
|
131
286
|
"join_keys": [{"from": "channel_id", "to": "channel_id"}],
|
|
132
287
|
"relationship_type": "many_to_one",
|
|
133
|
-
"description": "
|
|
288
|
+
"description": "销售订单行关联渠道",
|
|
134
289
|
},
|
|
135
290
|
]
|
|
136
291
|
for rel in table_relationships:
|
|
137
292
|
rid = s.tables.add_relationship(**rel)
|
|
138
293
|
output.print(f"OK {rel['from_table']} -> {rel['to_table']} ({rid})")
|
|
139
294
|
|
|
140
|
-
# 4. 注册 Cube
|
|
141
|
-
output.print("\n[4/
|
|
295
|
+
# 4. 注册 Cube(4 个)
|
|
296
|
+
output.print("\n[4/10] 注册 Cube...")
|
|
142
297
|
|
|
143
|
-
fact = "
|
|
298
|
+
fact = "fact_sales_order_line"
|
|
144
299
|
common_measures = [
|
|
145
300
|
{"name": "quantity", "col": "quantity", "agg": "sum", "title": "销售数量"},
|
|
146
301
|
{"name": "sales_amount", "col": "sales_amount", "agg": "sum", "title": "销售金额"},
|
|
@@ -149,6 +304,7 @@ def main():
|
|
|
149
304
|
{"name": "line_count", "col": "order_line_id", "agg": "uniq", "title": "订单行数"},
|
|
150
305
|
]
|
|
151
306
|
|
|
307
|
+
# SalesCube(Process · 销售分析主 Cube)
|
|
152
308
|
s.register_cube(
|
|
153
309
|
name="SalesCube",
|
|
154
310
|
table=fact,
|
|
@@ -157,16 +313,19 @@ def main():
|
|
|
157
313
|
dimensions=[
|
|
158
314
|
{"name": "order_id", "col": "order_id", "type": "string", "title": "订单ID"},
|
|
159
315
|
{"name": "order_line_id", "col": "order_line_id", "type": "string", "title": "订单行ID"},
|
|
316
|
+
{"name": "date_key", "col": "date_key", "type": "int32", "title": "日期键"},
|
|
160
317
|
{"name": "order_date", "col": "order_date", "type": "date", "title": "订单日期"},
|
|
161
318
|
{"name": "product_id", "col": "product_id", "type": "string", "title": "产品ID"},
|
|
162
319
|
{"name": "product_category", "col": "product_category", "type": "string", "title": "产品大类"},
|
|
163
320
|
{"name": "customer_id", "col": "customer_id", "type": "string", "title": "客户ID"},
|
|
164
321
|
{"name": "customer_region", "col": "customer_region", "type": "string", "title": "销售区域"},
|
|
322
|
+
{"name": "customer_type", "col": "customer_type", "type": "string", "title": "客户类型"},
|
|
165
323
|
{"name": "channel_id", "col": "channel_id", "type": "string", "title": "渠道ID"},
|
|
166
324
|
],
|
|
167
325
|
)
|
|
168
326
|
output.print("OK SalesCube")
|
|
169
327
|
|
|
328
|
+
# ProductSalesCube(Subject · 产品销售)
|
|
170
329
|
s.register_cube(
|
|
171
330
|
name="ProductSalesCube",
|
|
172
331
|
table=fact,
|
|
@@ -183,6 +342,7 @@ def main():
|
|
|
183
342
|
)
|
|
184
343
|
output.print("OK ProductSalesCube")
|
|
185
344
|
|
|
345
|
+
# CustomerSalesCube(Subject · 客户销售)
|
|
186
346
|
s.register_cube(
|
|
187
347
|
name="CustomerSalesCube",
|
|
188
348
|
table=fact,
|
|
@@ -200,6 +360,7 @@ def main():
|
|
|
200
360
|
)
|
|
201
361
|
output.print("OK CustomerSalesCube")
|
|
202
362
|
|
|
363
|
+
# ChannelSalesCube(Subject · 渠道销售)
|
|
203
364
|
s.register_cube(
|
|
204
365
|
name="ChannelSalesCube",
|
|
205
366
|
table=fact,
|
|
@@ -215,26 +376,8 @@ def main():
|
|
|
215
376
|
)
|
|
216
377
|
output.print("OK ChannelSalesCube")
|
|
217
378
|
|
|
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
379
|
# 5. 派生度量
|
|
237
|
-
output.print("\n[5/
|
|
380
|
+
output.print("\n[5/10] 配置派生度量...")
|
|
238
381
|
|
|
239
382
|
s.upsert_derived_measures(
|
|
240
383
|
"SalesCube",
|
|
@@ -253,6 +396,8 @@ def main():
|
|
|
253
396
|
},
|
|
254
397
|
],
|
|
255
398
|
)
|
|
399
|
+
output.print("OK SalesCube 派生度量")
|
|
400
|
+
|
|
256
401
|
s.upsert_derived_measures(
|
|
257
402
|
"ProductSalesCube",
|
|
258
403
|
[
|
|
@@ -264,6 +409,8 @@ def main():
|
|
|
264
409
|
},
|
|
265
410
|
],
|
|
266
411
|
)
|
|
412
|
+
output.print("OK ProductSalesCube 派生度量")
|
|
413
|
+
|
|
267
414
|
s.upsert_derived_measures(
|
|
268
415
|
"CustomerSalesCube",
|
|
269
416
|
[
|
|
@@ -275,10 +422,10 @@ def main():
|
|
|
275
422
|
},
|
|
276
423
|
],
|
|
277
424
|
)
|
|
278
|
-
output.print("OK 派生度量")
|
|
425
|
+
output.print("OK CustomerSalesCube 派生度量")
|
|
279
426
|
|
|
280
427
|
# 6. 对象类型
|
|
281
|
-
output.print("\n[6/
|
|
428
|
+
output.print("\n[6/10] 定义对象类型...")
|
|
282
429
|
|
|
283
430
|
object_types = [
|
|
284
431
|
("Product", "产品", "可售产品业务对象"),
|
|
@@ -292,7 +439,7 @@ def main():
|
|
|
292
439
|
output.print(f"OK {code}")
|
|
293
440
|
|
|
294
441
|
# 7. 绑定数据源
|
|
295
|
-
output.print("\n[7/
|
|
442
|
+
output.print("\n[7/10] 绑定数据源...")
|
|
296
443
|
|
|
297
444
|
bindings = [
|
|
298
445
|
("Product", "ProductSalesCube"),
|
|
@@ -301,103 +448,92 @@ def main():
|
|
|
301
448
|
("SalesOrder", "SalesCube"),
|
|
302
449
|
("SalesAnalysis", "SalesCube"),
|
|
303
450
|
]
|
|
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] 定义链接与同步指标...")
|
|
451
|
+
for code, cube in bindings:
|
|
452
|
+
s.onto.bind_source(code, "dazi_cube", config={"cube": cube})
|
|
453
|
+
output.print(f"OK {code} -> {cube}")
|
|
454
|
+
|
|
455
|
+
# 8. 定义属性
|
|
456
|
+
output.print("\n[8/10] 定义属性...")
|
|
457
|
+
|
|
458
|
+
properties = [
|
|
459
|
+
# Product 属性
|
|
460
|
+
("Product", "id", "产品ID", "dimension", "ProductSalesCube.product_id"),
|
|
461
|
+
("Product", "category", "产品大类", "dimension", "ProductSalesCube.product_category"),
|
|
462
|
+
("Product", "quantity", "累计销量", "measure", "ProductSalesCube.quantity"),
|
|
463
|
+
("Product", "sales_amount", "累计销售额", "measure", "ProductSalesCube.sales_amount"),
|
|
464
|
+
("Product", "order_count", "订单数", "measure", "ProductSalesCube.order_count"),
|
|
465
|
+
("Product", "avg_unit_price", "平均单价", "measure", "ProductSalesCube.avg_unit_price"),
|
|
466
|
+
# Customer 属性
|
|
467
|
+
("Customer", "id", "客户ID", "dimension", "CustomerSalesCube.customer_id"),
|
|
468
|
+
("Customer", "region", "销售区域", "dimension", "CustomerSalesCube.customer_region"),
|
|
469
|
+
("Customer", "type", "客户类型", "dimension", "CustomerSalesCube.customer_type"),
|
|
470
|
+
("Customer", "quantity", "累计销量", "measure", "CustomerSalesCube.quantity"),
|
|
471
|
+
("Customer", "sales_amount", "累计销售额", "measure", "CustomerSalesCube.sales_amount"),
|
|
472
|
+
("Customer", "order_count", "订单数", "measure", "CustomerSalesCube.order_count"),
|
|
473
|
+
("Customer", "avg_order_value", "客单价", "measure", "CustomerSalesCube.avg_order_value"),
|
|
474
|
+
# SalesChannel 属性
|
|
475
|
+
("SalesChannel", "id", "渠道ID", "dimension", "ChannelSalesCube.channel_id"),
|
|
476
|
+
("SalesChannel", "quantity", "累计销量", "measure", "ChannelSalesCube.quantity"),
|
|
477
|
+
("SalesChannel", "sales_amount", "累计销售额", "measure", "ChannelSalesCube.sales_amount"),
|
|
478
|
+
("SalesChannel", "order_count", "订单数", "measure", "ChannelSalesCube.order_count"),
|
|
479
|
+
# SalesOrder 属性
|
|
480
|
+
("SalesOrder", "id", "订单ID", "dimension", "SalesCube.order_id"),
|
|
481
|
+
("SalesOrder", "line_id", "订单行", "dimension", "SalesCube.order_line_id"),
|
|
482
|
+
("SalesOrder", "date", "订单日期", "dimension", "SalesCube.order_date"),
|
|
483
|
+
("SalesOrder", "quantity", "数量", "measure", "SalesCube.quantity"),
|
|
484
|
+
("SalesOrder", "sales_amount", "销售金额", "measure", "SalesCube.sales_amount"),
|
|
485
|
+
("SalesOrder", "unit_price", "成交单价", "measure", "SalesCube.avg_unit_price"),
|
|
486
|
+
# SalesAnalysis 属性
|
|
487
|
+
("SalesAnalysis", "total_sales", "总销售额", "measure", "SalesCube.sales_amount"),
|
|
488
|
+
("SalesAnalysis", "total_quantity", "总销量", "measure", "SalesCube.quantity"),
|
|
489
|
+
("SalesAnalysis", "order_count", "订单数", "measure", "SalesCube.order_count"),
|
|
490
|
+
("SalesAnalysis", "avg_order_value", "客单价", "measure", "SalesCube.avg_order_value"),
|
|
491
|
+
("SalesAnalysis", "avg_unit_price", "平均单价", "measure", "SalesCube.avg_unit_price"),
|
|
492
|
+
]
|
|
493
|
+
for obj_code, prop_code, title, role, qualified_name in properties:
|
|
494
|
+
s.onto.define_property(obj_code, prop_code, title, semantic_role=role, qualified_name=qualified_name)
|
|
495
|
+
output.print(f"OK {len(properties)} 个属性")
|
|
496
|
+
|
|
497
|
+
# 9. 定义链接类型
|
|
498
|
+
output.print("\n[9/10] 定义链接类型...")
|
|
366
499
|
|
|
367
500
|
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"
|
|
501
|
+
("order_contains_product", "订单包含产品", "SalesOrder", "Product"),
|
|
502
|
+
("order_belongs_customer", "订单归属客户", "SalesOrder", "Customer"),
|
|
503
|
+
("order_via_channel", "订单经渠道成交", "SalesOrder", "SalesChannel"),
|
|
504
|
+
("product_has_orders", "产品有订单", "Product", "SalesOrder"),
|
|
505
|
+
("customer_places_orders", "客户下单", "Customer", "SalesOrder"),
|
|
506
|
+
("analysis_by_product", "分析归因产品", "SalesAnalysis", "Product"),
|
|
507
|
+
("analysis_by_customer", "分析归因客户", "SalesAnalysis", "Customer"),
|
|
508
|
+
("analysis_by_channel", "分析归因渠道", "SalesAnalysis", "SalesChannel"),
|
|
376
509
|
]
|
|
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
|
-
)
|
|
510
|
+
for code, name, from_obj, to_obj in link_types:
|
|
511
|
+
s.onto.define_link_type(code, name, from_object_type_code=from_obj, to_object_type_code=to_obj)
|
|
385
512
|
output.print(f"OK {code}")
|
|
386
513
|
|
|
514
|
+
# 同步指标引用
|
|
387
515
|
s.sync_metric_refs()
|
|
388
516
|
output.print("OK sync_metric_refs")
|
|
389
517
|
|
|
518
|
+
# 10. 347 对齐分类
|
|
519
|
+
output.print("\n[10/10] 配置对象分类(347 对齐)...")
|
|
520
|
+
|
|
521
|
+
cat_counts = s.categories.apply_registry(CATEGORY_REGISTRY, skip_missing=True)
|
|
522
|
+
for kind, cnt in cat_counts.items():
|
|
523
|
+
if cnt:
|
|
524
|
+
output.print(f"OK 分类[{kind}] 挂载 {cnt} 项")
|
|
525
|
+
|
|
390
526
|
summary = {
|
|
391
527
|
"ok": True,
|
|
392
528
|
"space_id": space_id,
|
|
393
|
-
"tables":
|
|
394
|
-
"table_relationships":
|
|
395
|
-
"cubes":
|
|
529
|
+
"tables": 5,
|
|
530
|
+
"table_relationships": 4,
|
|
531
|
+
"cubes": 4,
|
|
396
532
|
"object_types": 5,
|
|
397
|
-
"properties":
|
|
398
|
-
"link_types":
|
|
533
|
+
"properties": len(properties),
|
|
534
|
+
"link_types": len(link_types),
|
|
535
|
+
"category_mounts": cat_counts,
|
|
399
536
|
}
|
|
400
|
-
|
|
401
|
-
output.print("
|
|
402
|
-
output.
|
|
403
|
-
output.print("__JSON_SUMMARY__" + json.dumps(summary, ensure_ascii=True, default=str))
|
|
537
|
+
output.success("本体初始化完成")
|
|
538
|
+
output.print(f"space_id: {space_id}")
|
|
539
|
+
output.print("__JSON_SUMMARY__" + json.dumps(summary, ensure_ascii=False))
|