aukeys-opscli 0.0.6__py3-none-any.whl

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.
Files changed (92) hide show
  1. aukeys_opscli-0.0.6.dist-info/METADATA +15 -0
  2. aukeys_opscli-0.0.6.dist-info/RECORD +92 -0
  3. aukeys_opscli-0.0.6.dist-info/WHEEL +4 -0
  4. aukeys_opscli-0.0.6.dist-info/entry_points.txt +2 -0
  5. opscli/__init__.py +9 -0
  6. opscli/amazon/__init__.py +13 -0
  7. opscli/amazon/cli.py +5 -0
  8. opscli/amazon/client.py +5 -0
  9. opscli/amazon/commands/__init__.py +1 -0
  10. opscli/amazon/commands/cli.py +200 -0
  11. opscli/amazon/domain/__init__.py +25 -0
  12. opscli/amazon/domain/exceptions.py +73 -0
  13. opscli/amazon/domain/models.py +74 -0
  14. opscli/amazon/exceptions.py +21 -0
  15. opscli/amazon/manager.py +5 -0
  16. opscli/amazon/models.py +5 -0
  17. opscli/amazon/parser.py +5 -0
  18. opscli/amazon/scraper.py +5 -0
  19. opscli/amazon/scraping/__init__.py +12 -0
  20. opscli/amazon/scraping/parser.py +66 -0
  21. opscli/amazon/scraping/scraper.py +315 -0
  22. opscli/amazon/services/__init__.py +5 -0
  23. opscli/amazon/services/manager.py +105 -0
  24. opscli/amazon/transport/__init__.py +5 -0
  25. opscli/amazon/transport/client.py +77 -0
  26. opscli/auth/__init__.py +79 -0
  27. opscli/auth/cli.py +255 -0
  28. opscli/auth/commands/__init__.py +1 -0
  29. opscli/auth/commands/cli.py +5 -0
  30. opscli/auth/config.py +55 -0
  31. opscli/auth/core/__init__.py +1 -0
  32. opscli/auth/core/device_flow.py +80 -0
  33. opscli/auth/core/system_registry.py +89 -0
  34. opscli/auth/core/token_manager.py +167 -0
  35. opscli/auth/domain/__init__.py +23 -0
  36. opscli/auth/domain/exceptions.py +33 -0
  37. opscli/auth/exceptions.py +23 -0
  38. opscli/auth/storage/__init__.py +1 -0
  39. opscli/auth/storage/credential_store.py +163 -0
  40. opscli/auth/storage/crypto.py +67 -0
  41. opscli/cli.py +36 -0
  42. opscli/config.py +3 -0
  43. opscli/query/__init__.py +6 -0
  44. opscli/query/cli.py +5 -0
  45. opscli/query/client.py +5 -0
  46. opscli/query/commands/__init__.py +1 -0
  47. opscli/query/commands/cli.py +140 -0
  48. opscli/query/domain/__init__.py +23 -0
  49. opscli/query/domain/exceptions.py +73 -0
  50. opscli/query/domain/models.py +21 -0
  51. opscli/query/exceptions.py +21 -0
  52. opscli/query/manager.py +5 -0
  53. opscli/query/models.py +5 -0
  54. opscli/query/services/__init__.py +5 -0
  55. opscli/query/services/manager.py +373 -0
  56. opscli/query/transport/__init__.py +5 -0
  57. opscli/query/transport/client.py +57 -0
  58. opscli/skills/__init__.py +37 -0
  59. opscli/skills/cli.py +5 -0
  60. opscli/skills/commands/__init__.py +1 -0
  61. opscli/skills/commands/cli.py +389 -0
  62. opscli/skills/detector.py +5 -0
  63. opscli/skills/discovery/__init__.py +5 -0
  64. opscli/skills/discovery/detector.py +225 -0
  65. opscli/skills/domain/__init__.py +23 -0
  66. opscli/skills/domain/exceptions.py +51 -0
  67. opscli/skills/domain/models.py +144 -0
  68. opscli/skills/exceptions.py +5 -0
  69. opscli/skills/manager.py +5 -0
  70. opscli/skills/models.py +19 -0
  71. opscli/skills/services/__init__.py +5 -0
  72. opscli/skills/services/manager.py +276 -0
  73. opscli/skills/sync/__init__.py +5 -0
  74. opscli/skills/sync/updater.py +274 -0
  75. opscli/skills/templates/ops-amazon/SKILL.md +181 -0
  76. opscli/skills/templates/ops-amazon/data/VERSION.json +4 -0
  77. opscli/skills/templates/ops-auth/SKILL.md +466 -0
  78. opscli/skills/templates/ops-auth/data/VERSION.json +4 -0
  79. opscli/skills/templates/ops-dataset-query/SKILL.md +691 -0
  80. opscli/skills/templates/ops-dataset-query/data/VERSION.json +4 -0
  81. opscli/skills/templates/ops-dataset-query/data/dataset_fields.csv +1 -0
  82. opscli/skills/templates/ops-dataset-query/data/datasets.csv +1 -0
  83. opscli/skills/templates/ops-dataset-query/data/query_metadata.json +4 -0
  84. opscli/skills/templates/ops-dataset-query/references//346/225/260/346/215/256/346/237/245/350/257/242/346/234/215/345/212/241/345/274/200/345/217/221/350/257/264/346/230/216/346/226/207/346/241/243.md +1126 -0
  85. opscli/skills/templates/ops-dataset-query/scripts/core.py +140 -0
  86. opscli/skills/templates/ops-dataset-query/scripts/query.py +145 -0
  87. opscli/skills/templates/ops-dataset-query/scripts/search.py +36 -0
  88. opscli/skills/templates/ops-dataset-query/scripts/updater.py +106 -0
  89. opscli/skills/templates/ops-skills/SKILL.md +494 -0
  90. opscli/skills/templates/ops-skills/data/VERSION.json +4 -0
  91. opscli/skills/updater.py +5 -0
  92. opscli/version.py +19 -0
@@ -0,0 +1,691 @@
1
+ ---
2
+ name: ops-dataset-query
3
+ description: 使用本地缓存的数据集与字段索引辅助检索和查询
4
+ version: v0.0.0
5
+ ---
6
+
7
+ # ops-dataset-query
8
+
9
+ 使用本地缓存的数据集与字段索引辅助检索可用数据集、维度和指标,通过 `opscli query` 执行数据查询,通过 `opscli skills upgrade` 拉取远端最新数据。
10
+
11
+ ---
12
+
13
+ ## 调用前置要求
14
+
15
+ > **【强制】使用本 Skill 前,必须先阅读 `references/数据查询服务开发说明文档.md`**
16
+
17
+ - 若需求涉及 `innerWhere`、子查询数据集、`translate`、`dataComparison`、高级计算(`MOY` / `ACC` / `PPT`)、权限占位符、小计/总计、交叉表/透视表、多次查询等场景,**必须**回到该引用文档逐节核对后再生成 payload
18
+ - WHERE 操作符完整列表、聚合函数完整列表、请求体完整结构均在引用文档中,本文件不再赘述
19
+ - 若引用文档与仓库原文冲突,以仓库原文 `docs/query/数据查询服务开发说明文档.md` 为准
20
+
21
+ ---
22
+
23
+ ## 使用原则
24
+
25
+ - 本 Skill 只负责本地字段搜索、缓存读取和辅助构造查询参数
26
+ - 所有远端查询动作必须通过 `opscli query` 执行,**禁止直接调用后端 HTTP 接口**
27
+ - 本地数据过期时,先执行 `opscli skills upgrade ops-dataset-query` 再重试查询
28
+ - 字段搜索结果已按相关性排序(精确匹配 > 子串匹配 > 关键词匹配)
29
+ - `opscli query build` 适合常见聚合查询(select / groupBy / where / having / orderBy / limit / offset / dryRun)
30
+ - `opscli query run` 适合透传完整高级 payload(`innerWhere`、`joins`、`dataComparison`、`translate` 等复杂场景)
31
+
32
+ ### 【强制】比较类查询优先级规则
33
+
34
+ > 涉及环比、同比、趋势对比等场景时,**必须按以下优先级选择方案,禁止跳过高优先级直接多次调用 CLI 后在客户端合并结果**。
35
+
36
+ | 优先级 | 场景 | 方案 |
37
+ |--------|------|------|
38
+ | ① 最优 | 当期 vs 对比期汇总对比(环比/同比) | `dataComparison`(服务端条件聚合,一次 SQL) |
39
+ | ② 次优 | 按时间粒度分组的趋势环比/同比 | `MOY` 高级计算(服务端窗口函数,一次 SQL) |
40
+ | ③ 兜底 | ①② 均因工具限制无法使用时 | 多次 `opscli query run` + 客户端合并 |
41
+
42
+ > ⚠️ **已知限制**:`dataComparison` 已在 opscli `query build` 中通过 `--data-comparison` 参数支持,但 Python 查询服务的 Pydantic 模型尚未接受此字段(报 `Extra inputs are not permitted`)。待后端修复后,`dataComparison` 将恢复为首选。`comparison`(MOY/ACC/PPT)写在 `select` 字段内部可正常透传。
43
+
44
+ ---
45
+
46
+ ## 本地数据文件
47
+
48
+ | 文件 | 内容 | 说明 |
49
+ |------|------|------|
50
+ | `data/VERSION.json` | 版本号 | `{"name": "ops-dataset-query", "version": "v1.x.x"}` |
51
+ | `data/dataset_fields.csv` | 字段明细 | dataset_alias、field_name、verbose_name、field_type、is_dttm、description、keywords 等 |
52
+ | `data/datasets.csv` | 数据集列表 | table_id、dataset_alias、dataset_name、dataset_type、dataset_category、description、keywords 等 |
53
+ | `data/query_metadata.json` | 查询元数据 | 字段类型映射、可用聚合方式等 |
54
+
55
+ CSV 各列详细说明见 `references/数据查询服务开发说明文档.md` 附录。
56
+
57
+ ---
58
+
59
+ ## 命令参考
60
+
61
+ ### `opscli query metadata`
62
+
63
+ 读取指定数据集的 query metadata(字段定义、可用聚合方式等)。
64
+
65
+ ```
66
+ 选项:
67
+ --dataset TEXT dataset_alias(与 --table-id 二选一)
68
+ --table-id INTEGER table_id(与 --dataset 二选一)
69
+ --skills-dir TEXT 指定 Skill 目录
70
+ --pretty 格式化 JSON 输出
71
+ ```
72
+
73
+ ```bash
74
+ opscli query metadata --dataset sales_order_d --pretty
75
+ opscli query metadata --table-id 123 --pretty
76
+ ```
77
+
78
+ ---
79
+
80
+ ### `opscli query build`
81
+
82
+ 基于简化参数构造标准 query payload,可选直接执行。
83
+
84
+ ```
85
+ 选项:
86
+ --dataset TEXT dataset_alias(与 --table-id 二选一)
87
+ --table-id INTEGER table_id
88
+ --dimension TEXT 维度:field_name[:alias],可重复
89
+ --metric TEXT 指标:field_name:aggregation[:alias],可重复
90
+ --where TEXT 筛选:field|operator|value_json,可重复
91
+ --where-json TEXT where 条件 JSON 字符串(与 --where 互斥)
92
+ --where-file TEXT where 条件 JSON 文件路径(与 --where 互斥)
93
+ --having TEXT having 条件:expr|operator|value_json,可重复
94
+ --order-by TEXT 排序:expr[:asc|desc],可重复
95
+ --limit INTEGER 返回行数,默认 20
96
+ --offset INTEGER 分页偏移,默认 0
97
+ --dry-run 仅生成 SQL,不执行查询
98
+ --output TEXT 将 payload 写入指定文件
99
+ --data-comparison TEXT 数据对比:field,start_date,end_date(例: date_id,2026-03-01,2026-03-22)
100
+ --run 构造后立即执行查询
101
+ --skills-dir TEXT 指定 Skill 目录
102
+ --pretty 格式化 JSON 输出
103
+ ```
104
+
105
+ #### 参数格式
106
+
107
+ **dimension**:`field_name[:alias]`
108
+ - `date_id` → 按 date_id 分组
109
+ - `date_id:日期` → 按 date_id 分组,列名改为"日期"
110
+
111
+ **metric**:`field_name:aggregation[:alias]`
112
+ - `order_cost:sum` → 求和
113
+ - `order_cost:sum:total_cost` → 求和,列名改为 total_cost
114
+ - `order_id:count_distinct:uv` → 去重计数
115
+
116
+ > 完整聚合函数列表见 `references/数据查询服务开发说明文档.md` 第八章。
117
+
118
+ **where**:`field|operator|value_json`(完整操作符列表见引用文档第五章)
119
+
120
+ ```bash
121
+ --where "date_id|gte|\"2024-01-01\""
122
+ --where "country_id|in|[\"CN\",\"US\"]"
123
+ ```
124
+
125
+ **where-json / where-file**:传入结构化 where 对象,支持嵌套逻辑分组:
126
+
127
+ ```bash
128
+ --where-json '{"operator":"AND","conditions":[{"field":"country_id","operator":"in","value":["CN","US"]}]}'
129
+ --where-file /tmp/where.json
130
+ ```
131
+
132
+ **having**:`expr|operator|value_json`
133
+
134
+ ```bash
135
+ --having 'total_cost|gt|1000'
136
+ ```
137
+
138
+ **order-by**:`expr[:asc|desc]`
139
+
140
+ ```bash
141
+ --order-by total_cost:desc
142
+ --order-by date_id # 默认升序
143
+ ```
144
+
145
+ #### 示例
146
+
147
+ ```bash
148
+ # 构造 payload 并写入文件
149
+ opscli query build \
150
+ --dataset sales_order_d \
151
+ --dimension date_id \
152
+ --dimension country_id:country \
153
+ --metric order_cost:sum:total_cost \
154
+ --metric order_id:count_distinct:order_count \
155
+ --where "date_id|gte|\"2024-01-01\"" \
156
+ --where "date_id|lte|\"2024-12-31\"" \
157
+ --order-by total_cost:desc \
158
+ --limit 50 \
159
+ --output /tmp/query.json
160
+
161
+ # 构造后直接执行
162
+ opscli query build \
163
+ --dataset sales_order_d \
164
+ --dimension date_id \
165
+ --metric order_cost:sum \
166
+ --run --pretty
167
+
168
+ # 使用 where-file 传入复杂条件
169
+ opscli query build \
170
+ --dataset sales_order_d \
171
+ --dimension date_id \
172
+ --metric order_cost:sum \
173
+ --where-file /tmp/where.json \
174
+ --run --pretty
175
+
176
+ # 带 having 的聚合查询
177
+ opscli query build \
178
+ --dataset sales_order_d \
179
+ --dimension country_id:country \
180
+ --metric order_cost:sum:total_cost \
181
+ --having 'total_cost|gt|1000' \
182
+ --order-by total_cost:desc \
183
+ --run --pretty
184
+
185
+ # 分页查询(第 2 页,每页 20 条)
186
+ opscli query build \
187
+ --dataset sales_order_d \
188
+ --dimension date_id \
189
+ --metric order_cost:sum \
190
+ --limit 20 --offset 20 \
191
+ --run --pretty
192
+
193
+ # 仅生成 SQL,不执行
194
+ opscli query build \
195
+ --dataset sales_order_d \
196
+ --dimension date_id \
197
+ --metric order_cost:sum:total_cost \
198
+ --dry-run --run --pretty
199
+
200
+ # 带数据对比(环比上月同期)
201
+ opscli query build \
202
+ --table-id 1104 \
203
+ --dimension dept_name \
204
+ --metric price:sum:total_price \
205
+ --metric order_qty:sum:total_qty \
206
+ --where "date_id|gte|\"2026-04-01\"" \
207
+ --where "date_id|lte|\"2026-04-22\"" \
208
+ --data-comparison "date_id,2026-03-01,2026-03-22" \
209
+ --output /tmp/comparison.json
210
+ ```
211
+
212
+ ---
213
+
214
+ ### `opscli query run`
215
+
216
+ 执行查询,将 payload 文件转发到服务端。
217
+
218
+ ```
219
+ 选项:
220
+ --payload TEXT 查询 JSON 文件路径(必填)
221
+ --pretty 格式化 JSON 输出
222
+ ```
223
+
224
+ ```bash
225
+ opscli query run --payload /tmp/query.json --pretty
226
+ ```
227
+
228
+ **输出格式:**
229
+
230
+ ```json
231
+ {
232
+ "success": true,
233
+ "command": "query run",
234
+ "data": {
235
+ "success": true,
236
+ "data": [{"date_id": "2024-01-01", "total_cost": "12345.67"}],
237
+ "meta": {"rowCount": 2, "totalCount": 365}
238
+ },
239
+ "error": null
240
+ }
241
+ ```
242
+
243
+ ---
244
+
245
+ ### `opscli skills upgrade ops-dataset-query`
246
+
247
+ 从运营系统后端拉取最新字段数据,原子替换本地 `data/` 目录。
248
+
249
+ ```
250
+ 选项:
251
+ --force 强制重新拉取(忽略版本比较)
252
+ --skills-dir 指定 Skill 目录
253
+ --pretty 格式化 JSON 输出
254
+ ```
255
+
256
+ ```bash
257
+ # 检查版本状态
258
+ opscli skills status --pretty
259
+
260
+ # 升级到最新
261
+ opscli skills upgrade ops-dataset-query
262
+
263
+ # 强制重新拉取
264
+ opscli skills upgrade ops-dataset-query --force
265
+ ```
266
+
267
+ ---
268
+
269
+ ## 字段搜索(本地索引)
270
+
271
+ 本 Skill 内置本地字段索引,可用于辅助确认 `dataset_alias`、`field_name`、`verbose_name`、`keywords`。
272
+
273
+ **推荐流程**:本地索引确认字段名 → `opscli query metadata` 查看完整 metadata → `opscli query build` 或手写 payload + `opscli query run`
274
+
275
+ **搜索排序策略(相关性从高到低):**
276
+
277
+ | 匹配类型 | 分值 |
278
+ |---------|------|
279
+ | `field_name` 精确匹配 | 120 |
280
+ | `verbose_name` 精确匹配 | 100 |
281
+ | `field_name` 子串匹配 | 60 |
282
+ | `verbose_name` 子串匹配 | 45 |
283
+ | `dataset_alias` 精确匹配 | 40 |
284
+ | `keywords` 子串匹配 | 35 |
285
+ | `description` 子串匹配 | 10 |
286
+
287
+ ---
288
+
289
+ ## 高级查询说明
290
+
291
+ 详细规则见 `references/数据查询服务开发说明文档.md`,核心章节:
292
+
293
+ | 场景 | 参考章节 |
294
+ |------|---------|
295
+ | innerWhere、子查询数据集 | 第三章 数据集类型详解 |
296
+ | WHERE 操作符、嵌套条件、translate | 第五章 WHERE 条件构建指南 |
297
+ | dataComparison 数据对比 | 第六章 |
298
+ | 多次查询(交叉表/透视表/堆叠图) | 第七章 |
299
+ | SELECT 字段、聚合函数、高级计算(MOY/ACC/PPT) | 第八章 |
300
+ | 权限占位符 | 第四章 |
301
+ | 分页与排序 | 第九章 |
302
+
303
+ **使用建议**:
304
+ - 普通聚合优先使用 `opscli query build`
305
+ - 涉及上述高级场景时,先阅读引用文档,再手写 payload + `opscli query run`
306
+
307
+ ---
308
+
309
+ ## 数据对比与高级计算
310
+
311
+ ### 方案选择决策流程
312
+
313
+ ```
314
+ 用户需要比较两个时间段的数据?
315
+ ├── YES → 需要按时间粒度(日/月)分组展示趋势?
316
+ │ ├── YES → 使用 MOY 高级计算(comparison 写在 select 字段内)
317
+ │ └── NO → 需要当期 vs 对比期汇总对比?
318
+ │ ├── YES → 优先 dataComparison(当前 opscli v0.0.4 有 bug,降级用 MOY)
319
+ │ └── NO → 普通聚合 opscli query build
320
+ └── NO → 普通聚合 opscli query build
321
+ ```
322
+
323
+ ---
324
+
325
+ ### dataComparison 数据对比
326
+
327
+ > 服务端将当期和对比期合并为**一次 SQL**(条件聚合),每个度量字段自动裂变为 4 个字段。
328
+
329
+ **字段裂变规则**(以别名 `total_price` 为例):
330
+
331
+ | 裂变字段 | 含义 |
332
+ |---------|------|
333
+ | `total_price` | 当期值 |
334
+ | `last_total_price` | 对比期值 |
335
+ | `diff_total_price` | 绝对差值(当期 - 对比期) |
336
+ | `pct_total_price` | 变化率(差值 / ABS(对比期)),上期为 0 时返回 null |
337
+
338
+ **payload 结构**(`opscli query run --payload`):
339
+
340
+ ```json
341
+ {
342
+ "tableId": 1104,
343
+ "query": {
344
+ "select": [
345
+ {"expr": "ds_xxx.dept_name", "alias": "dept_name"},
346
+ {"expr": "ds_xxx.price", "alias": "total_price", "aggregation": "SUM"},
347
+ {"expr": "ds_xxx.order_qty", "alias": "total_qty", "aggregation": "SUM"}
348
+ ],
349
+ "groupBy": ["dept_name"],
350
+ "where": {
351
+ "operator": "AND",
352
+ "conditions": [
353
+ {"field": "ds_xxx.date_id", "operator": "gte", "value": "2026-04-01"},
354
+ {"field": "ds_xxx.date_id", "operator": "lte", "value": "2026-04-22"}
355
+ ]
356
+ },
357
+ "orderBy": [{"expr": "total_price", "desc": true}],
358
+ "limit": 50,
359
+ "offset": 0
360
+ },
361
+ "dataComparison": {
362
+ "switch": true,
363
+ "field": "ds_xxx.date_id",
364
+ "startDate": "2026-03-01",
365
+ "endDate": "2026-03-22"
366
+ }
367
+ }
368
+ ```
369
+
370
+ > ⚠️ **已知限制**:opscli 已支持通过 `--data-comparison` 参数构造此结构,但 Python 查询服务的 Pydantic 模型尚未接受 `dataComparison` 字段(报 `Extra inputs are not permitted`)。待后端服务修复后此方案方可使用。临时降级使用 MOY(见下节)。
371
+
372
+ **适用场景**:当期(如本月 1-22 日) vs 对比期(如上月同期 1-22 日)的汇总数据对比,**同期天数对等**,适合月度/季度环比汇总看板。
373
+
374
+ ---
375
+
376
+ ### MOY 同环比(高级计算)
377
+
378
+ > 服务端通过窗口函数 `LAG()` 计算,**`comparison` 字段写在 `select` 内部**,opscli 可正常透传。
379
+
380
+ **前提条件**:`groupBy` 中**必须同时包含日期维度和其他业务维度**。
381
+
382
+ **type 枚举速查**:
383
+
384
+ | 类型 | `type` 值 | groupBy 日期格式 |
385
+ |------|-----------|----------------|
386
+ | 月环比 | `MOM_MONTH` | `DATE_FORMAT(ds_xxx.date_id, '%Y-%m')` |
387
+ | 日环比 | `MOM_DAY` | `DATE_FORMAT(ds_xxx.date_id, '%Y-%m-%d')` |
388
+ | 周环比 | `MOM_WEEK` | `DATE_FORMAT(ds_xxx.date_id, '%x-%v')` |
389
+ | 月同比 | `YOY_MONTH` | `DATE_FORMAT(ds_xxx.date_id, '%Y-%m-%d')` |
390
+ | 年同比 | `YOY_YEAR` | `DATE_FORMAT(ds_xxx.date_id, '%Y-%m-%d')` |
391
+
392
+ **`cacl_type` 字段语义**(重要,容易误解):
393
+
394
+ | `cacl_type` | 字段值含义 | 说明 |
395
+ |-------------|-----------|------|
396
+ | `ORIGINAL` | **上期值(LAG)** | 不是当期原始值!是前一期的聚合结果 |
397
+ | `COMPARE` | 当期 − 上期 | 正数=增长,负数=下滑 |
398
+ | `PERCENT` | (当期 − 上期) / ABS(上期) | 环比变化率,上期为 0 时返回 null |
399
+
400
+ > 💡 当期实际值 = `ORIGINAL 字段值` + `COMPARE 字段值`
401
+
402
+ **完整 payload 示例(月环比,按部门)**:
403
+
404
+ ```json
405
+ {
406
+ "tableId": 1104,
407
+ "query": {
408
+ "select": [
409
+ {"expr": "ds_xxx.dept_name", "alias": "dept_name"},
410
+ {"expr": "DATE_FORMAT(ds_xxx.date_id, '%Y-%m')", "alias": "month"},
411
+ {
412
+ "expr": "ds_xxx.price",
413
+ "alias": "price_prev",
414
+ "comparison": "MOY",
415
+ "params": {
416
+ "date": "DATE_FORMAT(ds_xxx.date_id, '%Y-%m')",
417
+ "dim": ["dept_name"],
418
+ "type": "MOM_MONTH",
419
+ "cacl_type": "ORIGINAL",
420
+ "aggregation": "SUM"
421
+ }
422
+ },
423
+ {
424
+ "expr": "ds_xxx.price",
425
+ "alias": "price_diff",
426
+ "comparison": "MOY",
427
+ "params": {
428
+ "date": "DATE_FORMAT(ds_xxx.date_id, '%Y-%m')",
429
+ "dim": ["dept_name"],
430
+ "type": "MOM_MONTH",
431
+ "cacl_type": "COMPARE",
432
+ "aggregation": "SUM"
433
+ }
434
+ },
435
+ {
436
+ "expr": "ds_xxx.price",
437
+ "alias": "price_pct",
438
+ "comparison": "MOY",
439
+ "params": {
440
+ "date": "DATE_FORMAT(ds_xxx.date_id, '%Y-%m')",
441
+ "dim": ["dept_name"],
442
+ "type": "MOM_MONTH",
443
+ "cacl_type": "PERCENT",
444
+ "aggregation": "SUM"
445
+ }
446
+ }
447
+ ],
448
+ "groupBy": ["dept_name", "month"],
449
+ "where": {
450
+ "operator": "AND",
451
+ "conditions": [
452
+ {"field": "ds_xxx.date_id", "operator": "gte", "value": "2026-03-01"},
453
+ {"field": "ds_xxx.date_id", "operator": "lte", "value": "2026-04-22"}
454
+ ]
455
+ },
456
+ "orderBy": [
457
+ {"expr": "month", "desc": true},
458
+ {"expr": "price_diff", "desc": true}
459
+ ],
460
+ "limit": 100,
461
+ "offset": 0
462
+ }
463
+ }
464
+ ```
465
+
466
+ **结果读取说明**:
467
+ - 当月行(如 `2026-04`):`price_prev` = 上月值,`price_diff` = 本月增减,`price_pct` = 环比率
468
+ - 上月行(如 `2026-03`):`price_prev` = 上上月值,其他同理
469
+ - WHERE 范围需覆盖**当期 + 对比期**(至少两个完整粒度),否则最早一期 `price_prev` 为 NULL
470
+
471
+ **适用场景**:按月/日/周分组的趋势图、时序对比;注意 MOY 用整个历史周期做 LAG,与 `dataComparison` 的同期对比不同,**月中查询时本月 vs 上月完整月存在天数不等的偏差**。
472
+
473
+ ---
474
+
475
+ ### ACC 累加计算
476
+
477
+ > 按时间序列滚动累计(Running Total),适合 YTD 累计销售额等场景。
478
+
479
+ ```json
480
+ {
481
+ "expr": "ds_xxx.price",
482
+ "alias": "price_acc",
483
+ "comparison": "ACC",
484
+ "params": {
485
+ "dim": [],
486
+ "aggregation": "SUM"
487
+ }
488
+ }
489
+ ```
490
+
491
+ > `dim` 当前固定传空数组 `[]`,暂不支持分组累加。
492
+
493
+ ---
494
+
495
+ ### PPT 占比计算
496
+
497
+ > 当前维度指标值 ÷ 全局总量,适合各部门销售额占比等场景。
498
+
499
+ ```json
500
+ {
501
+ "expr": "ds_xxx.price",
502
+ "alias": "price_ppt",
503
+ "comparison": "PPT",
504
+ "params": {
505
+ "dim": [],
506
+ "aggregation": "SUM"
507
+ }
508
+ }
509
+ ```
510
+
511
+ ---
512
+
513
+ ### 降级方案:多次查询客户端合并
514
+
515
+ > **仅在 dataComparison 和 MOY 均无法满足需求时使用**(如工具限制、跨数据集对比)。
516
+
517
+ ```bash
518
+ # 当期查询
519
+ opscli query build --table-id 1104 \
520
+ --dimension dept_name:dept_name \
521
+ --metric price:sum:total_price \
522
+ --where "date_id|gte|\"2026-04-01\"" \
523
+ --where "date_id|lte|\"2026-04-22\"" \
524
+ --run --pretty > /tmp/cur.json
525
+
526
+ # 对比期查询
527
+ opscli query build --table-id 1104 \
528
+ --dimension dept_name:dept_name \
529
+ --metric price:sum:total_price \
530
+ --where "date_id|gte|\"2026-03-01\"" \
531
+ --where "date_id|lte|\"2026-03-22\"" \
532
+ --run --pretty > /tmp/prev.json
533
+
534
+ # 客户端合并(Python 示例)
535
+ python3 -c "
536
+ import json
537
+ cur = {r['dept_name']: r for r in json.load(open('/tmp/cur.json'))['data']['result']['data']}
538
+ prev = {r['dept_name']: r for r in json.load(open('/tmp/prev.json'))['data']['result']['data']}
539
+ for dept, c in cur.items():
540
+ p = prev.get(dept, {})
541
+ cv, pv = float(c['total_price']), float(p.get('total_price', 0))
542
+ pct = (cv - pv) / abs(pv) * 100 if pv else float('inf')
543
+ print(f'{dept}: 本期={cv:,.0f} 上期={pv:,.0f} 环比={pct:+.1f}%')
544
+ "
545
+ ```
546
+
547
+ ---
548
+
549
+ ## 错误处理
550
+
551
+ | 场景 | 解决方法 |
552
+ |------|---------|
553
+ | 本地数据为空 | `opscli skills upgrade ops-dataset-query` |
554
+ | dataset_alias 不存在 | 检查拼写或 `opscli skills upgrade` 同步最新数据集 |
555
+ | 未登录 / Token 过期 | `opscli auth login` 重新登录 |
556
+ | opscli 未找到 | 激活虚拟环境或设置 `OPSCLI_BIN` |
557
+ | 远端 manifest 不存在 | 检查网络和 ops 服务地址配置 |
558
+ | payload 文件不存在 | 先 `opscli query build --output` 生成 |
559
+
560
+ ---
561
+
562
+ ## 典型工作流
563
+
564
+ ### 探索数据集 → 构造 → 执行
565
+
566
+ ```bash
567
+ # 1. 通过本地索引确认数据集和字段名
568
+ # 2. 查看完整 metadata
569
+ opscli query metadata --dataset sales_order_d --pretty
570
+ # 3. 构造并执行
571
+ opscli query build \
572
+ --dataset sales_order_d \
573
+ --dimension date_id \
574
+ --metric order_cost:sum:total_cost \
575
+ --where "date_id|gte|\"2024-01-01\"" \
576
+ --order-by total_cost:desc \
577
+ --limit 50 \
578
+ --run --pretty
579
+ ```
580
+
581
+ ### 手写高级 payload → 执行
582
+
583
+ ```bash
584
+ # 1. 按引用文档规范手写 payload(含 innerWhere / dataComparison 等)
585
+ # 2. 执行
586
+ opscli query run --payload /tmp/advanced_query.json --pretty
587
+ ```
588
+
589
+ ### 环比查询(MOY 月环比,当前推荐方案)
590
+
591
+ ```bash
592
+ # 1. 手写含 comparison 字段的 payload,覆盖当期 + 对比期的 WHERE 范围
593
+ cat > /tmp/moy_query.json << 'EOF'
594
+ {
595
+ "tableId": 1104,
596
+ "query": {
597
+ "select": [
598
+ {"expr": "ds_xxx.dept_name", "alias": "dept_name"},
599
+ {"expr": "DATE_FORMAT(ds_xxx.date_id, '%Y-%m')", "alias": "month"},
600
+ {
601
+ "expr": "ds_xxx.price", "alias": "price_prev",
602
+ "comparison": "MOY",
603
+ "params": {"date": "DATE_FORMAT(ds_xxx.date_id, '%Y-%m')", "dim": ["dept_name"], "type": "MOM_MONTH", "cacl_type": "ORIGINAL", "aggregation": "SUM"}
604
+ },
605
+ {
606
+ "expr": "ds_xxx.price", "alias": "price_diff",
607
+ "comparison": "MOY",
608
+ "params": {"date": "DATE_FORMAT(ds_xxx.date_id, '%Y-%m')", "dim": ["dept_name"], "type": "MOM_MONTH", "cacl_type": "COMPARE", "aggregation": "SUM"}
609
+ },
610
+ {
611
+ "expr": "ds_xxx.price", "alias": "price_pct",
612
+ "comparison": "MOY",
613
+ "params": {"date": "DATE_FORMAT(ds_xxx.date_id, '%Y-%m')", "dim": ["dept_name"], "type": "MOM_MONTH", "cacl_type": "PERCENT", "aggregation": "SUM"}
614
+ }
615
+ ],
616
+ "groupBy": ["dept_name", "month"],
617
+ "where": {
618
+ "operator": "AND",
619
+ "conditions": [
620
+ {"field": "ds_xxx.date_id", "operator": "gte", "value": "2026-03-01"},
621
+ {"field": "ds_xxx.date_id", "operator": "lte", "value": "2026-04-22"}
622
+ ]
623
+ },
624
+ "orderBy": [{"expr": "month", "desc": true}, {"expr": "price_diff", "desc": true}],
625
+ "limit": 100, "offset": 0
626
+ }
627
+ }
628
+ EOF
629
+
630
+ # 2. 执行查询
631
+ opscli query run --payload /tmp/moy_query.json --pretty
632
+
633
+ # 3. 结果说明:
634
+ # price_prev = 上月销售额(LAG值)
635
+ # price_diff = 本月增减额(当期 - 上期)
636
+ # price_pct = 环比变化率(小数,×100 得百分比)
637
+ # 当期实际值 = price_prev + price_diff
638
+ ```
639
+
640
+ ### 环比查询(dataComparison,待 opscli 修复后使用)
641
+
642
+ ```bash
643
+ # dataComparison 正确 payload 结构(当前 opscli v0.0.4 暂不支持,留存备用)
644
+ cat > /tmp/dc_query.json << 'EOF'
645
+ {
646
+ "tableId": 1104,
647
+ "query": {
648
+ "select": [
649
+ {"expr": "ds_xxx.dept_name", "alias": "dept_name"},
650
+ {"expr": "ds_xxx.price", "alias": "total_price", "aggregation": "SUM"}
651
+ ],
652
+ "groupBy": ["dept_name"],
653
+ "where": {
654
+ "operator": "AND",
655
+ "conditions": [
656
+ {"field": "ds_xxx.date_id", "operator": "gte", "value": "2026-04-01"},
657
+ {"field": "ds_xxx.date_id", "operator": "lte", "value": "2026-04-22"}
658
+ ]
659
+ },
660
+ "orderBy": [{"expr": "total_price", "desc": true}],
661
+ "limit": 50, "offset": 0
662
+ },
663
+ "dataComparison": {
664
+ "switch": true,
665
+ "field": "ds_xxx.date_id",
666
+ "startDate": "2026-03-01",
667
+ "endDate": "2026-03-22"
668
+ }
669
+ }
670
+ EOF
671
+ # 响应自动包含:total_price / last_total_price / diff_total_price / pct_total_price
672
+ ```
673
+
674
+ ### 数据更新 → 重新查询
675
+
676
+ ```bash
677
+ opscli skills status --pretty
678
+ opscli skills upgrade ops-dataset-query
679
+ opscli query metadata --dataset sales_order_d --pretty
680
+ ```
681
+
682
+ ---
683
+
684
+ ## 安装与管理
685
+
686
+ ```bash
687
+ opscli skills install ops-dataset-query # 安装
688
+ opscli skills install ops-dataset-query --force # 强制重装
689
+ opscli skills status --pretty # 查看版本
690
+ opscli skills upgrade ops-dataset-query # 升级
691
+ ```
@@ -0,0 +1,4 @@
1
+ {
2
+ "name": "ops-dataset-query",
3
+ "version": "v0.0.0"
4
+ }
@@ -0,0 +1 @@
1
+ dataset_alias,dataset_name,dataset_type,dataset_category,field_name,verbose_name,field_type,data_type,is_dttm,is_restricted,expression,description,keywords
@@ -0,0 +1 @@
1
+ table_id,dataset_alias,dataset_name,dataset_type,dataset_category,from_table,database,data_source,main_dttm_col,inner_where_enabled,permission,cache_timeout,description,keywords