cố gắng tạo các chuỗi con động từ dag cha dựa trên mảng tên tệp


10

Tôi đang cố gắng di chuyển các tệp s3 từ nhóm "không xóa" (có nghĩa là tôi không thể xóa các tệp) sang GCS bằng luồng khí. Tôi không thể đảm bảo rằng các tệp mới sẽ ở đó hàng ngày, nhưng tôi phải kiểm tra các tệp mới hàng ngày.

vấn đề của tôi là sự sáng tạo năng động của subags. Nếu có tệp IS, tôi cần subags. Nếu không có tập tin nào, tôi không cần subags. Vấn đề của tôi là cài đặt ngược dòng / hạ lưu. Trong mã của tôi, nó phát hiện các tệp, nhưng không khởi động các tệp con như chúng được yêu cầu. Tôi đang thiếu một cái gì đó.

đây là mã của tôi:

from airflow import models
from  airflow.utils.helpers import chain
from airflow.providers.amazon.aws.hooks.s3 import S3Hook
from airflow.operators.python_operator import PythonOperator, BranchPythonOperator
from airflow.operators.dummy_operator import DummyOperator
from airflow.operators.subdag_operator import SubDagOperator
from airflow.contrib.operators.s3_to_gcs_operator import S3ToGoogleCloudStorageOperator
from airflow.utils import dates
from airflow.models import Variable
import logging

args = {
    'owner': 'Airflow',
    'start_date': dates.days_ago(1),
    'email': ['sinistersparrow1701@gmail.com'],
    'email_on_failure': True,
    'email_on_success': True,
}

bucket = 'mybucket'
prefix = 'myprefix/'
LastBDEXDate = int(Variable.get("last_publish_date"))
maxdate = LastBDEXDate
files = []

parent_dag = models.DAG(
    dag_id='My_Ingestion',
    default_args=args,
    schedule_interval='@daily',
    catchup=False
)

def Check_For_Files(**kwargs):
    s3 = S3Hook(aws_conn_id='S3_BOX')
    s3.get_conn()
    bucket = bucket
    LastBDEXDate = int(Variable.get("last_publish_date"))
    maxdate = LastBDEXDate
    files = s3.list_keys(bucket_name=bucket, prefix='myprefix/file')
    for file in files:
        print(file)
        print(file.split("_")[-2])
        print(file.split("_")[-2][-8:])  ##proves I can see a date in the file name is ok.
        maxdate = maxdate if maxdate > int(file.split("_")[-2][-8:]) else int(file.split("_")[-2][-8:])
    if maxdate > LastBDEXDate:
        return 'Start_Process'
    return 'finished'

def create_subdag(dag_parent, dag_id_child_prefix, file_name):
    # dag params
    dag_id_child = '%s.%s' % (dag_parent.dag_id, dag_id_child_prefix)

    # dag
    subdag = models.DAG(dag_id=dag_id_child,
              default_args=args,
              schedule_interval=None)

    # operators
    s3_to_gcs_op = S3ToGoogleCloudStorageOperator(
        task_id=dag_id_child,
        bucket=bucket,
        prefix=file_name,
        dest_gcs_conn_id='GCP_Account',
        dest_gcs='gs://my_files/To_Process/',
        replace=False,
        gzip=True,
        dag=subdag)


    return subdag

def create_subdag_operator(dag_parent, filename, index):
    tid_subdag = 'file_{}'.format(index)
    subdag = create_subdag(dag_parent, tid_subdag, filename)
    sd_op = SubDagOperator(task_id=tid_subdag, dag=dag_parent, subdag=subdag)
    return sd_op

def create_subdag_operators(dag_parent, file_list):
    subdags = [create_subdag_operator(dag_parent, file, file_list.index(file)) for file in file_list]
    # chain subdag-operators together
    chain(*subdags)
    return subdags

check_for_files = BranchPythonOperator(
    task_id='Check_for_s3_Files',
    provide_context=True,
    python_callable=Check_For_Files,
    dag=parent_dag
)

finished = DummyOperator(
    task_id='finished',
    dag=parent_dag
)

decision_to_continue = DummyOperator(
    task_id='Start_Process',
    dag=parent_dag
)

if len(files) > 0:
    subdag_ops = create_subdag_operators(parent_dag, files)
    check_for_files >> decision_to_continue >> subdag_ops[0] >> subdag_ops[-1] >> finished


check_for_files >> finished

Những loại công việc nào chạy ở phần cuối của các DAGS này là những sparkcông việc hoặc một số pythontập lệnh và bạn đang sử dụng để chạy nó như thế nào livyhoặc một phương pháp nào khác
ashwin agrawal

Tôi xin lỗi, tôi không hiểu câu hỏi. bạn có thể vui lòng nghỉ ngơi không?
arcee123

Tôi có nghĩa là bạn chỉ sử dụng các kịch bản python đơn giản và không sử dụng bất kỳ công việc tia lửa nào phải không?
ashwin agrawal

Đúng. toán tử đơn giản được mặc định trong luồng không khí. Tôi muốn thêm các toán tử hiện có ở tốc độ động dựa trên các tệp được gắn cờ trong S3 Tôi muốn nhập vào GCS.
arcee123

Tại sao filesmột danh sách trống?
Oluwafemi Sule

Câu trả lời:


3

Dưới đây là cách được đề xuất để tạo DAG động hoặc DAG phụ trong luồng khí, mặc dù cũng có những cách khác, nhưng tôi đoán điều này sẽ được áp dụng chủ yếu cho vấn đề của bạn.

Đầu tiên, tạo một tệp (yaml/csv)bao gồm danh sách tất cả s3các tệp và vị trí, trong trường hợp của bạn, bạn đã viết một hàm để lưu trữ chúng trong danh sách, tôi sẽ nói lưu trữ chúng trong một yamltệp riêng biệt và tải nó trong thời gian chạy trong luồng khí env và sau đó tạo DAGs.

Dưới đây là một yamltệp mẫu : dynamicDagConfigFile.yaml

job: dynamic-dag
bucket_name: 'bucket-name'
prefix: 'bucket-prefix'
S3Files:
    - File1: 'S3Loc1'
    - File2: 'S3Loc2'
    - File3: 'S3Loc3'

Bạn có thể sửa đổi Check_For_Fileschức năng của mình để lưu trữ chúng trong một yamltệp.

Bây giờ chúng ta có thể chuyển sang tạo dag động:

Đầu tiên xác định hai tác vụ bằng cách sử dụng các toán tử giả, bắt đầu và tác vụ kết thúc. Những nhiệm vụ như vậy là những nhiệm vụ mà chúng ta sẽ xây dựng dựa trên chúng ta DAGbằng cách tự động tạo ra các nhiệm vụ giữa chúng:

start = DummyOperator(
    task_id='start',
    dag=dag
)

end = DummyOperator(
    task_id='end',
    dag=dag)

Dynamic DAG: Chúng tôi sẽ sử dụng PythonOperatorstrong luồng không khí. Hàm sẽ nhận làm đối số id tác vụ; một hàm python sẽ được thực thi, tức là python_callable cho toán tử Python; và một tập hợp các đối số sẽ được sử dụng trong quá trình thực thi.

Bao gồm một đối số task id. Vì vậy, chúng ta có thể trao đổi dữ liệu giữa các tác vụ được tạo theo cách động, ví dụ: thông qua XCOM.

Bạn có thể chỉ định chức năng hoạt động của bạn trong dag động này như thế nào s3_to_gcs_op.

def createDynamicDAG(task_id, callableFunction, args):
    task = PythonOperator(
        task_id = task_id,
        provide_context=True,
        #Eval is used since the callableFunction var is of type string
        #while the python_callable argument for PythonOperators only receives objects of type callable not strings.
        python_callable = eval(callableFunction),
        op_kwargs = args,
        xcom_push = True,
        dag = dag,
    )
    return task

Cuối cùng, dựa trên vị trí có trong tệp yaml, bạn có thể tạo các dags động, trước tiên hãy đọc yamltệp như bên dưới và tạo dag động:

with open('/usr/local/airflow/dags/config_files/dynamicDagConfigFile.yaml') as f:
    # use safe_load instead to load the YAML file
    configFile = yaml.safe_load(f)

    #Extract file list
    S3Files = configFile['S3Files']

    #In this loop tasks are created for each table defined in the YAML file
    for S3File in S3Files:
        for S3File, fieldName in S3File.items():

            #Remember task id is provided in order to exchange data among tasks generated in dynamic way.
            get_s3_files = createDynamicDAG('{}-getS3Data'.format(S3File), 
                                            'getS3Data', 
                                            {}) #your configs here.

            #Second step is upload S3 to GCS
            upload_s3_toGCS = createDynamicDAG('{}-uploadDataS3ToGCS'.format(S3File), 'uploadDataS3ToGCS', {'previous_task_id':'{}-'})

#write your configs again here like S3 bucket name prefix extra or read from yaml file, and other GCS config.

Định nghĩa DAG cuối cùng:

Ý tưởng là

#once tasks are generated they should linked with the
#dummy operators generated in the start and end tasks. 
start >> get_s3_files
get_s3_files >> upload_s3_toGCS
upload_s3_toGCS >> end

Mã luồng khí đầy đủ theo thứ tự:

import yaml
import airflow
from airflow import DAG
from datetime import datetime, timedelta, time
from airflow.operators.python_operator import PythonOperator
from airflow.operators.dummy_operator import DummyOperator

start = DummyOperator(
    task_id='start',
    dag=dag
)


def createDynamicDAG(task_id, callableFunction, args):
    task = PythonOperator(
        task_id = task_id,
        provide_context=True,
        #Eval is used since the callableFunction var is of type string
        #while the python_callable argument for PythonOperators only receives objects of type callable not strings.
        python_callable = eval(callableFunction),
        op_kwargs = args,
        xcom_push = True,
        dag = dag,
    )
    return task


end = DummyOperator(
    task_id='end',
    dag=dag)



with open('/usr/local/airflow/dags/config_files/dynamicDagConfigFile.yaml') as f:
    configFile = yaml.safe_load(f)

    #Extract file list
    S3Files = configFile['S3Files']

    #In this loop tasks are created for each table defined in the YAML file
    for S3File in S3Files:
        for S3File, fieldName in S3File.items():

            #Remember task id is provided in order to exchange data among tasks generated in dynamic way.
            get_s3_files = createDynamicDAG('{}-getS3Data'.format(S3File), 
                                            'getS3Data', 
                                            {}) #your configs here.

            #Second step is upload S3 to GCS
            upload_s3_toGCS = createDynamicDAG('{}-uploadDataS3ToGCS'.format(S3File), 'uploadDataS3ToGCS', {'previous_task_id':'{}-'})

#write your configs again here like S3 bucket name prefix extra or read from yaml file, and other GCS config.


start >> get_s3_files
get_s3_files >> upload_s3_toGCS
upload_s3_toGCS >> end

Cảm ơn bạn rất nhiều. Vì vậy, một trong những vấn đề tôi gặp phải là chuyện gì sẽ xảy ra nếu không có tệp mới? Một trong những vấn đề tôi gặp phải là sẽ luôn có các tệp ở nơi này, nhưng không đảm bảo các tệp MỚI được kéo, điều đó có nghĩa là phần đó upload_s3_toGCSsẽ không tồn tại và lỗi trong luồng khí.
arcee123

Bạn có thể giải quyết vấn đề bằng cách xóa các tệp khỏi yamltệp sau khi tất cả các tệp này được tải lên GCS, theo cách này chỉ có các tệp mới sẽ xuất hiện trong yamltệp. Và trong trường hợp không có tệp mới, yamltệp sẽ trống và không có dag động nào được tạo. Đây là lý do tại sao yamltệp là tùy chọn tốt hơn nhiều so với việc lưu trữ tệp trong danh sách.
ashwin agrawal

Các yamltập tin cũng sẽ giúp đỡ trong việc duy trì khai thác gỗ của các tập tin s3 theo một cách, nếu giả sử một số các tập tin s3 không được tải lên GCS, sau đó bạn cũng có thể duy trì một lá cờ tương ứng với tập tin đó và sau đó thử lại những lúc DAG chạy tới.
ashwin agrawal

Và nếu không có tệp mới, bạn có thể đặt một ifđiều kiện trước DAG sẽ kiểm tra các tệp mới trong yamltệp nếu có tệp mới thực thi nếu không sẽ bỏ qua nó.
ashwin agrawal

vấn đề ở đây là hạ lưu được thiết lập. nếu hạ lưu được đặt mà không có các công việc thực tế (vì không có tệp nào tồn tại), nó sẽ bị lỗi.
arcee123
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.