本文目录导读:

我来详细说明如何用Python生成Impala表配置(包括建表语句和Hive元数据配置)。
生成Impala建表语句
基础建表语句生成
def generate_create_table_sql(table_name, columns, partition_cols=None,
storage_format='PARQUET', location=None):
"""
生成Impala建表SQL语句
Args:
table_name: 表名(可包含数据库名)
columns: 列定义列表 [('col1', 'STRING', 'comment1'), ...]
partition_cols: 分区列 [('dt', 'STRING'), ...]
storage_format: 存储格式
location: HDFS路径
"""
# 列定义
col_defs = []
for col in columns:
col_name = col[0]
col_type = col[1]
col_comment = col[2] if len(col) > 2 else ''
if col_comment:
col_defs.append(f" `{col_name}` {col_type} COMMENT '{col_comment}'")
else:
col_defs.append(f" `{col_name}` {col_type}")
# 分区定义
part_defs = ""
if partition_cols:
part_strs = [f" `{p[0]}` {p[1]}" for p in partition_cols]
part_defs = f"PARTITIONED BY (\n" + ",\n".join(part_strs) + "\n)"
# 存储格式
if storage_format.upper() == 'PARQUET':
storage_clause = "STORED AS PARQUET"
elif storage_format.upper() == 'TEXTFILE':
storage_clause = "ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' STORED AS TEXTFILE"
elif storage_format.upper() == 'ORC':
storage_clause = "STORED AS ORC"
else:
storage_clause = f"STORED AS {storage_format}"
# HDFS路径
location_clause = f"LOCATION '{location}'" if location else ""
# 组合SQL
sql = f"""
CREATE EXTERNAL TABLE IF NOT EXISTS {table_name} (
{",\n".join(col_defs)}
)
{part_defs}
{storage_clause}
{location_clause}
TBLPROPERTIES (
'impala.table.statistics.enabled'='true',
'impala.enable.orc.schema.evolution'='false'
);
"""
return sql.strip()
# 使用示例
columns = [
('id', 'BIGINT', '用户ID'),
('name', 'STRING', '用户名'),
('age', 'INT', '年龄'),
('amount', 'DECIMAL(10,2)', '金额')
]
partition_cols = [('dt', 'STRING'), ('city', 'STRING')]
sql = generate_create_table_sql(
'db_name.user_info',
columns=columns,
partition_cols=partition_cols,
storage_format='PARQUET',
location='/user/hive/warehouse/db_name.db/user_info'
)
print(sql)
从配置文件生成建表语句
import json
import yaml
import configparser
class ImpalaTableConfigGenerator:
"""Impala表配置生成器"""
def __init__(self, config_file):
self.config = self._load_config(config_file)
def _load_config(self, config_file):
"""加载配置文件"""
if config_file.endswith('.json'):
with open(config_file, 'r') as f:
return json.load(f)
elif config_file.endswith('.yaml') or config_file.endswith('.yml'):
with open(config_file, 'r') as f:
return yaml.safe_load(f)
else:
raise ValueError("Unsupported config file format")
def generate_ddl(self, table_name=None):
"""生成DDL语句"""
table_config = self.config.get(table_name, self.config)
columns = []
for col in table_config['columns']:
col_tuple = (
col['name'],
col['type'],
col.get('comment', '')
)
columns.append(col_tuple)
partition_cols = [
(p['name'], p['type'])
for p in table_config.get('partition_columns', [])
]
return generate_create_table_sql(
table_name or table_config['table_name'],
columns,
partition_cols=partition_cols,
storage_format=table_config.get('storage_format', 'PARQUET'),
location=table_config.get('location', None)
)
def generate_all_ddls(self, output_file=None):
"""生成所有表的DDL"""
ddls = []
for table_name in self.config:
if isinstance(self.config[table_name], dict) and 'columns' in self.config[table_name]:
ddl = self.generate_ddl(table_name)
ddls.append(ddl)
if output_file:
with open(output_file, 'w') as f:
f.write('\n\n'.join(ddls))
return '\n\n'.join(ddls)
# YAML配置示例(table_config.yaml)
yaml_config = """
user_info:
columns:
- name: id
type: BIGINT
comment: 用户ID
- name: name
type: STRING
comment: 用户名
- name: age
type: INT
comment: 年龄
partition_columns:
- name: dt
type: STRING
storage_format: PARQUET
location: /user/hive/warehouse/test.db/user_info
order_info:
columns:
- name: order_id
type: STRING
comment: 订单ID
- name: user_id
type: BIGINT
comment: 用户ID
- name: amount
type: DECIMAL(10,2)
comment: 订单金额
- name: status
type: STRING
comment: 订单状态
partition_columns:
- name: dt
type: STRING
storage_format: PARQUET
"""
# 使用
with open('table_config.yaml', 'w') as f:
f.write(yaml_config)
generator = ImpalaTableConfigGenerator('table_config.yaml')
all_ddls = generator.generate_all_ddls('all_tables.sql')
print(all_ddls)
从数据库元数据生成
import pymysql
from sqlalchemy import create_engine, MetaData, Table
def generate_from_mysql(mysql_conn, database, table_name):
"""从MySQL表结构生成Impala建表语句"""
# 类型映射
type_mapping = {
'int': 'INT',
'bigint': 'BIGINT',
'varchar': 'STRING',
'char': 'STRING',
'text': 'STRING',
'decimal': 'DECIMAL',
'float': 'FLOAT',
'double': 'DOUBLE',
'datetime': 'TIMESTAMP',
'timestamp': 'TIMESTAMP',
'date': 'DATE',
'tinyint': 'TINYINT',
'smallint': 'SMALLINT',
}
# 连接到MySQL
conn = pymysql.connect(**mysql_conn)
cursor = conn.cursor()
# 获取表结构
cursor.execute(f"DESCRIBE {database}.{table_name}")
columns_info = cursor.fetchall()
# 获取注释
cursor.execute(f"""
SELECT COLUMN_NAME, COLUMN_COMMENT
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = '{database}' AND TABLE_NAME = '{table_name}'
""")
comments = dict(cursor.fetchall())
columns = []
for col_info in columns_info:
col_name = col_info[0]
mysql_type = col_info[1]
# 转换类型
impala_type = type_mapping.get(
mysql_type.split('(')[0].lower(),
'STRING'
)
# 保留精度
if 'decimal' in mysql_type.lower():
impala_type = mysql_type.upper()
comment = comments.get(col_name, '')
columns.append((col_name, impala_type, comment))
cursor.close()
conn.close()
return generate_create_table_sql(
f"{database}.{table_name}",
columns,
storage_format='PARQUET'
)
# 使用示例
mysql_config = {
'host': 'localhost',
'user': 'root',
'password': 'password',
'port': 3306
}
impala_ddl = generate_from_mysql(mysql_config, 'source_db', 'users')
print(impala_ddl)
从CSV文件生成
import csv
def generate_from_csv(csv_file_path, table_name, delimiter=','):
"""从CSV文件头生成Impala建表语句"""
# 读取CSV头部
with open(csv_file_path, 'r') as f:
reader = csv.reader(f, delimiter=delimiter)
headers = next(reader)
# 推断数据类型(简化版)
type_guesses = []
with open(csv_file_path, 'r') as f:
reader = csv.DictReader(f, delimiter=delimiter)
for row_num, row in enumerate(reader):
if row_num >= 100: # 只检查前100行
break
for i, header in enumerate(headers):
if len(type_guesses) <= i:
type_guesses.append({'INT': True, 'FLOAT': True, 'STRING': False})
value = row[header].strip()
if value:
# 尝试推断类型
try:
int(value)
except ValueError:
type_guesses[i]['INT'] = False
try:
float(value)
except ValueError:
type_guesses[i]['FLOAT'] = False
# 确定最终类型
columns = []
for i, header in enumerate(headers):
if type_guesses[i]['INT']:
col_type = 'INT'
elif type_guesses[i]['FLOAT']:
col_type = 'DECIMAL(20,10)'
else:
col_type = 'STRING'
columns.append((header, col_type, ''))
return generate_create_table_sql(table_name, columns, storage_format='PARQUET')
# 使用示例
csv_ddl = generate_from_csv('data.csv', 'csv_table')
print(csv_ddl)
生成表配置JSON
def generate_table_config(table_name, table_metadata):
"""生成表配置JSON"""
config = {
'table_name': table_name,
'database': table_metadata.get('database', 'default'),
'columns': [],
'partition_columns': [],
'properties': {
'format': table_metadata.get('format', 'PARQUET'),
'compression': table_metadata.get('compression', 'SNAPPY'),
'location': table_metadata.get('location', ''),
'row_format': table_metadata.get('row_format', ''),
'serde': table_metadata.get('serde', ''),
},
'statistics': {
'num_rows': table_metadata.get('num_rows', 0),
'total_size': table_metadata.get('total_size', 0),
},
'tblproperties': {
'impala.table.statistics.enabled': 'true',
'transient_lastDdlTime': str(int(time.time())),
}
}
for col in table_metadata.get('columns', []):
config['columns'].append({
'name': col['name'],
'type': col['type'],
'comment': col.get('comment', ''),
'nullable': col.get('nullable', True),
'default': col.get('default', None),
'statistics': {
'num_distinct': col.get('ndv', 0),
'num_nulls': col.get('num_nulls', 0),
}
})
for part in table_metadata.get('partition_columns', []):
config['partition_columns'].append({
'name': part['name'],
'type': part['type'],
'position': part.get('position', 0),
})
return config
# 使用示例
import time
test_metadata = {
'database': 'analytics',
'format': 'PARQUET',
'compression': 'SNAPPY',
'location': '/user/hive/warehouse/analytics.db/events',
'columns': [
{'name': 'event_id', 'type': 'STRING', 'comment': '事件ID', 'ndv': 1000000},
{'name': 'user_id', 'type': 'BIGINT', 'comment': '用户ID', 'ndv': 500000},
{'name': 'event_time', 'type': 'TIMESTAMP', 'comment': '事件时间'},
{'name': 'event_type', 'type': 'STRING', 'comment': '事件类型', 'ndv': 50},
],
'partition_columns': [
{'name': 'dt', 'type': 'STRING', 'position': 1},
{'name': 'hour', 'type': 'STRING', 'position': 2},
],
'num_rows': 10000000,
'total_size': 2147483648,
}
config = generate_table_config('events', test_metadata)
print(json.dumps(config, indent=2, ensure_ascii=False))
完整工具类
class ImpalaTableManager:
"""Impala表管理工具类"""
def __init__(self, impala_host='localhost', impala_port=21050):
self.host = impala_host
self.port = impala_port
def generate_ddl_from_spec(self, spec):
"""从表规范生成DDL"""
return generate_create_table_sql(
f"{spec['database']}.{spec['table_name']}",
spec['columns'],
partition_cols=spec.get('partition_columns', []),
storage_format=spec.get('storage_format', 'PARQUET'),
location=spec.get('location', '')
)
def execute_ddl(self, ddl):
"""执行DDL语句"""
from impala.dbapi import connect
conn = connect(host=self.host, port=self.port)
cursor = conn.cursor()
try:
cursor.execute(ddl)
conn.commit()
print(f"Successfully executed DDL")
except Exception as e:
print(f"Error executing DDL: {e}")
conn.rollback()
finally:
cursor.close()
conn.close()
def save_config(self, table_name, config, output_file):
"""保存表配置"""
if output_file.endswith('.json'):
with open(output_file, 'w') as f:
json.dump(config, f, indent=2, ensure_ascii=False)
elif output_file.endswith('.yaml'):
with open(output_file, 'w') as f:
yaml.dump(config, f, default_flow_style=False)
# 完整使用示例
manager = ImpalaTableManager()
# 生成DDL
spec = {
'database': 'test_db',
'table_name': 'user_behavior',
'columns': [
('user_id', 'BIGINT', '用户ID'),
('behavior', 'STRING', '行为类型'),
],
'partition_columns': [('dt', 'STRING')],
'storage_format': 'PARQUET'
}
ddl = manager.generate_ddl_from_spec(spec)
print("Generated DDL:")
print(ddl)
这些方法可以根据你的具体需求灵活调整,支持从各种数据源生成Impala表配置和DDL语句。