odps_client.py 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
  1. #!/usr/bin/env python
  2. # coding=utf-8
  3. import os
  4. from odps import ODPS, options
  5. class ODPSClient(object):
  6. def __init__(self, project="loghubods"):
  7. self.accessId = os.environ.get("ODPS_ACCESS_ID")
  8. self.accessSecret = os.environ.get("ODPS_ACCESS_SECRET")
  9. if not self.accessId or not self.accessSecret:
  10. raise RuntimeError(
  11. "请设置 ODPS_ACCESS_ID 和 ODPS_ACCESS_SECRET 环境变量"
  12. )
  13. self.endpoint = os.getenv(
  14. "ODPS_ENDPOINT", "http://service.odps.aliyun.com/api"
  15. )
  16. # 调长超时,应对复杂 SQL 长时间运行(20 分钟)
  17. options.connect_timeout = 60
  18. options.read_timeout = 1200
  19. options.retry_times = 3
  20. self.odps = ODPS(
  21. self.accessId,
  22. self.accessSecret,
  23. project,
  24. self.endpoint,
  25. )
  26. def execute_sql(self, sql: str):
  27. hints = {
  28. 'odps.sql.submit.mode': 'script'
  29. }
  30. # 异步提交以便先打印 instanceId / logview,方便用户在 ODPS 控制台跟踪进度
  31. inst = self.odps.run_sql(sql, hints=hints)
  32. try:
  33. logview = inst.get_logview_address()
  34. except Exception:
  35. logview = '(获取 logview 失败)'
  36. print(f'[ODPS] InstanceId: {inst.id}', flush=True)
  37. print(f'[ODPS] LogView : {logview}', flush=True)
  38. inst.wait_for_success()
  39. with inst.open_reader(tunnel=True) as reader:
  40. pd_df = reader.to_pandas()
  41. return pd_df
  42. def execute_sql_result_save_file(self, sql: str, output_file: str):
  43. data_df = self.execute_sql(sql)
  44. data_df.to_csv(output_file, index=False)