README.md 8.5 KB
Newer Older
M
Mars Liu 已提交
1
# skill_tree_oceanbase
M
Mars Liu 已提交
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

## 初始化

```
pip install -r requirement.txt
```


## 目录结构说明

* 技能树`骨架文件`
    * 位置:`data/tree.json` 
    * 说明:该文件是执行 `python main.py` 生成的,请勿人工编辑
* 技能树`根节点`配置文件:
    * 位置:`data/config.json`
    * 说明:可编辑配置关键词等字段,其中 `node_id` 字段是生成的,请勿编辑
* 技能树`难度节点`
M
Mars Liu 已提交
19
    * 位置:`data/xxx`,例如: `data/1.Oceanbase初阶`
M
Mars Liu 已提交
20 21 22 23
    * 说明:
        * 每个技能树有 3 个等级,目录前的序号是必要的,用来保持文件夹目录的顺序
        * 每个目录下有一个 `config.json` 可配置关键词信息,其中 `node_id` 字段是生成的,请勿编辑
* 技能树`章节点`
M
Mars Liu 已提交
24
    * 位置:`data/xxx/xxx`,例如:`data/1.OceanBase初阶/1.快速入门`
M
Mars Liu 已提交
25 26 27 28
    * 说明:
        * 每个技能树的每个难度等级有 n 个章节,目录前的序号是必要的,用来保持文件夹目录的顺序
        * 每个目录下有一个 `config.json` 可配置关键词信息,其中 `node_id` 字段是生成的,请勿编辑
* 技能树`知识节点`
M
Mars Liu 已提交
29
    * 位置:`data/xxx/xxx/xxx`,例如:`data/1.OceanBase初阶/1.快速入门/1.安装OBD`
M
Mars Liu 已提交
30 31 32 33 34 35 36 37 38 39 40
    * 说明:
        * 每个技能树的每章有 `n` 个知识节点,目录前的序号是必要的,用来保持文件夹目录的顺序
        * 每个目录下有一个 `config.json`
            * 其中 `node_id` 字段是生成的,请勿编辑
            * 其中 `keywords` 可配置关键字字段
            * 其中 `children` 可配置该`知识节点`下的子树结构信息,参考后面描述
            * 其中 `export` 可配置该`知识节点`下的导出习题信息,参考后面描述


## `知识节点` 子树信息结构

M
Mars Liu 已提交
41
例如 `data/1.OceanBase初阶/7.查询数据/config.json` 里配置对该知识节点子树信息结构:
M
Mars Liu 已提交
42 43 44 45 46 47 48 49 50 51 52 53 54
```json
    // ...

    "children": [
        // TODO ...
    ],
}
```



## `知识节点` 的导出习题编辑

M
Mars Liu 已提交
55
例如 `data/1.OceanBase初阶/7.查询数据/config.json` 里配置对该知识节点导出的习题
M
Mars Liu 已提交
56 57 58 59 60

```json
{
    // ...
    "export": [
M
Mars Liu 已提交
61
        "hello.json"
M
Mars Liu 已提交
62 63 64 65
    ]
}
```

M
Mars Liu 已提交
66
每个文件名,指向对应的习题定义 json 。
M
Mars Liu 已提交
67 68 69 70 71 72 73 74 75 76

## `知识节点` 的导出习题选项配置编辑

目前我们支持使用 markdown 语法直接编辑习题和各选项,或者编写习题代码和替换规则,让程序动态生成选项。

我们先介绍使用替换规则的习题如何编辑,在最后介绍 markdown 方式编写习题的方法。对于 Java 技能树,我们更*推荐*
使用 markdown 方式编写习题。

### 使用替换规则编写习题

M
Mars Liu 已提交
77
首先,在知识节点下增加一个习题定义文件,例如 hello.json :
M
Mars Liu 已提交
78

M
Mars Liu 已提交
79 80 81 82 83
```json
{
    "type": "code_options",
    "author": "刘鑫",
    "source": "hello.sql",
M
Mars Liu 已提交
84 85 86
}
```

M
Mars Liu 已提交
87 88 89 90 91 92 93 94 95 96 97 98 99 100
其中

 * 类型现在仅支持 `code_options` 一种,保持不变即可
 * author 是题目作者
 * source 指题目定义,题目可以是源代码 + 替换规则的形式,也可以用 markdown 编写

我们先讨论使用替换规则定义题目的方式。

例如在 `data/1.OceanBase初阶/7.查询数据` 下增加一个`hello.sql`代码文件:

```sql
select 'hello';
```

M
Mars Liu 已提交
101 102 103 104 105 106 107 108 109 110 111 112
其次,增加一个同名的选项配置文件`HelloWorld.json`,目前有三种配置规则

#### 单行替换规则

* 配置由`one_line`字段指定的单行替换字典
* 格式是:`"<源字符串>"`: [`"<替换字符串A>"`, `<替换字符串B>`,...],
    * 其中每个 `"<源字符串>"` `/` `"<替换字符串A>"` 被生成为是一个替换选项
    * 指定的配置应该能至少生成 `3+` 个替换选项

```json
{
    "one_line": {
M
Mars Liu 已提交
113
        "select": ["print", "log", "echo"]
M
Mars Liu 已提交
114 115 116 117 118 119
    }
}
```

上面的替换规则会将代码替换成 3 个变种的代码:

M
Mars Liu 已提交
120 121
```sql
print 'hello';
M
Mars Liu 已提交
122 123 124
```

```java
M
Mars Liu 已提交
125
log 'hello';
M
Mars Liu 已提交
126 127 128 129

```

```java
M
Mars Liu 已提交
130
echo 'hello';
M
Mars Liu 已提交
131 132 133 134 135 136 137 138 139 140 141
```

这些变种代码将会作为技能树该知识点该代码选择题的选项。

#### 多行替换规则

* 配置由`multiline`字段指定的多行替换数组
* 数组的每个元素是一组替换规则,会整组被替换

例如:

M
Mars Liu 已提交
142 143 144 145 146 147 148 149 150 151 152
假设我们有习题代码:

```sql
begin
    update parent set children = children + $child
    insert child(c select $child;
    commit;
end
```
和变形规则

M
Mars Liu 已提交
153 154 155
```json
{
    "mulitiline": [{
M
Mars Liu 已提交
156 157
        "begin": "{",
        "end": "}"
M
Mars Liu 已提交
158 159
    },
    { 
M
Mars Liu 已提交
160 161 162 163
        "commit": "save",
        "begin": "try{",
        "commit;": "",
        "end": "}finally{\n\tsave;\n}"
M
Mars Liu 已提交
164 165
    },
    {
M
Mars Liu 已提交
166 167 168
        "begin": "begin:",
        "commit;": "",
        "end": "finally: \tcommit;"
M
Mars Liu 已提交
169 170 171 172 173
    }]
```

上面的替换规则会将代码替换成 3 个变种的代码:

M
Mars Liu 已提交
174 175 176 177 178
```sql
{
    update parent set children = children + $child
    insert child(c select $child;
    commit;
M
Mars Liu 已提交
179 180 181
}
```

M
Mars Liu 已提交
182 183 184 185
```sql
try{
    update parent set children = children + $child
    insert child(c select $child;
M
Mars Liu 已提交
186

M
Mars Liu 已提交
187 188 189
}finally{
    save;
}
M
Mars Liu 已提交
190 191
```

M
Mars Liu 已提交
192 193 194 195 196 197 198
```sql
begin:
    update parent set children = children + $child
    insert child(c select $child;

finally:
    commit;
M
Mars Liu 已提交
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
```

这些变种代码将会作为技能树该知识点该代码选择题的选项。


#### 预制的替换规则

 * 配置由 `prepared` 字段制定的预制文件数组
 * 数组每一个元素是一个预制的代码文件的路径文件名

例如:

```json
{
    "prepared": [
M
Mars Liu 已提交
214 215 216
        "hello.1.sql",
        "hello.2.sql",
        "hello.3.sql"]
M
Mars Liu 已提交
217 218 219 220 221
}
```

同样,该配置将支持将源代码生成3个变种代码

M
Mars Liu 已提交
222 223 224 225
```sql
try{
    update parent set children = children + $child
    insert child(c select $child;
M
Mars Liu 已提交
226

M
Mars Liu 已提交
227 228
}finally{
    save;
M
Mars Liu 已提交
229 230 231
}
```

M
Mars Liu 已提交
232 233 234 235 236 237 238
```sql
begin:
    update parent set children = children + $child
    insert child(c select $child;

finally:
    commit;
M
Mars Liu 已提交
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
```

### 使用 markdown 编写习题

如前内容,我们在知识节点下增加一个习题配置,例如在 `data/1.Java初阶/1.Java概述/1.什么是Java` 下增加一个`HelloWorld.json`代码:

```json
{
    "type": "code_options",
    "author": "刘鑫",
    "source": "HelloWorld.md",
    "exercise_id":"1190bb7834904da0b1f20915960714d5",
    "notebook_enable": true
}
```
其中 type 字段目前都固定是 `code_options`。exercise_id 可以不写,处理程序会自动填补这个数据。根据具体情况写好其它字段,注意这里 source 的文件名,我们指定了一个 markdwon 文件。现在我们新建一个 HelloWorld.md 并编辑为:

````markdown
# Hello World


以下 `Hello World` 程序中,能够正确输出内容的是:

## 答案

M
Mars Liu 已提交
264
```sql
M
Mars Liu 已提交
265

M
Mars Liu 已提交
266
select 'hello';
M
Mars Liu 已提交
267 268 269 270 271 272
```

## 选项

### A

M
Mars Liu 已提交
273 274
```sql
print 'hello';
M
Mars Liu 已提交
275 276 277 278
```

### B

M
Mars Liu 已提交
279 280
```sql
echo 'hello';
M
Mars Liu 已提交
281 282 283 284
```

### C

M
Mars Liu 已提交
285 286
```sql
log 'hello';
M
Mars Liu 已提交
287 288 289 290
```

````

M
Mars Liu 已提交
291
这是一个最基本的习题结构,它包含标题、答案、选项,注意这几个一级和二级标题必须填写正确,解释器会读取这几个标题。而选项的标题会被直接忽略掉,在最终生成的习题中不包含选项的三级标题,所以这个标题可以用来标注一些编辑信息,例如“此选项没有关闭文件连接”,“类型错误”等等。
M
Mars Liu 已提交
292 293 294

### 增强信息

M
Mars Liu 已提交
295
    为了编写习题和生成 notebook 的需要,markdown 解释器支持两种模板能力,具体到 oceanbase ,现在还没有对应的 notebook 支持,所以这部分内容仅供参考,未来如果支持了 oceanbase notebook,就按照下文规范。
M
Mars Liu 已提交
296 297 298 299 300 301 302

````markdown

## aop

### before

M
Mars Liu 已提交
303 304
```sql
create table test(id integer primary key, content varchar(256));
M
Mars Liu 已提交
305 306 307 308 309
```

### after

```java
M
Mars Liu 已提交
310
drop table test;
M
Mars Liu 已提交
311 312 313 314 315 316 317 318 319 320 321
```
````

那么在创建notebook的时候,before 会插入到源代码前一个单元,after 则会插入到源代码后。aop 章节可以只包含 before 或 after 中的某一个,也可以两个都有。

另一些情况下,我们可能需要把各个选项中重复的代码提取出来,建立一个模板,此时可以在答案之前建立一个名为 template 的二级标题,例如:

````markdwon

## template

M
Mars Liu 已提交
322 323 324 325 326
```sql
begin
$code
end;

M
Mars Liu 已提交
327 328 329 330 331 332 333 334 335 336 337 338 339
```

````

注意这里的代码中,有一个 `$code` 占位符,它在管道程序处理过程中,会替换成答案和个选项内容中的代码。

在后续的数据处理流程中,markdown 会被编译为 prepared 类型的习题。

## 技能树合成

`src`目录下执行 `python main.py -a tree` 会合成技能树文件,合成的技能树文件: `data/tree.json`
* 合成过程中,会自动检查每个目录下 `config.json` 里的 `node_id` 是否存在,不存在则生成
* 合成过程中,会自动检查每个知识点目录下 `config.json` 里的 `export` 里导出的习题配置,检查是否存在`exercise_id` 字段,如果不存在则生成