我有一个不断填充新数据的S3存储桶,我使用Athena和Glue来查询数据,问题是如果胶水不知道创建了一个新分区它不会搜索它需要在那里搜索。如果我每次需要新分区时都要进行API调用来运行Glue爬虫,那么最好的解决办法是告诉胶水添加一个新分区,即在其属性表中创建一个新分区。我查看了AWS文档,但没有运气,我正在使用Java与AWS。有什么帮助吗?
答案 0 :(得分:4)
您可能要使用batch_create_partition()胶水api注册新分区。它不需要任何昂贵的操作,例如MSCK REPAIR TABLE或重新爬网。
我有一个类似的用例,为此我编写了一个执行以下操作的python脚本-
步骤1-获取表信息并从中解析注册分区所需的必要信息。
# Fetching table information from glue catalog
logger.info("Fetching table info for {}.{}".format(l_database, l_table))
try:
response = l_client.get_table(
CatalogId=l_catalog_id,
DatabaseName=l_database,
Name=l_table
)
except Exception as error:
logger.error("Exception while fetching table info for {}.{} - {}"
.format(l_database, l_table, error))
sys.exit(-1)
# Parsing table info required to create partitions from table
input_format = response['Table']['StorageDescriptor']['InputFormat']
output_format = response['Table']['StorageDescriptor']['OutputFormat']
table_location = response['Table']['StorageDescriptor']['Location']
serde_info = response['Table']['StorageDescriptor']['SerdeInfo']
partition_keys = response['Table']['PartitionKeys']
步骤2-生成列表字典,其中每个列表都包含创建单个分区的信息。所有列表将具有相同的结构,但其分区特定值将更改(年,月,日,小时)
def generate_partition_input_list(start_date, num_of_days, table_location,
input_format, output_format, serde_info):
input_list = [] # Initializing empty list
today = datetime.utcnow().date()
if start_date > today: # To handle scenarios if any future partitions are created manually
start_date = today
end_date = today + timedelta(days=num_of_days) # Getting end date till which partitions needs to be created
logger.info("Partitions to be created from {} to {}".format(start_date, end_date))
for input_date in date_range(start_date, end_date):
# Formatting partition values by padding required zeroes and converting into string
year = str(input_date)[0:4].zfill(4)
month = str(input_date)[5:7].zfill(2)
day = str(input_date)[8:10].zfill(2)
for hour in range(24): # Looping over 24 hours to generate partition input for 24 hours for a day
hour = str('{:02d}'.format(hour)) # Padding zero to make sure that hour is in two digits
part_location = "{}{}/{}/{}/{}/".format(table_location, year, month, day, hour)
input_dict = {
'Values': [
year, month, day, hour
],
'StorageDescriptor': {
'Location': part_location,
'InputFormat': input_format,
'OutputFormat': output_format,
'SerdeInfo': serde_info
}
}
input_list.append(input_dict.copy())
return input_list
第3步-调用batch_create_partition()API
for each_input in break_list_into_chunks(partition_input_list, 100):
create_partition_response = client.batch_create_partition(
CatalogId=catalog_id,
DatabaseName=l_database,
TableName=l_table,
PartitionInputList=each_input
)
单个api调用中限制有100个分区,因此,如果要创建100个以上的分区,则需要将列表分成多个块并对其进行迭代。
答案 1 :(得分:1)
您可以创建一个lambda函数,该函数将按计划运行,或者将由您的存储桶中的事件触发(例如.putObject事件),该函数可以调用athena来发现分区:
import boto3
athena = boto3.client('athena')
def lambda_handler(event, context):
athena.start_query_execution(
QueryString = "MSCK REPAIR TABLE mytable",
ResultConfiguration = {
'OutputLocation': "s3://some-bucket/_athena_results"
}
使用Athena手动添加分区。您也可以通过API运行SQL查询,就像在我的lambda示例中一样。
来自Athena manual的示例:
ALTER TABLE orders ADD
PARTITION (dt = '2016-05-14', country = 'IN') LOCATION 's3://mystorage/path/to/INDIA_14_May_2016'
PARTITION (dt = '2016-05-15', country = 'IN') LOCATION 's3://mystorage/path/to/INDIA_15_May_2016';
答案 2 :(得分:0)
这个问题很旧,但我想指出的是,有人可以通过OnSadListener listener
通知触发Lambda函数,该函数会在数据到达S3时注册新分区。我什至会扩展此功能以处理基于对象删除等的弃用。这是AWS的博客文章,其中详细介绍了S3事件通知:https://aws.amazon.com/blogs/aws/s3-event-notification/
答案 3 :(得分:0)
AWS Glue最近添加了一个RecrawlPolicy,它仅对您添加到S3存储桶中的新文件夹/分区进行爬网。
https://docs.aws.amazon.com/glue/latest/dg/incremental-crawls.html
这应该有助于您最大程度地减少再次再次爬网所有数据。据我了解,您可以在设置搜寻器或编辑现有的搜寻器时定义增量搜寻。但是要注意的一件事是,增量爬网要求新数据的架构与现有架构大致相同。