|
| 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