from datetime import datetime, timezone from flask import current_app from databricks import sql class DatabricksQuery: def __init__(self): """纯Python连接Databricks SQL,无JVM依赖""" try: # 读取配置(参数和原代码一致,无需修改) self.host = current_app.config["DATABRICKS_HOST"] self.token = current_app.config["DATABRICKS_TOKEN"] self.cluster_id = current_app.config["CLUSTER_ID"] # 校验参数 if not all([self.host, self.token, self.cluster_id]): raise ValueError( "必须配置DATABRICKS_HOST、DATABRICKS_TOKEN、CLUSTER_ID" ) print("Databricks SQL 连接器初始化成功") except Exception as e: print(f"初始化失败: {e}") raise # 复用原有参数校验逻辑 @staticmethod def _validate_table_name(table_name): if not table_name or not isinstance(table_name, str): raise ValueError(f"无效的表名: {table_name}") if ";" in table_name: raise ValueError(f"表名包含非法字符 ';': {table_name}") parts = table_name.split(".") if len(parts) != 3: raise ValueError(f"表名格式应为 catalog.schema.table: {table_name}") @staticmethod def _validate_vin(vin): if vin is None: return True if not isinstance(vin, str): raise ValueError(f"无效的 VIN: {vin} (必须是17位字母数字)") return True def query_table( self, table_name, vin=None, start_time=None, end_time=None,limit=None ): """纯Python查询表数据,无JVM依赖""" try: # 验证参数 self._validate_table_name(table_name) self._validate_vin(vin) # 构建SQL查询语句(替代原PySpark DataFrame操作) select_fields = """ Incident__Name AS incident_name, Incident__description AS incident_description, Meaning AS meaning, Signal__Name As signal_name, incident_time, oneid, speed, int_value, idc_tickcount_ms, latitude, longitude, mux_data, gps_heading, float_value """ sql_query = f"SELECT {select_fields} FROM {table_name}" where_conditions = [] # 拼接过滤条件 if vin: where_conditions.append(f"oneid = '{vin}'") if start_time: start_dt = self._parse_iso_time(start_time).isoformat() where_conditions.append(f"incident_time >= '{start_dt}'") if end_time: end_dt = self._parse_iso_time(end_time).isoformat() where_conditions.append(f"incident_time <= '{end_dt}'") # 拼接WHERE子句 if where_conditions: sql_query += " WHERE " + " AND ".join(where_conditions) # 拼接LIMIT if limit is not None: sql_query += f" LIMIT {limit}" # sql_query="select * from hive_metastore.taf_level_two_plus.accident_report_data WHERE oneid = 'LE4LG4GB6SL256937' limit 1" print(f"查询sql:{sql_query}") # 执行SQL(纯Python,无JVM) with sql.connect( server_hostname=self.host, http_path=f"sql/protocolv1/o/3035612432650494/{self.cluster_id}", # 注意路径格式 access_token=self.token, ) as connection: with connection.cursor() as cursor: cursor.execute(sql_query) # 获取列名和数据,转换为字典格式(和原代码返回格式一致) columns = [desc[0] for desc in cursor.description] results = [] for row in cursor.fetchall(): results.append(dict(zip(columns, row))) return results except Exception as e: print(f"查询失败: {str(e)}") raise # 复用原有时间解析逻辑 def _parse_iso_time(self, time_str): try: if time_str.endswith("Z"): time_str = time_str[:-1] + "+00:00" dt = datetime.fromisoformat(time_str) if dt.tzinfo is None: dt = dt.replace(tzinfo=timezone.utc) return dt except Exception as e: raise ValueError(f"无效的时间格式 '{time_str}': {str(e)}") def stop(self): # 纯Python连接器无需关闭SparkSession,此处保留方法以兼容原有调用逻辑 print("Databricks SQL 连接已释放")