Write data to Myscale/ClickHouse table. data: pd.DataFrame or List[dict],每行是data字段内容(dict)。
(self, data: Any)
| 387 | raise ValueError(f"Unsupported output type: {output_type}") |
| 388 | |
| 389 | def write(self, data: Any) -> Any: |
| 390 | """ |
| 391 | Write data to Myscale/ClickHouse table. |
| 392 | data: pd.DataFrame or List[dict],每行是data字段内容(dict)。 |
| 393 | """ |
| 394 | if isinstance(data, list): |
| 395 | df = pd.DataFrame(data) |
| 396 | elif isinstance(data, pd.DataFrame): |
| 397 | df = data |
| 398 | else: |
| 399 | raise ValueError(f"Unsupported data type: {type(data)}") |
| 400 | # data字段本身就是每行的内容 |
| 401 | if 'data' not in df.columns: |
| 402 | # 兼容直接传入dict列表的情况 |
| 403 | df['data'] = df.apply(lambda row: row.to_dict(), axis=1) |
| 404 | # 统一处理data列 |
| 405 | df['data'] = df['data'].apply(lambda x: x if isinstance(x, dict) else (json.loads(x) if isinstance(x, str) else {})) |
| 406 | # 自动填充pipeline_id, task_id, raw_data_id, min_hashes |
| 407 | df['pipeline_id'] = self.pipeline_id |
| 408 | df['task_id'] = self.output_task_id |
| 409 | df['raw_data_id'] = df['data'].apply(lambda d: d.get(SYS_FIELD_PREFIX + 'raw_data_id', 0) if isinstance(d, dict) else 0) |
| 410 | df['min_hashes'] = df['data'].apply(lambda d: _default_min_hashes(d) if isinstance(d, dict) else [0]) |
| 411 | # data字段转为JSON字符串 |
| 412 | df['data'] = df['data'].apply(lambda x: json.dumps(x, ensure_ascii=False) if not isinstance(x, str) else x) |
| 413 | # 只保留必需字段 |
| 414 | required_cols = ['pipeline_id', 'task_id', 'raw_data_id', 'min_hashes', 'data'] |
| 415 | df = df[required_cols] |
| 416 | records = df.to_dict(orient="records") |
| 417 | values = [ |
| 418 | ( |
| 419 | rec['pipeline_id'], |
| 420 | rec['task_id'], |
| 421 | int(rec['raw_data_id']), |
| 422 | rec['min_hashes'], |
| 423 | rec['data'] |
| 424 | ) for rec in records |
| 425 | ] |
| 426 | insert_sql = f""" |
| 427 | INSERT INTO {self.table} (pipeline_id, task_id, raw_data_id, min_hashes, data) |
| 428 | VALUES |
| 429 | """ |
| 430 | self.logger.info(f"Inserting {len(values)} rows into {self.table}") |
| 431 | self.client.execute(insert_sql, values) |
| 432 | return f"Inserted {len(values)} rows into {self.table}" |
nothing calls this directly
no test coverage detected