Skip to content

Commit 894d07b

Browse files
🌐 Add LLM Translations (#1002)
* 💬Generate LLM translations * Update 20240721-external-dictionary.md --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Quan <[email protected]>
1 parent 3cc558c commit 894d07b

File tree

1 file changed

+205
-0
lines changed

1 file changed

+205
-0
lines changed
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
---
2+
title: 外部字典
3+
description: 本RFC提议在Databend中实现外部字典功能,以允许无缝访问来自外部数据源的数据。
4+
5+
---
6+
7+
- RFC PR: [datafuselabs/databend-docs#996](https://github.com/datafuselabs/databend-docs/pull/996)
8+
- 跟踪问题: [datafuselabs/databend#15901](https://github.com/datafuselabs/databend/issues/15901)
9+
10+
## 概要
11+
12+
实现外部字典功能允许Databend访问来自其他外部数据源的数据。
13+
14+
## 动机
15+
16+
在Databend中访问来自外部数据库(如MySQL)的数据通常需要导出MySQL数据集,然后将其导入Databend数据库。当处理大量信息时,这一过程变得繁琐,并且由于频繁更新可能导致不一致。
17+
18+
引入外部字典功能通过简化Databend与多种数据库系统之间的无缝集成,解决了这些挑战。通过字典创建,直接访问外部数据集实现了实时修改,同时简化了整体数据管理。
19+
20+
## 指南级解释
21+
22+
DICTIONARY使用以下语法进行创建、删除和查询。
23+
24+
1. 创建名为user_info的字典。
25+
26+
```sql
27+
CREATE DICTIONARY user_info(
28+
user_id UInt86,
29+
user_name String,
30+
user_address String
31+
)
32+
primary key(user_id)
33+
SOURCE(MYSQL(
34+
host '[localhost](http://localhost/)'
35+
user 'root'
36+
password 'root'
37+
db 'db_name'
38+
table 'table_name'
39+
));
40+
```
41+
42+
2. 查询现有字典。
43+
44+
```sql
45+
SHOW DICTIONARIES;
46+
```
47+
48+
3. 查询用于创建字典user_info的SQL语句。
49+
50+
```sql
51+
SHOW CREATE DICTIONARY user_info;
52+
```
53+
54+
4. 删除字典user_info。
55+
56+
```sql
57+
DROP DICTIONARY user_info;
58+
```
59+
60+
您可以使用`dict_get(dict_name, dict_field, dict_id)`从字典中查询数据。
61+
62+
`dict_get`函数接受三个参数:第一个是字典的名称,第二个是要查询的字段,第三个是查询字典的ID。
63+
64+
## 参考级解释
65+
66+
DICTIONARY的相关元数据存储在Databend的meta模块中,并在执行SQL查询时用于检索必要信息。
67+
68+
### 使用protobuf编码数据
69+
70+
Protocol Buffers(Protobuf)是一种高级数据序列化框架,为高性能计算环境提供了一系列优势。其功能包括以紧凑的二进制格式高效存储数据、快速序列化和反序列化过程、跨语言支持以及为数据结构提供定义良好的模式。因此,Databend使用Protobuf来编码数据并将二进制结果转换为数据库。
71+
72+
一个体现该技术精髓的示例Protobuf结构如下:
73+
74+
```protobuf
75+
syntax = "proto3";
76+
package databend.meta;
77+
//描述字典的元数据
78+
message DictionaryMeta {
79+
//字典名称
80+
string name = 1;
81+
//字典数据源
82+
string source = 2;
83+
//字典配置选项
84+
map<string, string> options = 3;
85+
//表的架构,如列数据类型和其他元信息。
86+
DataSchema schema = 4;
87+
//主键列的ID
88+
u32 primary_column_id = 5;
89+
}
90+
```
91+
92+
### 查询DICTIONARY的数据
93+
94+
`async_function`模块中定义`DictionaryAsyncFunction`,以实现对外部数据的异步读取。
95+
96+
```rust
97+
enum DictionarySourceEngine {
98+
MySQL,
99+
PostgreSQL,
100+
..
101+
}
102+
```
103+
104+
```rust
105+
pub struct DictionaryAsyncFunction {
106+
engine: DictionarySourceEngine,
107+
// 字典地址,例如:mysql://root:[email protected]:3306/default
108+
url: String,
109+
// 从源表获取值的SQL。
110+
// 例如:select name from user_info where id=1;
111+
query_sql: String,
112+
return_type: DataType,
113+
//指定连接数据源的最大尝试时间。
114+
connection_timeout: std::time::Duration,
115+
//指定查询操作的最大执行时间。
116+
query_timeout: std::time::Duration,
117+
//用于存储查询可能需要的附加参数,例如SQL查询中的占位符值。
118+
params: Vec<ParameterValue>,
119+
}
120+
```
121+
122+
`async_function`模块中的`AsyncFunction`重命名为`AsyncFunctionDesc`,以避免与AsyncFunction的逻辑和物理计划命名冲突。同时,包含`DictionaryAsyncFunction`。定义如下:
123+
124+
```rust
125+
pub enum AsyncFunctionDesc {
126+
SequenceAsyncFunction(SequenceAsyncFunction),
127+
DictonaryAsyncFunction(DictionaryAsyncFunction),
128+
}
129+
```
130+
131+
在逻辑和物理计划中更新`AsyncFunction`的定义,添加`AsyncFunctionDesc`字段。此过程重用现有逻辑生成字典AsyncFunction的逻辑和物理计划。
132+
133+
- 逻辑计划的结构如下:
134+
135+
```rust
136+
pub struct AsyncFunction {
137+
pub func_name: String,
138+
pub display_name: String,
139+
pub arguments: Vec<String>,
140+
pub return_type: DataType,
141+
pub index: IndexType,
142+
pub desc: AsyncFunctionDesc,//新增属性
143+
}
144+
```
145+
146+
- 物理计划的结构如下:
147+
148+
```rust
149+
pub struct AsyncFunction {
150+
pub plan_id: u32,
151+
pub func_name: String,
152+
pub display_name: String,
153+
pub arguments: Vec<String>,
154+
pub return_type: DataType,
155+
pub schema: DataSchemaRef,
156+
pub input: Box<PhysicalPlan>,
157+
pub stat_info: Option<PlanStatsInfo>,
158+
pub desc: AsyncFunctionDesc,//新增属性
159+
}
160+
```
161+
162+
在实际读取外部数据的pipeline中的`Transform`可以定义如下:
163+
164+
```rust
165+
pub struct TransformDictionary {
166+
ctx: Arc<QueryContext>,
167+
dict_func: DictionaryAsyncFunction,
168+
}
169+
```
170+
171+
实现`AsyncTransform`特性的`transform`方法,并调用外部数据库获取字典数据。主要过程如下图所示:
172+
173+
<img src="/img/rfc/20240721-external-dictionary/external-dictionary-1.png" alt="获取外部数据的流程图" style={{zoom:"80%"}} />
174+
175+
`dict_get`函数的执行过程总结如下图:
176+
177+
<img src="/img/rfc/20240721-external-dictionary/external-dictionary-2.png" alt="dict_get的流程图" style={{zoom:"80%"}} />
178+
179+
## 未解决问题
180+
181+
- 是否可以使用算法来提高数据字典查询的速度?
182+
183+
## 未来可能性
184+
185+
1. 用户可以通过外部字典连接多种类型的数据源,从同一客户端对各种数据端点进行实时操作,如文件、HTTP接口和其他数据库(如ClickHouse、Redis、MongoDB等)。
186+
187+
例如,如果数据源是本地CSV文件:
188+
189+
```sql
190+
CREATE DICTIONARY dict_name
191+
(
192+
... -- 属性
193+
)
194+
SOURCE(FILE(path './user_files/os.csv' format 'CommaSeparated')) -- 源配置
195+
```
196+
197+
2. 添加更多操作数据字典的函数,如`dict_get_or_default``dict_get_or_null``dict_has`等。
198+
199+
例如,`dict_get_or_default(dict_name, dict_field, dict_id, default_value)`包含一个额外的默认值参数,如果未找到目标数据则返回该值。
200+
201+
3. 支持使用TOML格式配置内置字典。
202+
203+
## 参考
204+
205+
[Clickhouse Dictionary](https://clickhouse.com/docs/en/dictionary)

0 commit comments

Comments
 (0)