Source code for operators.iceberg.drop_iceberg_partition
from airflow.utils.decorators import apply_defaults
from typing import Dict, Optional, Any, Union
from operators.iceberg.base_iceberg_table import BaseIcebergTableOperator
from operators.iceberg.maintain_iceberg_table import MaintainIcebergTableOperator
[docs]
class DropIcebergPartitionOperator(BaseIcebergTableOperator):
"""
Drops a partition from an Iceberg table and optionally runs maintenance afterward.
This operator deletes data from a specific partition using a WHERE clause and
can trigger maintenance operations after the deletion.
The DropIcebergPartitionOperator inherits from BaseIcebergTableOperator, so by default it will already verify the table exists during the pre_execute phase. Since your verify_exists parameter is set to True by default in the base operator, all derived operators will perform this check unless explicitly disabled.
:param table_name: The Iceberg table name
:type table_name: str
:param partition_col: The partition column name
:type partition_col: str
:param partition_value: The partition value to drop
:type partition_value: str, int, or float
:param database: The database containing the table
:type database: str
:param additional_filter: Additional WHERE conditions (without 'AND')
:type additional_filter: str
:param run_maintenance: Whether to run maintenance after dropping the partition
:type run_maintenance: bool
:param maintenance_options: Optional parameters for maintenance operation
:type maintenance_options: dict
"""
template_fields = BaseIcebergTableOperator.template_fields + [
"partition_col",
"partition_value",
"additional_filter",
]
ui_color = "#FADBD8" # Light Red/Pink shade
@apply_defaults
def __init__(
self,
table_name: str,
partition_col: str,
partition_value: Union[str, int, float],
database: Optional[str] = None,
additional_filter: Optional[str] = None,
run_maintenance: bool = True,
maintenance_options: Optional[Dict[str, Any]] = None,
*args,
**kwargs,
):
super().__init__(table_name=table_name, database=database, *args, **kwargs)
self.partition_col = partition_col
self.partition_value = partition_value
self.additional_filter = additional_filter
self.run_maintenance = run_maintenance
self.maintenance_options = maintenance_options or {}
[docs]
def execute(self, context: Dict) -> Dict[str, Any]:
"""
Execute the partition drop operation.
:param context: Airflow context
:type context: Dict
"""
# Build the WHERE clause
where_clause = self._build_partition_filter()
# Execute the DELETE operation
sql = f"DELETE FROM {self.database}.{self.table_name} WHERE {where_clause}"
self.log.info(f"Dropping partition data with: {sql}")
self._execute_athena_query(sql=sql)
self.log.info(f"Successfully dropped data from partition where {where_clause}")
# Run maintenance if requested
if self.run_maintenance:
self.log.info(f"Running maintenance on table after partition drop")
maintenance_op = MaintainIcebergTableOperator(
task_id=f"maintenance_after_partition_drop",
table_name=self.table_name,
database=self.database,
**self.maintenance_options,
)
# Execute the maintenance operation directly
maintenance_op.execute(context)
def _build_partition_filter(self) -> str:
"""
Build the WHERE clause filter for the partition drop operation.
:return: SQL WHERE clause condition (without the WHERE keyword)
:rtype: str
"""
# Handle different value types appropriately
if isinstance(self.partition_value, str):
partition_condition = f"{self.partition_col}='{self.partition_value}'"
else:
partition_condition = f"{self.partition_col}={self.partition_value}"
# Add any additional WHERE conditions if provided
if self.additional_filter:
return f"({partition_condition}) AND ({self.additional_filter})"
return partition_condition