Python mở rộng lớp dựng sẵn

Hướng dẫn lập trình Beam dành cho người dùng Beam muốn sử dụng Beam SDK để tạo quy trình xử lý dữ liệu. Nó cung cấp hướng dẫn sử dụng các lớp Beam SDK để xây dựng và kiểm tra quy trình của bạn. Hướng dẫn lập trình không nhằm mục đích tham khảo toàn diện, mà là hướng dẫn cấp cao, không phụ thuộc vào ngôn ngữ để lập trình quy trình Beam của bạn. Khi hướng dẫn lập trình được điền vào, văn bản sẽ bao gồm các mẫu mã bằng nhiều ngôn ngữ để giúp minh họa cách triển khai các khái niệm Beam trong quy trình của bạn

Nếu bạn muốn giới thiệu ngắn gọn về các khái niệm cơ bản của Beam trước khi đọc hướng dẫn lập trình, hãy xem trang Khái niệm cơ bản về mô hình Beam

Thích ứng cho
  • SDK Java
  • SDK Python
  • Truy cập SDK
  • SDK TypeScript

SDK Python hỗ trợ Python 3. 7, 3. 8, 3. 9 và 3. 10

Go SDK hỗ trợ Go v1. 18+. Bản phát hành SDK 2. 32. 0 là phiên bản thử nghiệm cuối cùng

Typescript SDK hỗ trợ Node v16+ và vẫn đang thử nghiệm

1. Tổng quan

Để sử dụng Beam, trước tiên bạn cần tạo một chương trình trình điều khiển bằng cách sử dụng các lớp trong một trong các Beam SDK. Chương trình trình điều khiển của bạn xác định đường dẫn của bạn, bao gồm tất cả đầu vào, biến đổi và đầu ra; . Chúng bao gồm Trình chạy đường ống, đến lượt nó, xác định đường ống của bạn sẽ chạy trên back-end nào

Beam SDK cung cấp một số khái niệm trừu tượng giúp đơn giản hóa cơ chế xử lý dữ liệu phân tán quy mô lớn. Các bản tóm tắt Beam giống nhau hoạt động với cả nguồn dữ liệu hàng loạt và luồng dữ liệu. Khi bạn tạo quy trình Beam, bạn có thể nghĩ về tác vụ xử lý dữ liệu của mình theo các khái niệm trừu tượng này. Chúng bao gồm

  • await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    68. Một
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    68 gói gọn toàn bộ tác vụ xử lý dữ liệu của bạn, từ đầu đến cuối. Điều này bao gồm đọc dữ liệu đầu vào, chuyển đổi dữ liệu đó và ghi dữ liệu đầu ra. Tất cả các chương trình trình điều khiển Beam phải tạo một
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    68. Khi bạn tạo
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    68, bạn cũng phải chỉ định các tùy chọn thực thi cho biết địa điểm và cách chạy của
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    68.

  • await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    73. Một
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    73 đại diện cho một tập dữ liệu phân tán mà đường dẫn Beam của bạn hoạt động trên đó. Tập dữ liệu có thể được giới hạn, nghĩa là nó đến từ một nguồn cố định như tệp hoặc không bị giới hạn, nghĩa là nó đến từ một nguồn cập nhật liên tục thông qua đăng ký hoặc cơ chế khác. Quy trình của bạn thường tạo một
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    73 ban đầu bằng cách đọc dữ liệu từ nguồn dữ liệu bên ngoài, nhưng bạn cũng có thể tạo một
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    73 từ dữ liệu trong bộ nhớ trong chương trình trình điều khiển của mình. Từ đó, các
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    73 là đầu vào và đầu ra cho từng bước trong quy trình của bạn

  • await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    78. Một
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    78 đại diện cho một thao tác xử lý dữ liệu hoặc một bước trong quy trình của bạn. Mỗi
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    78 lấy một hoặc nhiều đối tượng
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    73 làm đầu vào, thực hiện chức năng xử lý mà bạn cung cấp trên các phần tử của
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    73 đó và tạo ra 0 hoặc nhiều đối tượng
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    73 đầu ra

  • await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    84. SDK Go có một biến phạm vi rõ ràng được sử dụng để tạo một
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    68. Một
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    68 có thể trả về phạm vi gốc của nó bằng phương thức
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    87. Biến phạm vi được chuyển đến các hàm
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    78 để đặt chúng trong
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    68 sở hữu
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    84
  • biến đổi vào/ra. Beam đi kèm với một số “IO” - thư viện
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    78 đọc hoặc ghi dữ liệu vào các hệ thống lưu trữ bên ngoài khác nhau

Một chương trình điều khiển Beam điển hình hoạt động như sau

  • Tạo một đối tượng
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    68 và đặt các tùy chọn thực thi đường ống, bao gồm cả Trình chạy đường ống
  • Tạo một
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    73 ban đầu cho dữ liệu đường ống, sử dụng IO để đọc dữ liệu từ hệ thống lưu trữ bên ngoài hoặc sử dụng biến đổi
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    94 để tạo một
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    73 từ dữ liệu trong bộ nhớ
  • Áp dụng các
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    78 cho mỗi
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    73. Biến đổi có thể thay đổi, lọc, nhóm, phân tích hoặc xử lý các phần tử trong một
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    73. Biến đổi tạo đầu ra mới
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    73 mà không sửa đổi bộ sưu tập đầu vào. Một quy trình điển hình lần lượt áp dụng các biến đổi tiếp theo cho từng đầu ra mới
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    73 cho đến khi quá trình xử lý hoàn tất. Tuy nhiên, lưu ý rằng một đường ống không nhất thiết phải là một đường thẳng duy nhất gồm các phép biến đổi được áp dụng lần lượt. coi các
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    73 là các biến và các
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    78 là các hàm được áp dụng cho các biến này. hình dạng của đường ống có thể là một biểu đồ xử lý phức tạp tùy ý
  • Sử dụng IO để viết [các]
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    73 cuối cùng, đã chuyển đổi sang nguồn bên ngoài
  • Chạy đường ống bằng Trình chạy đường ống được chỉ định

Khi bạn chạy chương trình trình điều khiển Beam, Trình chạy đường ống mà bạn chỉ định sẽ xây dựng biểu đồ quy trình công việc của đường ống của bạn dựa trên các đối tượng

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 mà bạn đã tạo và các biến đổi mà bạn đã áp dụng. Biểu đồ đó sau đó được thực thi bằng cách sử dụng back-end xử lý phân tán phù hợp, trở thành một “công việc” không đồng bộ [hoặc tương đương] trên back-end đó

2. Tạo một đường ống dẫn

Phần trừu tượng hóa

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
68 gói gọn tất cả dữ liệu và các bước trong tác vụ xử lý dữ liệu của bạn. Chương trình trình điều khiển Beam của bạn thường bắt đầu bằng cách xây dựng một đối tượng Pipeline Pipeline Pipeline , .

Để sử dụng Beam, trước tiên chương trình trình điều khiển của bạn phải tạo một phiên bản của Beam SDK lớp

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
68 [thường là trong hàm
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
909]. Khi bạn tạo
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
68, bạn cũng cần đặt một số tùy chọn cấu hình. Bạn có thể đặt các tùy chọn cấu hình cho đường dẫn của mình theo chương trình, nhưng việc đặt các tùy chọn trước [hoặc đọc chúng từ dòng lệnh] và chuyển chúng đến đối tượng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
68 khi bạn tạo đối tượng thường dễ dàng hơn

Đường ống trong TypeScript API chỉ đơn giản là một chức năng sẽ được gọi với một đối tượng `root` duy nhất và được truyền cho phương thức `run` của Người chạy

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
4

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
6

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];

2. 1. Định cấu hình tùy chọn đường ống

Sử dụng các tùy chọn đường ống để định cấu hình các khía cạnh khác nhau của đường ống của bạn, chẳng hạn như trình chạy đường ống sẽ thực thi đường ống của bạn và bất kỳ cấu hình cụ thể nào của trình chạy theo yêu cầu của trình chạy đã chọn. Các tùy chọn quy trình của bạn có khả năng sẽ bao gồm thông tin như ID dự án của bạn hoặc vị trí lưu trữ tệp

Khi bạn chạy quy trình trên một trình chạy mà bạn chọn, một bản sao của PipelineOptions sẽ có sẵn cho mã của bạn. Ví dụ: nếu bạn thêm tham số PipelineOptions vào phương thức

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
912 của DoFn, tham số đó sẽ được hệ thống điền vào

2. 1. 1. Đặt PipelineOptions từ đối số dòng lệnh

Mặc dù bạn có thể định cấu hình quy trình của mình bằng cách tạo đối tượng

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
913 và đặt trường trực tiếp, nhưng Beam SDK bao gồm trình phân tích cú pháp dòng lệnh mà bạn có thể sử dụng để đặt trường trong
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
913 bằng cách sử dụng đối số dòng lệnh

Để đọc các tùy chọn từ dòng lệnh, hãy xây dựng đối tượng

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
913 của bạn như minh họa trong mã ví dụ sau

Sử dụng cờ Go để phân tích các đối số dòng lệnh để định cấu hình đường dẫn của bạn. Cờ phải được phân tích cú pháp trước khi

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
916 được gọi

Bất kỳ đối tượng Javascript nào cũng có thể được sử dụng làm tùy chọn đường dẫn. Người ta có thể xây dựng một cách thủ công, nhưng cũng thường truyền một đối tượng được tạo từ các tùy chọn dòng lệnh, chẳng hạn như

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
917

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
9

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
6

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
7

Điều này diễn giải các đối số dòng lệnh tuân theo định dạng

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
8

Việc thêm phương thức

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
918 sẽ kiểm tra các đối số dòng lệnh được yêu cầu và xác thực các giá trị đối số

Xây dựng

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
913 của bạn theo cách này cho phép bạn chỉ định bất kỳ tùy chọn nào làm đối số dòng lệnh

Xác định các biến cờ theo cách này cho phép bạn chỉ định bất kỳ tùy chọn nào làm đối số dòng lệnh

Ghi chú. Đường dẫn ví dụ về WordCount trình bày cách đặt các tùy chọn đường dẫn trong thời gian chạy bằng cách sử dụng các tùy chọn dòng lệnh

2. 1. 2. Tạo tùy chọn tùy chỉnh

Bạn có thể thêm các tùy chọn tùy chỉnh của riêng mình ngoài

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
913 tiêu chuẩn

Để thêm các tùy chọn của riêng bạn, hãy xác định giao diện với các phương thức getter và setter cho từng tùy chọn

Ví dụ sau đây cho biết cách thêm tùy chọn tùy chỉnh
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
921 và
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
922

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
4

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
50

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
51

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
52

Bạn cũng có thể chỉ định mô tả, mô tả này sẽ xuất hiện khi người dùng chuyển

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
923 làm đối số dòng lệnh và giá trị mặc định

Bạn đặt mô tả và giá trị mặc định bằng chú thích, như sau

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
53

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
54

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
55

Đối với Python, bạn cũng có thể chỉ cần phân tích các tùy chọn tùy chỉnh của mình bằng argparse;

Bạn nên đăng ký giao diện của mình với

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
924 và sau đó chuyển giao diện khi tạo đối tượng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
913. Khi bạn đăng ký giao diện của mình với
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
924,
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
923 có thể tìm thấy giao diện tùy chọn tùy chỉnh của bạn và thêm nó vào đầu ra của lệnh
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
923.
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
924 cũng sẽ xác thực rằng các tùy chọn tùy chỉnh của bạn tương thích với tất cả các tùy chọn đã đăng ký khác

Mã ví dụ sau đây cho biết cách đăng ký giao diện tùy chọn tùy chỉnh của bạn với

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
924

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
56

Bây giờ quy trình của bạn có thể chấp nhận

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
931 và
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
932 làm đối số dòng lệnh

3. bộ sưu tập

The PCollection

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 PCollection đại diện cho một khả năng phân phối . Bạn có thể coi
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 là dữ liệu "đường ống dẫn"; . Như vậy, nếu bạn muốn làm việc với dữ liệu trong đường dẫn của mình, dữ liệu đó phải ở dạng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73.

Sau khi bạn đã tạo

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
68 của mình, bạn sẽ cần bắt đầu bằng cách tạo ít nhất một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 ở dạng nào đó.
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 bạn tạo đóng vai trò là đầu vào cho hoạt động đầu tiên trong quy trình của bạn

3. 1. Tạo một PCCollection

Bạn tạo một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 bằng cách đọc dữ liệu từ một nguồn bên ngoài bằng API nguồn của Beam hoặc bạn có thể tạo một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 dữ liệu được lưu trữ trong một lớp bộ sưu tập trong bộ nhớ trong chương trình trình điều khiển của bạn. Cái trước thường là cách một đường ống sản xuất sẽ nhập dữ liệu; . Cái sau chủ yếu hữu ích cho mục đích thử nghiệm và gỡ lỗi

3. 1. 1. Đọc từ một nguồn bên ngoài

Để đọc từ nguồn bên ngoài, bạn sử dụng một trong các bộ điều hợp I/O do Beam cung cấp. Các bộ điều hợp khác nhau về cách sử dụng chính xác, nhưng tất cả chúng đều đọc từ một số nguồn dữ liệu bên ngoài và trả về một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 có các phần tử đại diện cho các bản ghi dữ liệu trong nguồn đó

Mỗi bộ điều hợp nguồn dữ liệu có một biến đổi

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
943; . ______3945 ______3946
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
947
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
948
, . Đây là cách bạn sẽ đăng ký ____3945 ______3946
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
947
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
948
to your
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
68 root to create a
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73:

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
57

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
58

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
59

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
60

Xem phần về I/O để tìm hiểu thêm về cách đọc từ các nguồn dữ liệu khác nhau được Beam SDK hỗ trợ

3. 1. 2. Tạo PCollection từ dữ liệu trong bộ nhớ

Để tạo một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 từ một Java
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
959 trong bộ nhớ, bạn sử dụng biến đổi
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
94 do Beam cung cấp. Giống như
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
943 của bộ điều hợp dữ liệu, bạn áp dụng trực tiếp
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
94 cho chính đối tượng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
68 của mình

Là tham số,

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
94 chấp nhận đối tượng Java
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
959 và một đối tượng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
966.
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
966 chỉ định cách mã hóa các phần tử trong
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
959

Để tạo một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 từ một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
970 trong bộ nhớ, bạn sử dụng biến đổi
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
94 do Beam cung cấp. Áp dụng biến đổi này trực tiếp cho chính đối tượng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
68 của bạn

Để tạo một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 từ một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
974 trong bộ nhớ, bạn sử dụng biến đổi
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
975 do Beam cung cấp. Vượt qua đường dẫn
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
976 và
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
974 để chuyển đổi này

Để tạo một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 từ một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
979 trong bộ nhớ, bạn sử dụng biến đổi
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
94 do Beam cung cấp. Áp dụng biến đổi này trực tiếp cho đối tượng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
981 của bạn

Mã ví dụ sau cho biết cách tạo một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 từ bộ nhớ trong
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
983
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
970
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
974 .
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
979
:

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
61

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
62

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
63

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
64

3. 2. Đặc tính bộ sưu tập

A

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 được sở hữu bởi đối tượng cụ thể
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
68 mà nó được tạo ra; . Ở một số khía cạnh, chức năng của lớp
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 giống như lớp
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
959. Tuy nhiên, một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 có thể khác nhau theo một số cách chính.

3. 2. 1. Loại nguyên tố

Các phần tử của

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 có thể thuộc bất kỳ loại nào, nhưng tất cả phải cùng loại. Tuy nhiên, để hỗ trợ xử lý phân tán, Beam cần có khả năng mã hóa từng phần tử riêng lẻ dưới dạng chuỗi byte [để các phần tử có thể được chuyển cho các công nhân phân tán]. Beam SDK cung cấp cơ chế mã hóa dữ liệu bao gồm mã hóa tích hợp cho các loại thường được sử dụng cũng như hỗ trợ chỉ định mã hóa tùy chỉnh khi cần

3. 2. 2. lược đồ phần tử

Trong nhiều trường hợp, loại phần tử trong

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 có cấu trúc có thể xem xét nội tâm. Ví dụ là các bản ghi JSON, Bộ đệm giao thức, Avro và cơ sở dữ liệu. Các lược đồ cung cấp một cách để thể hiện các loại dưới dạng một tập hợp các trường được đặt tên, cho phép các tập hợp biểu cảm hơn

3. 2. 3. tính bất biến

Một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 là bất biến. Sau khi tạo, bạn không thể thêm, xóa hoặc thay đổi các thành phần riêng lẻ. Chuyển đổi Beam có thể xử lý từng phần tử của
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 và tạo dữ liệu đường ống mới [dưới dạng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 mới], nhưng nó không sử dụng hoặc sửa đổi bộ sưu tập đầu vào ban đầu

Ghi chú. Beam SDK tránh việc sao chép các phần tử không cần thiết, vì vậy nội dung của

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 là bất biến về mặt logic chứ không phải bất biến về mặt vật lý. Các thay đổi đối với các thành phần đầu vào có thể hiển thị đối với các DoFns khác đang thực thi trong cùng một gói và có thể gây ra các vấn đề về tính chính xác. Theo quy định, sẽ không an toàn khi sửa đổi các giá trị được cung cấp cho DoFn

3. 2. 4. Truy cập ngẫu nhiên

Một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 không hỗ trợ truy cập ngẫu nhiên vào các phần tử riêng lẻ. Thay vào đó, Beam Transforms xem xét từng phần tử trong một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 riêng lẻ

3. 2. 5. Kích thước và giới hạn

Một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 là một “túi” phần tử lớn, bất biến. Không có giới hạn trên về số lượng phần tử mà một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 có thể chứa;

Một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 có thể có kích thước giới hạn hoặc không giới hạn. Một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 có giới hạn biểu thị một tập dữ liệu có kích thước cố định, đã biết, trong khi một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 không giới hạn biểu thị một tập dữ liệu có kích thước không giới hạn. Việc một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 có giới hạn hay không giới hạn phụ thuộc vào nguồn của tập dữ liệu mà nó đại diện. Việc đọc từ nguồn dữ liệu lô, chẳng hạn như tệp hoặc cơ sở dữ liệu, sẽ tạo ra một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 có giới hạn. Việc đọc từ nguồn dữ liệu phát trực tuyến hoặc cập nhật liên tục, chẳng hạn như Pub/Sub hoặc Kafka, sẽ tạo ra một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 không giới hạn [trừ khi bạn yêu cầu rõ ràng là không làm như vậy]

Bản chất bị chặn [hoặc không bị chặn] của

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 của bạn ảnh hưởng đến cách Beam xử lý dữ liệu của bạn. Có thể xử lý một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 có giới hạn bằng cách sử dụng một công việc hàng loạt, có thể đọc toàn bộ tập dữ liệu một lần và thực hiện xử lý trong một công việc có độ dài hữu hạn. Một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 không giới hạn phải được xử lý bằng cách sử dụng công việc phát trực tuyến chạy liên tục, vì toàn bộ bộ sưu tập không bao giờ có sẵn để xử lý cùng một lúc

Beam sử dụng cửa sổ để phân chia một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 không giới hạn cập nhật liên tục thành các cửa sổ logic có kích thước hữu hạn. Các cửa sổ logic này được xác định bởi một số đặc điểm được liên kết với một phần tử dữ liệu, chẳng hạn như dấu thời gian. Các biến đổi tổng hợp [chẳng hạn như
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
514 và
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
515] hoạt động trên cơ sở mỗi cửa sổ — khi tập dữ liệu được tạo, chúng xử lý từng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 dưới dạng chuỗi liên tiếp của các cửa sổ hữu hạn này

3. 2. 6. dấu thời gian phần tử

Mỗi phần tử trong một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 có một dấu thời gian nội tại được liên kết. Dấu thời gian cho mỗi phần tử ban đầu được chỉ định bởi Nguồn tạo ra
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73. Các nguồn tạo
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 không giới hạn thường gán cho mỗi phần tử mới một dấu thời gian tương ứng với thời điểm phần tử được đọc hoặc thêm vào

Ghi chú. Các nguồn tạo một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 có giới hạn cho một tập dữ liệu cố định cũng tự động gán dấu thời gian, nhưng hành vi phổ biến nhất là gán mọi phần tử cùng một dấu thời gian [
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
521]

Dấu thời gian rất hữu ích cho một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 chứa các phần tử có khái niệm cố hữu về thời gian. Nếu quy trình bán hàng của bạn đang đọc một luồng sự kiện, chẳng hạn như Tweet hoặc các thông báo trên mạng xã hội khác, thì mỗi phần tử có thể sử dụng thời gian sự kiện được đăng làm dấu thời gian của phần tử

Bạn có thể tự gán dấu thời gian cho các thành phần của

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 nếu nguồn không làm việc đó cho bạn. Bạn sẽ muốn làm điều này nếu các phần tử có dấu thời gian vốn có, nhưng dấu thời gian nằm ở đâu đó trong cấu trúc của chính phần tử đó [chẳng hạn như trường “thời gian” trong mục nhập nhật ký máy chủ]. Beam có các Biến đổi lấy
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 làm đầu vào và xuất ra một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 giống hệt nhau có gắn dấu thời gian;

4. biến đổi

Chuyển đổi là các hoạt động trong quy trình của bạn và cung cấp khung xử lý chung. Bạn cung cấp logic xử lý dưới dạng một đối tượng chức năng [thường được gọi là “mã người dùng”] và mã người dùng của bạn được áp dụng cho từng thành phần của đầu vào

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 [hoặc nhiều hơn một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73]. Tùy thuộc vào trình chạy đường ống và back-end mà bạn chọn, nhiều công nhân khác nhau trong một cụm có thể thực thi song song các phiên bản mã người dùng của bạn. Mã người dùng chạy trên mỗi công nhân tạo ra các phần tử đầu ra cuối cùng được thêm vào đầu ra cuối cùng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 mà biến đổi tạo ra

Tập hợp là một khái niệm quan trọng cần hiểu khi tìm hiểu về các biến đổi của Beam. Để biết giới thiệu về tổng hợp, hãy xem phần Cơ bản về Tập hợp mô hình Beam

Beam SDK chứa một số biến đổi khác nhau mà bạn có thể áp dụng cho các

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 của quy trình bán hàng của mình. Chúng bao gồm các phép biến đổi cốt lõi có mục đích chung, chẳng hạn như ParDo hoặc Combine. Ngoài ra còn có các biến đổi tổng hợp được viết sẵn trong SDK, kết hợp một hoặc nhiều biến đổi cốt lõi trong một mẫu xử lý hữu ích, chẳng hạn như đếm hoặc kết hợp các phần tử trong một bộ sưu tập. Bạn cũng có thể xác định các phép biến đổi tổng hợp phức tạp hơn của riêng mình để phù hợp với trường hợp sử dụng chính xác của đường ống dẫn của bạn

4. 1. Áp dụng biến đổi

Để gọi một phép biến đổi, bạn phải áp dụng nó cho đầu vào

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73. Mỗi biến đổi trong Beam SDK có một phương thức chung
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
531 [hoặc toán tử đường ống
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
532]
. Gọi nhiều biến đổi Beam tương tự như chuỗi phương thức, nhưng có một chút khác biệt. Bạn áp dụng biến đổi cho đầu vào
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73, chuyển chính biến đổi đó làm đối số và thao tác trả về đầu ra
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73. Điều này có hình thức chung.

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
65

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
66

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
67

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
68

Vì Beam sử dụng một phương thức chung

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
531 cho
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73, nên bạn có thể thực hiện cả hai phép biến đổi chuỗi một cách tuần tự và cũng có thể áp dụng các phép biến đổi chứa các biến đổi khác được lồng bên trong [được gọi là phép biến đổi tổng hợp trong Beam SDK]

Bạn nên tạo một biến mới cho mỗi

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 mới để chuyển đổi tuần tự dữ liệu đầu vào. Các
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
84 có thể được sử dụng để tạo các hàm chứa các biến đổi khác [được gọi là các biến đổi tổng hợp trong Beam SDK]

Cách bạn áp dụng các biến đổi của quy trình xác định cấu trúc quy trình của bạn. Cách tốt nhất để nghĩ về quy trình của bạn là biểu đồ tuần hoàn có hướng, trong đó các nút

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
78 là các chương trình con chấp nhận các nút ________ 073 làm đầu vào và phát ra các nút ________ 073 làm đầu ra. Ví dụ: bạn có thể xâu chuỗi các biến đổi lại với nhau để tạo một quy trình sửa đổi liên tục dữ liệu đầu vào. Ví dụ: bạn có thể gọi liên tục các biến đổi trên PCCollections để sửa đổi dữ liệu đầu vào.

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
69

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
0

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
1

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
2

Biểu đồ của đường ống này trông giống như sau

Hình 1. Một đường ống tuyến tính với ba phép biến đổi tuần tự

Tuy nhiên, lưu ý rằng một phép biến đổi không tiêu thụ hoặc thay đổi bộ sưu tập đầu vào — hãy nhớ rằng theo định nghĩa, một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 là bất biến. Điều này có nghĩa là bạn có thể áp dụng nhiều biến đổi cho cùng một đầu vào
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 để tạo một đường dẫn phân nhánh, như vậy

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
3

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
4

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
6

Biểu đồ của đường ống phân nhánh này trông giống như sau

Hình 2. Một đường ống phân nhánh. Hai biến đổi được áp dụng cho một PCCollection các hàng của bảng cơ sở dữ liệu

Bạn cũng có thể xây dựng các biến đổi tổng hợp của riêng mình để lồng nhiều biến đổi vào trong một biến đổi đơn lớn hơn. Biến đổi tổng hợp đặc biệt hữu ích để xây dựng một chuỗi các bước đơn giản có thể tái sử dụng được sử dụng ở nhiều nơi khác nhau

Cú pháp đường ống cho phép một người áp dụng PTransforms cho

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
544 và
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
545 của PCCollections cũng như cho những biến đổi chấp nhận nhiều đầu vào [chẳng hạn như
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
546 và
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
547]

PTransforms cũng có thể được áp dụng cho bất kỳ

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
548 nào, bao gồm đối tượng Gốc, PCollections, mảng của
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
548 và các đối tượng có giá trị
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
548. Người ta có thể áp dụng các phép biến đổi cho các loại hỗn hợp này bằng cách bọc chúng bằng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
551, e. g.
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
552

PTransforms có hai dạng, đồng bộ và không đồng bộ, tùy thuộc vào việc ứng dụng của chúng* có liên quan đến các lệnh gọi không đồng bộ hay không. Một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
553 phải được áp dụng với
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
554 và trả lại một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
555 phải được chờ trước khi xây dựng đường ống tiếp theo

4. 2. biến đổi Core Beam

Beam cung cấp các biến đổi cốt lõi sau đây, mỗi biến đổi này đại diện cho một mô hình xử lý khác nhau

  • await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    556
  • await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    514
  • await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    547
  • await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    515
  • await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    546
  • await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    561

Typescript SDK cung cấp một số biến đổi cơ bản nhất dưới dạng các phương thức trên chính

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73

4. 2. 1. ân xá

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556 là một biến đổi Beam để xử lý song song chung. Mô hình xử lý
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556 tương tự như giai đoạn “Bản đồ” của thuật toán kiểu Bản đồ/Xáo trộn/Giảm. biến đổi
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556 xem xét từng phần tử trong đầu vào
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73, thực hiện một số chức năng xử lý [mã người dùng của bạn] trên phần tử đó và phát ra 0, một hoặc nhiều phần tử cho đầu ra
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556 hữu ích cho nhiều hoạt động xử lý dữ liệu phổ biến, bao gồm

  • Lọc tập dữ liệu. Bạn có thể sử dụng
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    556 để xem xét từng phần tử trong
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    73 và xuất phần tử đó sang bộ sưu tập mới hoặc loại bỏ phần tử đó
  • Định dạng hoặc chuyển đổi kiểu từng thành phần trong tập dữ liệu. Nếu đầu vào của bạn
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    73 chứa các phần tử thuộc loại hoặc định dạng khác với bạn muốn, bạn có thể sử dụng
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    556 để thực hiện chuyển đổi trên từng phần tử và xuất kết quả thành một
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    73 mới
  • Trích xuất các phần của từng phần tử trong tập dữ liệu. Ví dụ: nếu bạn có một
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    73 bản ghi với nhiều trường, bạn có thể sử dụng một
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    556 để phân tích cú pháp chỉ những trường bạn muốn xem xét thành một
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    73 mới
  • Thực hiện tính toán trên từng phần tử trong tập dữ liệu. Bạn có thể sử dụng
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    556 để thực hiện các tính toán đơn giản hoặc phức tạp trên mọi phần tử hoặc một số phần tử nhất định của
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    73 và xuất kết quả dưới dạng một
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    73 mới

Với những vai trò như vậy,

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556 là một bước trung gian phổ biến trong quy trình. Bạn có thể sử dụng nó để trích xuất các trường nhất định từ một tập hợp các bản ghi đầu vào thô hoặc chuyển đổi đầu vào thô sang một định dạng khác;

Khi bạn áp dụng biến đổi

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556, bạn sẽ cần cung cấp mã người dùng ở dạng đối tượng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583.
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583 là lớp Beam SDK xác định chức năng xử lý phân tán

Khi bạn tạo một lớp con của

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583, hãy lưu ý rằng lớp con của bạn phải tuân thủ các Yêu cầu để viết mã người dùng cho các biến đổi Beam

Tất cả các DoFns phải được đăng ký bằng hàm

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
586 chung. Điều này cho phép Go SDK phỏng đoán mã hóa từ bất kỳ đầu vào/đầu ra nào, đăng ký DoFn để thực thi trên các trình chạy từ xa và tối ưu hóa quá trình thực thi thời gian chạy của DoFns thông qua phản ánh

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
7

4. 2. 1. 1. Áp dụng ParDo

Giống như tất cả các biến đổi Beam, bạn áp dụng

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556 bằng cách gọi phương thức
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
531 trên đầu vào
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 và chuyển
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556 làm đối số, như được hiển thị trong mã ví dụ sau

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
591 áp dụng đối số được truyền trong
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583 cho đầu vào
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73, như thể hiện trong mã ví dụ sau

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
8

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
9

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
90

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
91

Trong ví dụ, đầu vào

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 của chúng tôi chứa các giá trị ____3950 ____5596 . Chúng tôi áp dụng một biến đổi
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556 chỉ định một hàm [
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
598] để tính toán độ dài của mỗi chuỗi và đưa ra kết quả cho một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 mới của
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
600
______5601< . values that stores the length of each word.

4. 2. 1. 2. Tạo DoFn

Đối tượng

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583 mà bạn chuyển đến
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556 chứa logic xử lý được áp dụng cho các phần tử trong bộ sưu tập đầu vào. Khi bạn sử dụng Beam, thường thì những đoạn mã quan trọng nhất mà bạn sẽ viết là những
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583 này - chúng là thứ xác định các tác vụ xử lý dữ liệu chính xác của quy trình bán hàng của bạn

Ghi chú. Khi bạn tạo

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583, hãy lưu ý đến Yêu cầu viết mã người dùng cho phép biến đổi Beam và đảm bảo rằng mã của bạn tuân theo các yêu cầu đó

Một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583 xử lý từng phần tử một từ đầu vào
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73. Khi bạn tạo một lớp con của
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583, bạn sẽ cần cung cấp các tham số loại phù hợp với các loại phần tử đầu vào và đầu ra. Nếu
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583 của bạn xử lý các phần tử
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
950 đến và tạo ra các phần tử
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
600 cho tập hợp đầu ra [như ví dụ trước của chúng tôi,
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
598], khai báo lớp của bạn sẽ như thế này

Một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583 xử lý từng phần tử một từ đầu vào
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73. Khi bạn tạo một cấu trúc
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583, bạn sẽ cần cung cấp các tham số loại phù hợp với các loại phần tử đầu vào và đầu ra trong một phương thức ProcessElement. Nếu
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583 của bạn xử lý các phần tử
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
596 đến và tạo các phần tử
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
601 cho tập hợp đầu ra [như ví dụ trước của chúng tôi,
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
598], dofn của bạn có thể trông như thế này

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
92

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
93

Bên trong lớp con

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583 của bạn, bạn sẽ viết một phương thức được chú thích bằng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
912 nơi bạn cung cấp logic xử lý thực tế. Bạn không cần trích xuất thủ công các phần tử từ bộ sưu tập đầu vào; . Phương thức
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
912 của bạn phải chấp nhận tham số được gắn thẻ
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
623, tham số này sẽ được điền bằng phần tử đầu vào. Để xuất các phần tử, phương thức cũng có thể nhận một tham số kiểu
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
624 cung cấp một phương thức để xuất các phần tử. Các loại tham số phải khớp với các loại đầu vào và đầu ra của
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583 của bạn, nếu không khung sẽ phát sinh lỗi. Ghi chú.
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
623 và
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
624 đã được giới thiệu trong Beam 2. 5. 0;

Bên trong lớp con

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583 của bạn, bạn sẽ viết một phương thức
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
630 nơi bạn cung cấp logic xử lý thực tế. Bạn không cần trích xuất thủ công các phần tử từ bộ sưu tập đầu vào; . Phương thức
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
630 của bạn phải chấp nhận một đối số
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
632, là phần tử đầu vào và trả về một lần lặp với các giá trị đầu ra của nó. Bạn có thể thực hiện điều này bằng cách phát ra các phần tử riêng lẻ với các câu lệnh
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
633. Bạn cũng có thể sử dụng câu lệnh
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
634 có thể lặp lại, như danh sách hoặc trình tạo

Đối với loại

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583 của bạn, bạn sẽ viết một phương thức
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
636 nơi bạn cung cấp logic xử lý thực tế. Bạn không cần trích xuất thủ công các phần tử từ bộ sưu tập đầu vào; . Phương thức
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
636 của bạn phải chấp nhận tham số
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
632, là phần tử đầu vào. Để xuất các phần tử, phương thức cũng có thể nhận một tham số chức năng, có thể được gọi để xuất các phần tử. Các loại tham số phải khớp với các loại đầu vào và đầu ra của
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583 của bạn, nếu không khung sẽ phát sinh lỗi

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
94

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
95

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
96

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
97

DoFns đơn giản cũng có thể được viết dưới dạng hàm

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
98

Ghi chú. Cho dù sử dụng loại

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583 cấu trúc hay chức năng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583, chúng phải được đăng ký với dầm trong một khối
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
642. Nếu không, chúng có thể không thực thi trên các chân chạy phân tán

Ghi chú. Nếu các phần tử trong dữ liệu đầu vào của bạn

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 là các cặp khóa/giá trị, thì bạn có thể truy cập khóa hoặc giá trị đó bằng cách sử dụng tương ứng là
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
644 hoặc
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
645.

Ghi chú. Nếu các phần tử trong đầu vào của bạn

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 là các cặp khóa/giá trị, thì phương thức phần tử quy trình của bạn phải có hai tham số, tương ứng cho mỗi khóa và giá trị. Tương tự, các cặp khóa/giá trị cũng được xuất dưới dạng các tham số riêng biệt cho một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
647

Một phiên bản

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583 nhất định thường được gọi một hoặc nhiều lần để xử lý một số gói phần tử tùy ý. Tuy nhiên, Beam không đảm bảo số lần gọi chính xác; . Như vậy, bạn có thể lưu trữ thông tin qua nhiều lệnh gọi đến phương thức xử lý của mình, nhưng nếu bạn làm như vậy, hãy đảm bảo rằng việc triển khai không phụ thuộc vào số lượng lệnh gọi

Trong phương thức xử lý của mình, bạn cũng cần phải đáp ứng một số yêu cầu về tính không thay đổi để đảm bảo rằng Beam và back-end xử lý có thể tuần tự hóa và lưu trữ các giá trị trong quy trình của bạn một cách an toàn. Phương pháp của bạn phải đáp ứng các yêu cầu sau

  • Bạn không nên sửa đổi một phần tử được trả về bởi chú thích
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    623 hoặc
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    650 [các phần tử đến từ bộ sưu tập đầu vào] dưới bất kỳ hình thức nào.
  • Khi bạn xuất một giá trị bằng cách sử dụng
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    651, bạn không nên sửa đổi giá trị đó theo bất kỳ cách nào
  • Bạn không nên sửa đổi đối số
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    632 được cung cấp cho phương thức
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    630 hoặc bất kỳ đầu vào bên nào theo bất kỳ cách nào.
  • Khi bạn xuất một giá trị bằng cách sử dụng
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    633 hoặc
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    634, bạn không nên sửa đổi giá trị đó theo bất kỳ cách nào
  • Bạn không nên sửa đổi các tham số được cung cấp cho phương thức
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    636 hoặc bất kỳ đầu vào phụ nào theo bất kỳ cách nào.
  • Khi bạn xuất một giá trị bằng cách sử dụng
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    647, bạn không nên sửa đổi giá trị đó theo bất kỳ cách nào
4. 2. 1. 3. DoFns nhẹ và trừu tượng khác

Nếu chức năng của bạn tương đối đơn giản, bạn có thể đơn giản hóa việc sử dụng

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556 của mình bằng cách cung cấp một nội tuyến
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583 nhẹ, dưới dạng một thể hiện của lớp bên trong ẩn danh a lambda function an anonymous function a function passed to
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
660 or
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
661
.

Đây là ví dụ trước,

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556 với
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
663, với
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583 được chỉ định là thể hiện của lớp bên trong ẩn danh hàm lambda an anonymous function a function:

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
99

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
50

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
51

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
52

Nếu

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556 của bạn thực hiện ánh xạ một đối một giữa các phần tử đầu vào với các phần tử đầu ra–nghĩa là đối với mỗi phần tử đầu vào, nó áp dụng một hàm tạo ra chính xác một phần tử đầu ra, you can return that element directly.bạn có thể sử dụng biến đổi
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
666
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
667
cấp cao hơn.
______5666 có thể chấp nhận hàm lambda Java 8 ẩn danh để thêm phần ngắn gọn.

Đây là ví dụ trước sử dụng

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
666
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
667
trả lại trực tiếp:

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
53

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
54

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
55

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
56

Ghi chú. Bạn có thể sử dụng các hàm lambda của Java 8 với một số biến đổi Beam khác, bao gồm

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
671,
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
672 và
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
561

Ghi chú. Chức năng ẩn danh DoFns có thể không hoạt động trên các trình chạy phân tán. Bạn nên sử dụng các hàm được đặt tên và đăng ký chúng với

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
674 trong một khối
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
675

4. 2. 1. 4. vòng đời doFn

Đây là sơ đồ trình tự hiển thị vòng đời của DoFn trong quá trình thực hiện biến đổi ParDo. Các nhận xét cung cấp thông tin hữu ích cho các nhà phát triển đường ống, chẳng hạn như các ràng buộc áp dụng cho các đối tượng hoặc các trường hợp cụ thể như chuyển đổi dự phòng hoặc tái sử dụng phiên bản. Họ cũng đưa ra các trường hợp sử dụng khởi tạo

4. 2. 2. NhómByKey

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
514 là một biến đổi Beam để xử lý tập hợp các cặp khóa/giá trị. Đó là một hoạt động giảm song song, tương tự như giai đoạn Xáo trộn của thuật toán kiểu Bản đồ/Xáo trộn/Giảm. Đầu vào của
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
514 là tập hợp các cặp khóa/giá trị đại diện cho nhiều ánh xạ, trong đó tập hợp chứa nhiều cặp có cùng khóa nhưng khác giá trị. Với một bộ sưu tập như vậy, bạn sử dụng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
514 để thu thập tất cả các giá trị được liên kết với mỗi khóa duy nhất

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
514 là một cách hay để tổng hợp dữ liệu có điểm chung. Ví dụ: nếu bạn có một bộ sưu tập lưu trữ các bản ghi đơn đặt hàng của khách hàng, bạn có thể muốn nhóm tất cả các đơn đặt hàng từ cùng một mã bưu điện lại với nhau [trong đó “khóa” của cặp khóa/giá trị là trường mã bưu chính và “

Hãy xem xét cơ chế của

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
514 với một trường hợp ví dụ đơn giản, trong đó tập dữ liệu của chúng tôi bao gồm các từ trong tệp văn bản và số dòng mà chúng xuất hiện. Chúng tôi muốn nhóm tất cả các số dòng [giá trị] có cùng một từ [khóa] lại với nhau, cho phép chúng tôi xem tất cả các vị trí trong văn bản nơi một từ cụ thể xuất hiện

Đầu vào của chúng tôi là một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 cặp khóa/giá trị trong đó mỗi từ là một khóa và giá trị là một số dòng trong tệp nơi từ đó xuất hiện. Đây là danh sách các cặp khóa/giá trị trong bộ sưu tập đầu vào

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
57

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
514 tập hợp tất cả các giá trị có cùng khóa và xuất ra một cặp mới bao gồm khóa duy nhất và tập hợp tất cả các giá trị được liên kết với khóa đó trong bộ sưu tập đầu vào. Nếu chúng tôi áp dụng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
514 cho bộ sưu tập đầu vào của chúng tôi ở trên, bộ sưu tập đầu ra sẽ như thế này

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
58

Do đó,

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
514 đại diện cho một phép biến đổi từ multimap [nhiều khóa thành các giá trị riêng lẻ] sang uni-map [các khóa duy nhất cho các bộ sưu tập giá trị]

Sử dụng

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
514 rất đơn giản

Mặc dù tất cả các SDK đều có biến đổi

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
514, nhưng việc sử dụng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
687 thường tự nhiên hơn. Biến đổi
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
687 có thể được tham số hóa bằng [các] tên thuộc tính để nhóm các phần tử của PCollection hoặc một hàm lấy từng phần tử làm đầu vào ánh xạ tới một khóa để thực hiện nhóm trên đó

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
59

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
60

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
61

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
62

4. 2. 2. 1 GroupByKey và PCollections không giới hạn

Nếu bạn đang sử dụng các

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 không giới hạn, bạn phải sử dụng cửa sổ không toàn cục hoặc trình kích hoạt tổng hợp để thực hiện một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
514 hoặc CoGroupByKey. Điều này là do một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
514 hoặc
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
547 có giới hạn phải đợi tất cả dữ liệu có khóa nhất định được thu thập, nhưng với các bộ sưu tập không giới hạn, dữ liệu là không giới hạn. Cửa sổ và/hoặc trình kích hoạt cho phép nhóm hoạt động trên các gói dữ liệu logic, hữu hạn trong các luồng dữ liệu không giới hạn

Nếu bạn áp dụng

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
514 hoặc
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
547 cho một nhóm
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 không giới hạn mà không đặt chiến lược cửa sổ không toàn cầu, chiến lược kích hoạt hoặc cả hai cho mỗi bộ sưu tập, Beam sẽ tạo ra lỗi IllegalStateException tại thời điểm xây dựng đường ống

Khi sử dụng

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
514 hoặc
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
547 để nhóm các
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 đã áp dụng chiến lược tạo cửa sổ, tất cả các
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 mà bạn muốn nhóm phải sử dụng cùng một chiến lược tạo cửa sổ và kích thước cửa sổ. Ví dụ: tất cả các bộ sưu tập bạn đang hợp nhất phải sử dụng cửa sổ cố định 5 phút giống hệt nhau [theo giả thuyết] hoặc cửa sổ trượt 4 phút bắt đầu cứ sau 30 giây

Nếu đường ống của bạn cố gắng sử dụng

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
514 hoặc
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
547 để hợp nhất các
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 với các cửa sổ không tương thích, thì Beam sẽ tạo ra lỗi IllegalStateException tại thời điểm xây dựng đường ống

4. 2. 3. CoGroupByKey

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
547 thực hiện liên kết quan hệ của hai hoặc nhiều khóa/giá trị
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 có cùng loại khóa. Thiết kế quy trình của bạn hiển thị một quy trình ví dụ sử dụng phép nối

Cân nhắc sử dụng

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
547 nếu bạn có nhiều bộ dữ liệu cung cấp thông tin về những thứ liên quan. Ví dụ: giả sử bạn có hai tệp khác nhau chứa dữ liệu người dùng. một tệp có tên và địa chỉ email; . Bạn có thể kết hợp hai tập dữ liệu đó, sử dụng tên người dùng làm khóa chung và dữ liệu khác làm giá trị được liên kết. Sau khi tham gia, bạn có một tập dữ liệu chứa tất cả thông tin [địa chỉ email và số điện thoại] được liên kết với mỗi tên

Nếu bạn đang sử dụng các

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 không giới hạn, bạn phải sử dụng cửa sổ không toàn cục hoặc trình kích hoạt tổng hợp để thực hiện một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
547. Xem GroupByKey và PCollections không giới hạn để biết thêm chi tiết

Trong Beam SDK cho Java,

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
547 chấp nhận một bộ các
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 có khóa [
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
710] làm đầu vào. Để đảm bảo an toàn cho loại, SDK yêu cầu bạn vượt qua từng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 như một phần của
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
712. Bạn phải khai báo một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
713 cho mỗi đầu vào
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 trong
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
712 mà bạn muốn chuyển đến
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
547. Là đầu ra,
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
547 trả về một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
718, nhóm các giá trị từ tất cả các
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 đầu vào theo các khóa chung của chúng. Mỗi khóa [tất cả thuộc loại
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
720] sẽ có một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
721 khác nhau, là bản đồ từ
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
722 đến
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
723. Bạn có thể truy cập một bộ sưu tập cụ thể trong một đối tượng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
721 bằng cách sử dụng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
713 mà bạn đã cung cấp cùng với bộ sưu tập ban đầu

Trong Beam SDK dành cho Python,

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
547 chấp nhận một từ điển gồm các
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 có khóa làm đầu vào. Là đầu ra,
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
547 tạo một đầu ra duy nhất
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 chứa một bộ khóa/giá trị cho mỗi khóa trong các
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 đầu vào. Giá trị của mỗi khóa là một từ điển ánh xạ từng thẻ thành một giá trị có thể lặp lại bên dưới khóa của chúng trong
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 tương ứng

Trong Beam Go SDK,

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
547 chấp nhận số lượng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 tùy ý làm đầu vào. Là đầu ra,
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
547 tạo một đầu ra duy nhất
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 nhóm từng khóa với các hàm lặp giá trị cho mỗi đầu vào
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73. Hàm iterator ánh xạ tới đầu vào
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
737 theo cùng thứ tự chúng được cung cấp cho
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
547

Các ví dụ khái niệm sau đây sử dụng hai bộ sưu tập đầu vào để hiển thị cơ chế của

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
547

Bộ dữ liệu đầu tiên có một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
740 được gọi là
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
741 và chứa tên và địa chỉ email. Bộ dữ liệu thứ hai có một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
740 được gọi là
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
743 và chứa tên và số điện thoại

Tập dữ liệu đầu tiên chứa tên và địa chỉ email. Bộ dữ liệu thứ hai chứa tên và số điện thoại

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
63

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
64

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
65

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
66

Sau

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
547, dữ liệu kết quả chứa tất cả dữ liệu được liên kết với từng khóa duy nhất từ ​​bất kỳ bộ sưu tập đầu vào nào

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
67

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
68

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
69

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
70

Ví dụ mã sau kết hợp hai

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 với
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
547, theo sau là một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556 để sử dụng kết quả. Sau đó, mã sử dụng các thẻ để tra cứu và định dạng dữ liệu từ mỗi bộ sưu tập

Ví dụ mã sau kết hợp hai

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 với
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
547, theo sau là một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556 để sử dụng kết quả. Thứ tự của các tham số trình vòng lặp
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583 ánh xạ tới thứ tự của các đầu vào
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
547

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
71

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
72

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
74

Dữ liệu được định dạng trông như thế này

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
75

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
76

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
77

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
78

4. 2. 4. Kết hợp

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
515
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
515
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
515
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
515
là một biến đổi Beam cho .
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
515 có các biến thể hoạt động trên toàn bộ
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 và một số biến thể kết hợp các giá trị cho từng khóa trong các cặp khóa/giá trị
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73.

Khi bạn áp dụng biến đổi

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
515, bạn phải cung cấp hàm chứa logic để kết hợp các phần tử hoặc giá trị. Hàm kết hợp phải có tính chất giao hoán và kết hợp, vì hàm này không nhất thiết phải được gọi chính xác một lần trên tất cả các giá trị với một khóa đã cho. Do dữ liệu đầu vào [bao gồm cả tập hợp giá trị] có thể được phân phối trên nhiều công nhân nên hàm kết hợp có thể được gọi nhiều lần để thực hiện kết hợp từng phần trên các tập hợp con của tập hợp giá trị. Beam SDK cũng cung cấp một số hàm kết hợp được tạo sẵn cho các hoạt động kết hợp số phổ biến như tổng, tối thiểu và tối đa

Các thao tác kết hợp đơn giản, chẳng hạn như tính tổng, thường có thể được triển khai dưới dạng một hàm đơn giản. Các hoạt động kết hợp phức tạp hơn có thể yêu cầu bạn tạo một lớp con của

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
761 có loại tích lũy khác với loại đầu vào/đầu ra.

Tính kết hợp và tính giao hoán của

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
761 cho phép người chạy tự động áp dụng một số tối ưu hóa

  • kết hợp nâng. Đây là tối ưu quan trọng nhất. Các phần tử đầu vào được kết hợp trên mỗi khóa và cửa sổ trước khi chúng được xáo trộn, do đó khối lượng dữ liệu được xáo trộn có thể giảm đi nhiều bậc độ lớn. Một thuật ngữ khác cho việc tối ưu hóa này là “kết hợp phía người lập bản đồ. ”
  • kết hợp tăng dần. Khi bạn có một
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    761 làm giảm rất nhiều kích thước dữ liệu, sẽ rất hữu ích khi kết hợp các phần tử khi chúng xuất hiện từ một luồng phát ngẫu nhiên. Điều này phân bổ chi phí thực hiện kết hợp theo thời gian mà tính toán phát trực tuyến của bạn có thể không hoạt động. Kết hợp tăng dần cũng làm giảm việc lưu trữ các bộ tích lũy trung gian
4. 2. 4. 1. Kết hợp đơn giản sử dụng chức năng đơn giản

Mã ví dụ sau hiển thị một hàm kết hợp đơn giản. Việc kết hợp được thực hiện bằng cách sửa đổi biến đổi nhóm bằng phương pháp

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
764. Phương thức này nhận ba tham số. giá trị để kết hợp [dưới dạng thuộc tính được đặt tên của các thành phần đầu vào hoặc hàm của toàn bộ đầu vào], thao tác kết hợp [hàm nhị phân hoặc
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
761] và cuối cùng là tên cho giá trị kết hợp trong đối tượng đầu ra.

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
79

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
80

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
81

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
82

Tất cả các Bộ kết hợp phải được đăng ký bằng hàm

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
766 chung. Điều này cho phép SDK Go suy ra mã hóa từ bất kỳ đầu vào/đầu ra nào, đăng ký Bộ kết hợp để thực thi trên các trình chạy từ xa và tối ưu hóa quá trình thực thi thời gian chạy của Bộ kết hợp thông qua phản chiếu

Combiner1 nên được sử dụng khi bộ tích lũy, đầu vào và đầu ra của bạn đều cùng loại. Nó có thể được gọi với

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
767 trong đó
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
768 là loại đầu vào/bộ tích lũy/đầu ra

Combiner2 nên được sử dụng khi bộ tích lũy, đầu vào và đầu ra của bạn là 2 loại riêng biệt. Nó có thể được gọi với

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
769 trong đó
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
770 là loại bộ tích lũy và
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
771 là loại khác

Combiner3 nên được sử dụng khi bộ tích lũy, đầu vào và đầu ra của bạn là 3 loại riêng biệt. Nó có thể được gọi với ________ 5772 trong đó _________ 5770 là loại bộ tích lũy, ________ 5771 là loại đầu vào và

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
775 là loại đầu ra

4. 2. 4. 2. Kết hợp nâng cao sử dụng CombineFn

Đối với các hàm kết hợp phức tạp hơn, bạn có thể định nghĩa một lớp con của

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
761. Bạn nên sử dụng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
761 nếu chức năng kết hợp yêu cầu bộ tích lũy phức tạp hơn, phải thực hiện thêm quá trình xử lý trước hoặc sau, có thể thay đổi loại đầu ra hoặc tính đến khóa.

Một thao tác kết hợp chung bao gồm bốn thao tác. Khi bạn tạo một lớp con của

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
761, bạn phải cung cấp bốn thao tác bằng cách ghi đè các phương thức tương ứng.

  1. Tạo bộ tích lũy tạo bộ tích lũy “cục bộ” mới. Trong trường hợp ví dụ, lấy giá trị trung bình trung bình, bộ tích lũy cục bộ theo dõi tổng giá trị đang chạy [giá trị tử số cho phép chia trung bình cuối cùng của chúng tôi] và số lượng giá trị được tính tổng cho đến nay [giá trị mẫu số]. Nó có thể được gọi bất kỳ số lần nào theo kiểu phân tán

  2. Add Input thêm phần tử đầu vào vào bộ tích lũy, trả về giá trị bộ tích lũy. Trong ví dụ của chúng tôi, nó sẽ cập nhật tổng và tăng số lượng. Nó cũng có thể được gọi song song

  3. Hợp nhất bộ tích lũy hợp nhất một số bộ tích lũy thành một bộ tích lũy duy nhất; . Trong trường hợp tính toán trung bình cộng trung bình, các bộ tích lũy đại diện cho từng phần của bộ phận được hợp nhất với nhau. Nó có thể được gọi lại trên đầu ra của nó bất kỳ số lần nào

  4. Trích xuất đầu ra thực hiện tính toán cuối cùng. Trong trường hợp tính toán trung bình cộng, điều này có nghĩa là chia tổng kết hợp của tất cả các giá trị cho số lượng giá trị tổng. Nó được gọi một lần trên bộ tích lũy cuối cùng, được hợp nhất

Mã ví dụ sau đây cho biết cách xác định một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
761 để tính trung bình cộng

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
83

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
84

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
85

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
86

Ghi chú. Chỉ có

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
780 là phương thức bắt buộc. Những cái khác sẽ có cách diễn giải mặc định dựa trên loại bộ tích lũy

4. 2. 4. 3. Kết hợp một PCollection thành một giá trị duy nhất

Sử dụng kết hợp toàn cầu để chuyển đổi tất cả các phần tử trong một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 nhất định thành một giá trị duy nhất, được biểu thị trong quy trình bán hàng của bạn dưới dạng một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 mới chứa một phần tử. Mã ví dụ sau đây cho biết cách áp dụng hàm kết hợp tổng do Beam cung cấp để tạo ra một giá trị tổng duy nhất cho
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 số nguyên

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
87

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
88

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
89

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
40

4. 2. 4. 4. Kết hợp và cửa sổ toàn cầu

Nếu đầu vào của bạn

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 sử dụng cửa sổ chung mặc định, hành vi mặc định là trả về một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 có chứa một mục. Giá trị của mặt hàng đó đến từ bộ tích lũy trong hàm kết hợp mà bạn đã chỉ định khi áp dụng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
515. Ví dụ: hàm kết hợp tổng do Beam cung cấp trả về giá trị 0 [tổng của đầu vào trống], trong khi hàm kết hợp nhỏ nhất trả về giá trị lớn nhất hoặc vô hạn

Thay vào đó, để có

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
515 trả về một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 trống nếu đầu vào trống, hãy chỉ định
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
789 khi bạn áp dụng biến đổi
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
515 của mình, như trong ví dụ mã sau

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
41

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
42

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
43

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
44

4. 2. 4. 5. Cửa sổ kết hợp và không toàn cầu

Nếu

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 của bạn sử dụng bất kỳ chức năng cửa sổ không toàn cầu nào, Beam sẽ không cung cấp hành vi mặc định. Bạn phải chỉ định một trong các tùy chọn sau khi đăng ký
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
515

  • Chỉ định
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    789, trong đó các cửa sổ trống trong đầu vào
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    73 cũng sẽ trống trong bộ sưu tập đầu ra
  • Chỉ định
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    795, trong đó đầu ra ngay lập tức được chuyển đổi thành
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    796, sẽ cung cấp giá trị mặc định cho mỗi cửa sổ trống khi được sử dụng làm đầu vào phụ. Nhìn chung, bạn chỉ cần sử dụng tùy chọn này nếu kết quả của
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    515 trong quy trình bán hàng của bạn sẽ được sử dụng làm đầu vào phụ sau này trong quy trình bán hàng

Nếu

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 của bạn sử dụng bất kỳ chức năng tạo cửa sổ không toàn cục nào, SDK Beam Go sẽ hoạt động giống như với tính năng tạo cửa sổ toàn cục. Cửa sổ trống trong đầu vào
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 cũng sẽ trống trong bộ sưu tập đầu ra

4. 2. 4. 6. Kết hợp các giá trị trong một PCollection có khóa

Sau khi tạo một PCollection có khóa [ví dụ: bằng cách sử dụng biến đổi

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
514], một mẫu phổ biến là kết hợp tập hợp các giá trị được liên kết với từng khóa thành một giá trị được hợp nhất. Dựa trên ví dụ trước từ ________ 5514, một ________ 073 được nhóm khóa có tên là ________ 5803 trông như thế này

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
45

Trong

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 ở trên, mỗi phần tử có một khóa chuỗi [ví dụ: “cat”] và một số nguyên có thể lặp lại cho giá trị của nó [trong phần tử đầu tiên, chứa [1, 5, 9]]. Nếu bước xử lý tiếp theo trong quy trình của chúng tôi kết hợp các giá trị [thay vì xem xét chúng riêng lẻ], thì bạn có thể kết hợp các số nguyên có thể lặp lại để tạo một giá trị hợp nhất duy nhất để ghép nối với từng khóa. Mẫu này của một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
514 theo sau là hợp nhất tập hợp các giá trị tương đương với biến đổi Kết hợp PerKey của Beam. Hàm kết hợp mà bạn cung cấp cho Combine PerKey phải là hàm rút gọn kết hợp hoặc một lớp con của
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
761.

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
46

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
47

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
48

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
49

4. 2. 5. làm phẳng

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
546
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
546
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
546
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
546
là một phép biến đổi Beam cho .
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
546 hợp nhất nhiều đối tượng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 thành một đối tượng logic duy nhất
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73.

Ví dụ sau đây cho thấy cách áp dụng biến đổi

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
546 để hợp nhất nhiều đối tượng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
500

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
501

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
502

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
503

4. 2. 5. 1. Mã hóa dữ liệu trong các bộ sưu tập hợp nhất

Theo mặc định, bộ mã hóa cho đầu ra

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 giống với bộ mã hóa cho
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 đầu tiên trong đầu vào
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
819. Tuy nhiên, mỗi đối tượng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 đầu vào có thể sử dụng các bộ mã hóa khác nhau, miễn là tất cả chúng đều chứa cùng một loại dữ liệu trong ngôn ngữ bạn chọn

4. 2. 5. 2. Hợp nhất các bộ sưu tập có cửa sổ

Khi sử dụng

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
546 để hợp nhất các đối tượng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 đã áp dụng chiến lược tạo cửa sổ, tất cả các đối tượng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 mà bạn muốn hợp nhất phải sử dụng chiến lược tạo cửa sổ và định cỡ cửa sổ tương thích. Ví dụ: tất cả các bộ sưu tập mà bạn đang hợp nhất đều phải sử dụng [theo giả thuyết] các cửa sổ cố định 5 phút giống hệt nhau hoặc cửa sổ trượt 4 phút bắt đầu cứ sau 30 giây

Nếu quy trình của bạn cố gắng sử dụng

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
546 để hợp nhất các đối tượng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 với các cửa sổ không tương thích, Beam sẽ tạo ra lỗi
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
826 khi quy trình của bạn được xây dựng

4. 2. 6. Vách ngăn

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
561 ______5561
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
561
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
561
là một biến đổi Beam cho .
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
561 tách một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 thành một số lượng cố định các bộ sưu tập nhỏ hơn.

Thông thường, trong TypeScript SDK, biến đổi

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
834 sẽ tự nhiên hơn khi sử dụng

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
561 phân chia các phần tử của
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 theo chức năng phân vùng mà bạn cung cấp. Hàm phân vùng chứa logic xác định cách tách các phần tử của đầu vào
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 thành từng phân vùng kết quả
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73. Số lượng phân vùng phải được xác định tại thời điểm xây dựng biểu đồ. Ví dụ: bạn có thể chuyển số lượng phân vùng dưới dạng tùy chọn dòng lệnh trong thời gian chạy [sau đó sẽ được sử dụng để xây dựng biểu đồ quy trình của bạn], nhưng bạn không thể xác định số lượng phân vùng ở giữa quy trình [dựa trên dữ liệu được tính toán sau

Ví dụ sau chia một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 thành các nhóm phần trăm

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
504

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
505

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
506

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
507

4. 3. Yêu cầu viết mã người dùng cho biến đổi Beam

Khi bạn xây dựng mã người dùng cho biến đổi Beam, bạn nên ghi nhớ bản chất thực thi phân tán. Ví dụ: có thể có nhiều bản sao chức năng của bạn chạy song song trên nhiều máy khác nhau và những bản sao đó hoạt động độc lập, không giao tiếp hoặc chia sẻ trạng thái với bất kỳ bản sao nào khác. Tùy thuộc vào Trình chạy đường ống và xử lý back-end mà bạn chọn cho đường ống của mình, mỗi bản sao chức năng mã người dùng của bạn có thể được thử lại hoặc chạy nhiều lần. Do đó, bạn nên thận trọng khi đưa những thứ như trạng thái phụ thuộc vào mã người dùng của mình

Nói chung, mã người dùng của bạn phải đáp ứng ít nhất các yêu cầu này

  • Đối tượng chức năng của bạn phải được tuần tự hóa
  • Đối tượng chức năng của bạn phải tương thích với luồng và lưu ý rằng SDK Beam không an toàn cho luồng

Ngoài ra, bạn nên đặt đối tượng chức năng của mình là idempotent. Các chức năng không bình thường được Beam hỗ trợ, nhưng cần suy nghĩ thêm để đảm bảo tính chính xác khi có tác dụng phụ bên ngoài

Ghi chú. Các yêu cầu này áp dụng cho các lớp con của

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583[một đối tượng hàm được sử dụng với biến đổi ParDo],
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
761 [một đối tượng hàm được sử dụng với biến đổi Kết hợp] và
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
842 [một đối tượng hàm được sử dụng với biến đổi Window].

Ghi chú. Các yêu cầu này áp dụng cho

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583s [đối tượng hàm được sử dụng với biến đổi ParDo],
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
761s [đối tượng hàm được sử dụng với biến đổi Kết hợp] và
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
842s [đối tượng hàm được sử dụng với biến đổi Window]

4. 3. 1. Khả năng tuần tự hóa

Mọi đối tượng hàm bạn cung cấp cho một biến đổi phải được tuần tự hóa hoàn toàn. Điều này là do một bản sao của hàm cần được đánh số thứ tự và truyền tới một nhân viên từ xa trong cụm xử lý của bạn. Các lớp cơ sở cho mã người dùng, chẳng hạn như

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583,
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
761 và
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
842, đã triển khai
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
849; . Các chức năng có thể tuần tự hóa miễn là chúng được đăng ký với
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
674 [đối với các chức năng đơn giản] hoặc
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
851 [đối với các DoFn cấu trúc] và không phải là các hàm đóng. Các cấu trúc
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583 sẽ có tất cả các trường đã xuất được đánh số thứ tự. Các trường chưa xuất không thể được đánh số thứ tự và sẽ bị bỏ qua âm thầm.
SDK bản mô tả sử dụng ts-serialize-closures để tuần tự hóa các hàm [và các đối tượng khác]. Điều này hoạt động vượt trội đối với các hàm không phải là hàm đóng và cũng hoạt động với hàm đóng miễn là hàm được đề cập [và bất kỳ hàm đóng nào mà nó tham chiếu] được biên dịch bằng các móc
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
853 [e. g. bằng cách sử dụng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
854 thay cho
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
855]. Ngoài ra, người ta có thể gọi
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
856 để đăng ký một chức năng trực tiếp theo tên có thể ít bị lỗi hơn. Lưu ý rằng nếu, như thường thấy trong Javascript, ________ 5857 trả về các đối tượng có bao đóng, thì việc đăng ký một mình ________ 5857 là không đủ – giá trị trả về của nó phải được đăng ký nếu được sử dụng.

Một số yếu tố khả năng tuần tự hóa khác mà bạn nên ghi nhớ là

  • Tạm thờiChưa xuất trong đối tượng chức năng của bạn không được truyền tới các phiên bản worker vì chúng không được tự động đánh số thứ tự.
  • Tránh tải một trường có lượng dữ liệu lớn trước khi tuần tự hóa
  • Các phiên bản riêng lẻ của đối tượng chức năng của bạn không thể chia sẻ dữ liệu
  • Thay đổi một đối tượng chức năng sau khi nó được áp dụng sẽ không có tác dụng

Ghi chú. Hãy cẩn thận khi khai báo nội tuyến đối tượng hàm của bạn bằng cách sử dụng một thể hiện của lớp bên trong ẩn danh. Trong ngữ cảnh không tĩnh, cá thể lớp bên trong của bạn sẽ ngầm chứa một con trỏ tới lớp kèm theo và trạng thái của lớp đó. Lớp kèm theo đó cũng sẽ được tuần tự hóa, và do đó, những cân nhắc tương tự áp dụng cho chính đối tượng hàm cũng áp dụng cho lớp bên ngoài này.

Ghi chú. Không có cách nào để phát hiện xem một chức năng có phải là một bao đóng hay không. Việc đóng cửa sẽ gây ra lỗi thời gian chạy và lỗi đường ống. Tránh sử dụng các chức năng ẩn danh khi có thể

4. 3. 2. Khả năng tương thích chủ đề

Đối tượng chức năng của bạn phải tương thích với luồng. Mỗi phiên bản của đối tượng chức năng của bạn được truy cập bởi một luồng duy nhất tại một thời điểm trên phiên bản worker, trừ khi bạn tạo các luồng của riêng mình một cách rõ ràng. Tuy nhiên, xin lưu ý rằng SDK Beam không an toàn cho luồng. Nếu bạn tạo chủ đề của riêng mình trong mã người dùng, bạn phải cung cấp đồng bộ hóa của riêng mình. Lưu ý rằng các thành viên tĩnh trong đối tượng chức năng của bạn không được chuyển đến các phiên bản worker và nhiều phiên bản chức năng của bạn có thể được truy cập từ các luồng khác nhau.

4. 3. 3. bất lực

Bạn nên đặt đối tượng chức năng của mình là idempotent–nghĩa là nó có thể được lặp lại hoặc thử lại thường xuyên nếu cần mà không gây ra các tác dụng phụ ngoài ý muốn. Các chức năng không bình thường được hỗ trợ, tuy nhiên, mô hình Beam không đảm bảo về số lần mã người dùng của bạn có thể được gọi hoặc thử lại;

4. 4. đầu vào bên

Ngoài đầu vào chính

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73, bạn có thể cung cấp thêm đầu vào cho biến đổi
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556 ở dạng đầu vào phụ. Đầu vào phụ là đầu vào bổ sung mà
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583 của bạn có thể truy cập mỗi khi nó xử lý một phần tử trong đầu vào
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73. Khi bạn chỉ định đầu vào phụ, bạn tạo chế độ xem một số dữ liệu khác có thể được đọc từ bên trong biến đổi ________ 5556 của biến đổi ________ 5583 trong khi xử lý từng phần tử

Đầu vào phụ hữu ích nếu

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556 của bạn cần thêm dữ liệu bổ sung khi xử lý từng phần tử trong đầu vào
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73, nhưng dữ liệu bổ sung cần được xác định trong thời gian chạy [và không được mã hóa cứng]. Các giá trị như vậy có thể được xác định bởi dữ liệu đầu vào hoặc phụ thuộc vào một nhánh khác trong quy trình của bạn

Tất cả các lần lặp đầu vào bên phải được đăng ký bằng hàm

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
867 chung. Điều này tối ưu hóa việc thực thi thời gian chạy của iterable

4. 4. 1. Truyền đầu vào bên cho ParDo

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
508

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
509

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
510

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
511

4. 4. 2. Đầu vào bên và cửa sổ

Một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 có cửa sổ có thể là vô hạn và do đó không thể được nén thành một giá trị duy nhất [hoặc một lớp bộ sưu tập duy nhất]. Khi bạn tạo một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
796 của một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 có cửa sổ, thì
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
796 đại diện cho một thực thể duy nhất trên mỗi cửa sổ [một đơn vị trên mỗi cửa sổ, một danh sách trên mỗi cửa sổ, v.v. ]

Beam sử dụng [các] cửa sổ cho phần tử đầu vào chính để tra cứu cửa sổ thích hợp cho phần tử đầu vào phụ. Beam chiếu cửa sổ của phần tử đầu vào chính vào bộ cửa sổ của đầu vào bên, sau đó sử dụng đầu vào bên từ cửa sổ kết quả. Nếu đầu vào chính và đầu vào phụ có các cửa sổ giống hệt nhau, phép chiếu sẽ cung cấp chính xác cửa sổ tương ứng. Tuy nhiên, nếu đầu vào có các cửa sổ khác nhau, Beam sẽ sử dụng phép chiếu để chọn cửa sổ đầu vào bên thích hợp nhất

Ví dụ: nếu đầu vào chính được tạo cửa sổ bằng cách sử dụng cửa sổ có thời gian cố định là một phút và đầu vào bên được hiển thị bằng cửa sổ có thời gian cố định là một giờ, thì Beam sẽ chiếu cửa sổ đầu vào chính dựa trên bộ cửa sổ đầu vào bên và chọn đầu vào bên

Nếu phần tử đầu vào chính tồn tại trong nhiều cửa sổ, thì

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
872 được gọi nhiều lần, một lần cho mỗi cửa sổ. Mỗi lần gọi đến
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
872 sẽ chiếu cửa sổ “hiện tại” cho phần tử đầu vào chính và do đó có thể cung cấp một chế độ xem khác nhau về đầu vào phụ mỗi lần

Nếu đầu vào bên có nhiều lần kích hoạt kích hoạt, Beam sẽ sử dụng giá trị từ lần kích hoạt mới nhất. Điều này đặc biệt hữu ích nếu bạn sử dụng đầu vào phụ với một cửa sổ chung duy nhất và chỉ định trình kích hoạt

4. 5. đầu ra bổ sung

Mặc dù

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556 luôn tạo ra một đầu ra chính
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 [là giá trị trả về từ
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
531], bạn cũng có thể yêu cầu
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556 của mình tạo ra bất kỳ số lượng đầu ra bổ sung nào của
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73. Nếu bạn chọn có nhiều đầu ra, thì
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556 của bạn sẽ trả về tất cả các
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 đầu ra [bao gồm cả đầu ra chính] được gộp lại với nhau

Mặc dù

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
591 luôn tạo ra đầu ra
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73, nhưng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583 của bạn có thể tạo ra bất kỳ số lượng đầu ra bổ sung nào của
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
737 hoặc thậm chí không có đầu ra nào. Nếu bạn chọn có nhiều đầu ra, thì
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583 của bạn cần được gọi bằng hàm
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556 khớp với số lượng đầu ra.
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
887 cho hai đầu ra
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73,
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
889 cho ba đầu ra, v.v. cho đến khi
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
890. Nếu bạn cần nhiều hơn, bạn có thể sử dụng ________ 5891 sẽ trả về ________ 5892

Trong khi

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556 luôn tạo ra đầu ra chính
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 [dưới dạng giá trị trả về từ
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
531]. Nếu bạn muốn có nhiều đầu ra, hãy phát ra một đối tượng có các thuộc tính riêng biệt trong thao tác
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556 của bạn và làm theo thao tác này với một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
834 để chia nó thành nhiều
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73

4. 5. 1. Thẻ cho nhiều đầu ra

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
834 PTransform sẽ lấy một PCCollection của các phần tử có dạng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
400 và trả về một đối tượng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
401. Tập hợp các thẻ mong muốn được chuyển đến hoạt động;

SDK Go không sử dụng thẻ đầu ra mà thay vào đó sử dụng thứ tự theo vị trí cho nhiều PCCollections đầu ra

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
512

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
513

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
514

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
515

4. 5. 2. Phát ra nhiều đầu ra trong DoFn của bạn

Gọi các hàm trình phát khi cần để tạo 0 hoặc nhiều phần tử để khớp với nó

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73. Cùng một giá trị có thể được phát ra với nhiều bộ phát. Như bình thường, không thay đổi giá trị sau khi phát chúng từ bất kỳ bộ phát nào

Tất cả các trình phát phải được đăng ký bằng hàm

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
404 chung. Điều này tối ưu hóa việc thực thi thời gian chạy của bộ phát

DoFns cũng có thể trả về một phần tử thông qua trả về tiêu chuẩn. Trả về tiêu chuẩn luôn là PCollection đầu tiên được trả về từ chùm. ân xá. Các trình phát khác xuất ra PCCollections của riêng chúng theo thứ tự tham số đã xác định

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
516

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
517

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
518

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
519

4. 5. 3. Truy cập các tham số bổ sung trong DoFn của bạn

Ngoài phần tử và

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
624, Beam sẽ điền các tham số khác vào phương thức
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
912 của DoFn của bạn. Bất kỳ sự kết hợp nào của các tham số này đều có thể được thêm vào phương thức quy trình của bạn theo bất kỳ thứ tự nào

Ngoài phần tử, Beam sẽ đưa các tham số khác vào phương thức

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
630 của DoFn của bạn. Bất kỳ sự kết hợp nào của các tham số này đều có thể được thêm vào phương thức quy trình của bạn theo bất kỳ thứ tự nào

Ngoài phần tử, Beam sẽ đưa các tham số khác vào phương thức

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
630 của DoFn của bạn. Chúng có sẵn bằng cách đặt các bộ truy cập trong đối số ngữ cảnh, giống như đối với các đầu vào bên

Ngoài phần tử, Beam sẽ điền các tham số khác vào phương thức

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
636 của DoFn của bạn. Bất kỳ sự kết hợp nào của các tham số này đều có thể được thêm vào phương thức quy trình của bạn theo thứ tự tiêu chuẩn

định nghĩa bài văn. Định nghĩa bài văn. Để hỗ trợ ghi nhật ký tổng hợp và số liệu do người dùng xác định, có thể yêu cầu tham số

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
410. Các quy ước Per Go, nếu có, nó bắt buộc phải là tham số đầu tiên của phương thức
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
520

Dấu thời gian. Để truy cập dấu thời gian của một phần tử đầu vào, hãy thêm một tham số được chú thích bằng

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
412 thuộc loại
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
413. Ví dụ

Dấu thời gian. Để truy cập dấu thời gian của phần tử đầu vào, hãy thêm tham số từ khóa mặc định vào

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
414. Ví dụ

Dấu thời gian. Để truy cập dấu thời gian của phần tử đầu vào, hãy thêm tham số

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
415 trước phần tử. Ví dụ

Dấu thời gian. Để truy cập vào cửa sổ có phần tử đầu vào, hãy thêm ____6416 vào đối số ngữ cảnh

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
521

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
522

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
523

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
524

Cửa sổ. Để truy cập vào cửa sổ mà phần tử đầu vào rơi vào, hãy thêm tham số loại cửa sổ được sử dụng cho đầu vào

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73. Nếu tham số là loại cửa sổ [một lớp con của
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
418] không khớp với đầu vào
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 thì sẽ xảy ra lỗi. Nếu một phần tử nằm trong nhiều cửa sổ [ví dụ: điều này sẽ xảy ra khi sử dụng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
420], thì phương thức
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
912 sẽ được gọi nhiều lần cho phần tử, một lần cho mỗi cửa sổ. Ví dụ: khi cửa sổ cố định đang được sử dụng, cửa sổ thuộc loại
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
422

Cửa sổ. Để truy cập vào cửa sổ có phần tử đầu vào, hãy thêm tham số từ khóa mặc định vào

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
423. Nếu một phần tử nằm trong nhiều cửa sổ [ví dụ: điều này sẽ xảy ra khi sử dụng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
420], thì phương thức
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
630 sẽ được gọi nhiều lần cho phần tử, một lần cho mỗi cửa sổ

Cửa sổ. Để truy cập cửa sổ có phần tử đầu vào, hãy thêm tham số

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
426 trước phần tử. Nếu một phần tử nằm trong nhiều cửa sổ [ví dụ: điều này sẽ xảy ra khi sử dụng SlidingWindows], thì phương thức
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
636 sẽ được gọi nhiều lần cho phần tử, một lần cho mỗi cửa sổ. Vì
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
426 là một giao diện nên có thể nhập khẳng định để triển khai cụ thể cửa sổ. Ví dụ: khi cửa sổ cố định đang được sử dụng, cửa sổ thuộc loại
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
429

Cửa sổ. Để truy cập vào cửa sổ có phần tử đầu vào, hãy thêm ____6416 vào đối số ngữ cảnh. Nếu một phần tử nằm trong nhiều cửa sổ [ví dụ: điều này sẽ xảy ra khi sử dụng

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
420], thì hàm sẽ được gọi nhiều lần cho phần tử, một lần cho mỗi cửa sổ

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
525

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
526

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
527

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
528

PaneInfo. Khi kích hoạt được sử dụng, Beam cung cấp đối tượng

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
432 chứa thông tin về kích hoạt hiện tại. Sử dụng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
432, bạn có thể xác định xem đây là lần kích hoạt sớm hay muộn và cửa sổ này đã kích hoạt bao nhiêu lần cho khóa này

PaneInfo. Khi kích hoạt được sử dụng, Beam cung cấp đối tượng

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
434 chứa thông tin về kích hoạt hiện tại. Sử dụng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
434, bạn có thể xác định xem đây là lần kích hoạt sớm hay muộn và cửa sổ này đã kích hoạt bao nhiêu lần cho khóa này. Việc triển khai tính năng này trong Python SDK chưa được hoàn thành đầy đủ;

PaneInfo. Khi kích hoạt được sử dụng, Beam cung cấp đối tượng

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
436 chứa thông tin về kích hoạt hiện tại. Sử dụng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
436, bạn có thể xác định xem đây là lần kích hoạt sớm hay muộn và cửa sổ này đã kích hoạt bao nhiêu lần cho khóa này

Cửa sổ. Để truy cập vào cửa sổ có phần tử đầu vào, hãy thêm ____6438 vào đối số ngữ cảnh. Sử dụng

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
436, bạn có thể xác định xem đây là lần kích hoạt sớm hay muộn và cửa sổ này đã kích hoạt bao nhiêu lần cho khóa này

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
529

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
530

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
531

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
532

Tùy chọn đường ống. Luôn có thể truy cập

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
913 cho quy trình hiện tại trong một phương thức quy trình bằng cách thêm nó làm tham số

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
533

Các phương thức

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
441 cũng có thể truy cập nhiều tham số này. Tất cả các tham số Dấu thời gian, Cửa sổ, khóa,
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
913,
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
624 và
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
444 đều có thể được truy cập theo phương thức
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
441. Ngoài ra, phương thức
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
441 có thể nhận tham số kiểu
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
447 cho biết bộ hẹn giờ dựa trên thời gian sự kiện hay thời gian xử lý. Bộ hẹn giờ được giải thích chi tiết hơn trong bài đăng trên blog Xử lý kịp thời [và có trạng thái] với Apache Beam

Hẹn giờ và trạng thái. Ngoài các tham số đã nói ở trên, các tham số Trạng thái và Hẹn giờ do người dùng xác định có thể được sử dụng trong DoFn có trạng thái. Bộ hẹn giờ và trạng thái được giải thích chi tiết hơn trong bài đăng trên blog Xử lý kịp thời [và có trạng thái] với Apache Beam

Hẹn giờ và trạng thái. Các tham số Trạng thái do người dùng xác định có thể được sử dụng trong DoFn có trạng thái. Bộ hẹn giờ chưa được triển khai trong Go SDK; . Sau khi được triển khai, các tham số Hẹn giờ do người dùng xác định có thể được sử dụng trong DoFn có trạng thái. Bộ hẹn giờ và trạng thái được giải thích chi tiết hơn trong bài đăng trên blog Xử lý kịp thời [và có trạng thái] với Apache Beam

Hẹn giờ và trạng thái. Tính năng này chưa được triển khai trong TypeScript SDK, nhưng chúng tôi hoan nghênh các đóng góp. Trong thời gian chờ đợi, các đường ống Bản mô tả muốn sử dụng trạng thái và bộ hẹn giờ có thể làm như vậy bằng cách sử dụng các biến đổi ngôn ngữ chéo

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
534

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
535

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
536

4. 6. biến đổi tổ hợp

Các phép biến đổi có thể có cấu trúc lồng nhau, trong đó một phép biến đổi phức tạp thực hiện nhiều phép biến đổi đơn giản hơn [chẳng hạn như nhiều biến đổi

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556,
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
515,
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
514 hoặc thậm chí các phép biến đổi hỗn hợp khác]. Các phép biến hình này được gọi là phép biến hình tổ hợp. Việc lồng nhiều biến đổi bên trong một biến đổi tổng hợp duy nhất có thể làm cho mã của bạn trở nên mô đun hơn và dễ hiểu hơn

Beam SDK đi kèm với nhiều biến đổi tổng hợp hữu ích. Xem các trang tham chiếu API để biết danh sách các biến đổi

  • Biến đổi Beam được viết sẵn cho Java
  • Biến đổi Beam được viết sẵn cho Python
  • Biến đổi Beam được viết sẵn cho Go

4. 6. 1. Một ví dụ biến đổi tổng hợp

Biến đổi

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
451 trong chương trình ví dụ WordCount là một ví dụ về biến đổi tổng hợp.
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
451 là một lớp con của
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
78 subclass bao gồm nhiều phép biến đổi lồng nhau.

Trong phương pháp

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
454 của nó, phép biến đổi The
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
451 áp dụng các thao tác biến đổi sau.

  1. Nó áp dụng một
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    556 trên đầu vào
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    73 của các dòng văn bản, tạo ra một đầu ra
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    73 của các từ riêng lẻ
  2. Nó áp dụng biến đổi thư viện Beam SDK
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    459 trên
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    73 từ, tạo ra một
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    73 cặp khóa/giá trị. Mỗi khóa đại diện cho một từ trong văn bản và mỗi giá trị đại diện cho số lần từ đó xuất hiện trong dữ liệu gốc

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
537

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
538

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
539

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
540

Ghi chú. Bởi vì bản thân

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
459 là một phép biến đổi tổ hợp, nên
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
451 cũng là một phép biến đổi tổ hợp lồng nhau

4. 6. 2. Tạo một biến đổi tổng hợp

Một PTransform trong Typescript SDK chỉ đơn giản là một chức năng chấp nhận và trả về các

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
548, chẳng hạn như các
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73

Để tạo biến đổi tổng hợp của riêng bạn, hãy tạo một lớp con của lớp

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
78 và ghi đè phương thức
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
454 để chỉ định logic xử lý thực tế. Sau đó, bạn có thể sử dụng biến đổi này giống như cách bạn sử dụng biến đổi tích hợp từ Beam SDK

Đối với các tham số loại lớp

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
78, bạn chuyển các loại
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 mà biến đổi của bạn lấy làm đầu vào và tạo ra làm đầu ra. Để lấy nhiều
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 làm đầu vào hoặc tạo nhiều
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 làm đầu ra, hãy sử dụng một trong các loại nhiều bộ sưu tập cho tham số loại có liên quan

Để tạo

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
78 tổng hợp của riêng bạn, hãy gọi phương thức
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
84 trên biến phạm vi đường ống hiện tại. Các phép biến đổi được thông qua sub-
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
84 mới này sẽ là một phần của cùng một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
78 tổng hợp

Để có thể sử dụng lại Tổng hợp của bạn, hãy xây dựng nó bên trong một hàm hoặc phương thức Go thông thường. Hàm này được truyền một phạm vi và PCollections đầu vào, đồng thời trả về bất kỳ PCCollections đầu ra nào mà nó tạo ra. Ghi chú. Các chức năng như vậy không thể được chuyển trực tiếp đến các chức năng

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556

Mẫu mã sau đây cho biết cách khai báo một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
78 chấp nhận một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 của
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
950 cho đầu vào và xuất ra một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 của
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
600

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
541

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
542

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
539

Trong lớp con

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
78 của bạn, bạn sẽ cần ghi đè phương thức
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
454. Phương thức
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
454 là nơi bạn thêm logic xử lý cho
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
78. Quyền ghi đè của bạn đối với
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
454 phải chấp nhận loại đầu vào phù hợp
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 làm tham số và chỉ định đầu ra
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 làm giá trị trả về

Mẫu mã sau đây cho thấy cách ghi đè

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
454 cho lớp
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
490 được khai báo trong ví dụ trước

Mẫu mã sau đây cho biết cách gọi PTransform tổng hợp

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
451, thêm nó vào quy trình của bạn

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
544

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
542

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
546

Miễn là bạn ghi đè phương thức

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
454 trong lớp con
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
78 của mình để chấp nhận [các] đầu vào thích hợp
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 và trả về [các] đầu ra tương ứng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73, thì bạn có thể bao gồm bao nhiêu biến đổi tùy thích. Các biến đổi này có thể bao gồm các biến đổi lõi, biến đổi tổng hợp hoặc các biến đổi có trong thư viện Beam SDK

Các

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
78 tổng hợp của bạn có thể bao gồm bao nhiêu biến đổi tùy thích. Các biến đổi này có thể bao gồm các biến đổi lõi, các biến đổi tổng hợp khác hoặc các biến đổi có trong thư viện Beam SDK. Họ cũng có thể tiêu thụ và trả lại bao nhiêu
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 nếu cần

Các tham số và giá trị trả về của biến đổi tổng hợp của bạn phải khớp với loại đầu vào ban đầu và loại trả về cuối cùng cho toàn bộ biến đổi, ngay cả khi dữ liệu trung gian của biến đổi thay đổi loại nhiều lần

Ghi chú. Phương thức

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
454 của
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
78 không có nghĩa là được gọi trực tiếp bởi người dùng biến đổi. Thay vào đó, bạn nên gọi phương thức
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
531 trên chính
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73, với biến đổi làm đối số. Điều này cho phép các biến đổi được lồng vào trong cấu trúc đường ống của bạn

4. 6. 3. Hướng dẫn Phong cách PTransform

Hướng dẫn về Phong cách PTransform chứa thông tin bổ sung không có ở đây, chẳng hạn như hướng dẫn về phong cách, hướng dẫn kiểm tra và ghi nhật ký cũng như các cân nhắc về ngôn ngữ cụ thể. Hướng dẫn này là điểm khởi đầu hữu ích khi bạn muốn viết các PTransform tổng hợp mới

5. Đường ống I/O

Khi bạn tạo một đường dẫn, bạn thường cần đọc dữ liệu từ một số nguồn bên ngoài, chẳng hạn như tệp hoặc cơ sở dữ liệu. Tương tự như vậy, bạn có thể muốn quy trình của mình xuất dữ liệu kết quả sang hệ thống lưu trữ bên ngoài. Beam cung cấp các biến đổi đọc và ghi cho một số loại lưu trữ dữ liệu phổ biến. Nếu bạn muốn quy trình của mình đọc hoặc ghi sang định dạng lưu trữ dữ liệu không được hỗ trợ bởi các biến đổi tích hợp, bạn có thể triển khai các biến đổi đọc và ghi của riêng mình

5. 1. Đọc dữ liệu đầu vào

Biến đổi đọc đọc dữ liệu từ một nguồn bên ngoài và trả về một đại diện dữ liệu

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 để đường dẫn của bạn sử dụng. Bạn có thể sử dụng biến đổi đọc tại bất kỳ thời điểm nào trong khi xây dựng quy trình của mình để tạo một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 mới, mặc dù nó sẽ phổ biến nhất khi bắt đầu quy trình của bạn

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
547

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
548

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
549

5. 2. Ghi dữ liệu đầu ra

Biến đổi ghi ghi dữ liệu trong

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 vào nguồn dữ liệu ngoài. Bạn thường sẽ sử dụng các biến đổi ghi ở cuối quy trình để xuất kết quả cuối cùng của quy trình. Tuy nhiên, bạn có thể sử dụng biến đổi ghi để xuất dữ liệu của
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 tại bất kỳ điểm nào trong quy trình của bạn

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
550

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
551

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
552

5. 3. Dữ liệu đầu vào và đầu ra dựa trên tệp

5. 3. 1. Đọc từ nhiều địa điểm

Nhiều biến đổi đọc hỗ trợ đọc từ nhiều tệp đầu vào khớp với toán tử toàn cầu mà bạn cung cấp. Lưu ý rằng các toán tử toàn cục dành riêng cho hệ thống tệp và tuân theo các mô hình nhất quán dành riêng cho hệ thống tệp. Ví dụ TextIO sau đây sử dụng toán tử toàn cầu [_______45006] để đọc tất cả các tệp đầu vào phù hợp có tiền tố “đầu vào-” và hậu tố “. csv” ở vị trí nhất định

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
553

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
554

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
555

Để đọc dữ liệu từ các nguồn khác nhau vào một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 duy nhất, hãy đọc từng nguồn một cách độc lập rồi sử dụng biến đổi Làm phẳng để tạo một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 duy nhất

5. 3. 2. Ghi vào nhiều tệp đầu ra

Đối với dữ liệu đầu ra dựa trên tệp, ghi biến đổi ghi vào nhiều tệp đầu ra theo mặc định. Khi bạn chuyển tên tệp đầu ra cho một biến đổi ghi, tên tệp được sử dụng làm tiền tố cho tất cả các tệp đầu ra mà biến đổi ghi tạo ra. Bạn có thể thêm một hậu tố vào mỗi tệp đầu ra bằng cách chỉ định một hậu tố

Ví dụ chuyển đổi ghi sau đây ghi nhiều tệp đầu ra vào một vị trí. Mỗi tệp có tiền tố “số”, thẻ số và hậu tố “. csv”

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
557

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
558

5. 4. Biến đổi I/O do tia cung cấp

Xem trang Biến đổi I/O do Beam cung cấp để biết danh sách các biến đổi I/O hiện có

6. lược đồ

Thông thường, các loại hồ sơ đang được xử lý có cấu trúc rõ ràng. Các nguồn Beam phổ biến tạo ra các đối tượng hàng JSON, Avro, Bộ đệm giao thức hoặc cơ sở dữ liệu; . Ngay cả trong một đường dẫn SDK, các POJO Java đơn giản [hoặc các cấu trúc tương đương trong các ngôn ngữ khác] thường được sử dụng làm các loại trung gian và chúng cũng có cấu trúc rõ ràng có thể được suy ra bằng cách kiểm tra lớp. Bằng cách hiểu cấu trúc của các bản ghi của quy trình, chúng tôi có thể cung cấp các API ngắn gọn hơn nhiều để xử lý dữ liệu

6. 1. Lược đồ là gì?

Hầu hết các bản ghi có cấu trúc đều có chung một số đặc điểm

  • Chúng có thể được chia nhỏ thành các trường được đặt tên riêng biệt. Các trường thường có tên chuỗi, nhưng đôi khi - như trong trường hợp bộ dữ liệu được lập chỉ mục - thay vào đó có các chỉ mục số
  • Có một danh sách giới hạn các kiểu nguyên thủy mà một trường có thể có. Chúng thường khớp với các kiểu nguyên thủy trong hầu hết các ngôn ngữ lập trình. int, dài, chuỗi, v.v.
  • Thường thì một loại trường có thể được đánh dấu là tùy chọn [đôi khi được gọi là nullable] hoặc bắt buộc

Các bản ghi thường có cấu trúc lồng nhau. Cấu trúc lồng nhau xảy ra khi bản thân một trường có các trường con, do đó, loại trường đó có một lược đồ. Các trường là kiểu mảng hoặc bản đồ cũng là một đặc điểm chung của các bản ghi có cấu trúc này

Ví dụ: hãy xem xét lược đồ sau, biểu thị các hành động trong một công ty thương mại điện tử hư cấu

Mua, tựa vào, bám vào

Tên trườngLoại trườngngười dùngIdSTRINGitemIdINT64shippingAddressROW[ShippingAddress]chi phíINT64giao dịchARRAY[ROW[Giao dịch]]

Địa chỉ giao hàng

Tên trườngLoại trườngđường phốĐịa chỉSTRINGthành phốSTRINGstatenullable STRINGCountrySTRINGpostCodeSTRING

Giao dịch

Tên trườngField TypebankSTRINGpurchaseAmountDOUBLE

Bản ghi sự kiện mua hàng được biểu thị bằng lược đồ mua hàng ở trên. Mỗi sự kiện mua hàng chứa một địa chỉ giao hàng, là một hàng lồng nhau chứa giản đồ riêng của nó. Mỗi giao dịch mua cũng chứa một loạt các giao dịch thẻ tín dụng [một danh sách, vì một giao dịch mua có thể được chia thành nhiều thẻ tín dụng]; .

Điều này cung cấp một mô tả trừu tượng về các loại liên quan, một loại được trừu tượng hóa khỏi bất kỳ ngôn ngữ lập trình cụ thể nào

Các lược đồ cung cấp cho chúng tôi một hệ thống loại cho các bản ghi Beam độc lập với bất kỳ loại ngôn ngữ lập trình cụ thể nào. Có thể có nhiều lớp Java đều có cùng một lược đồ [ví dụ: lớp Bộ đệm giao thức hoặc lớp POJO] và Beam sẽ cho phép chúng tôi chuyển đổi liền mạch giữa các loại này. Các lược đồ cũng cung cấp một cách đơn giản để suy luận về các loại trên các API ngôn ngữ lập trình khác nhau

Một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 với một lược đồ không cần phải có một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
966 được chỉ định, vì Beam biết cách mã hóa và giải mã các hàng Lược đồ;

6. 2. Lược đồ cho các loại ngôn ngữ lập trình

Mặc dù bản thân các lược đồ độc lập với ngôn ngữ, nhưng chúng được thiết kế để nhúng một cách tự nhiên vào các ngôn ngữ lập trình của Beam SDK đang được sử dụng. Điều này cho phép người dùng Beam tiếp tục sử dụng các kiểu gốc trong khi tận dụng lợi thế của việc Beam hiểu các lược đồ phần tử của họ

Trong Java, bạn có thể sử dụng tập hợp các lớp sau đây để biểu diễn lược đồ mua hàng. Beam sẽ tự động suy ra lược đồ chính xác dựa trên các thành viên của lớp

Trong Python, bạn có thể sử dụng tập hợp các lớp sau để biểu diễn lược đồ mua hàng. Beam sẽ tự động suy ra lược đồ chính xác dựa trên các thành viên của lớp

Trong Go, mã hóa lược đồ được sử dụng theo mặc định cho các loại cấu trúc, với các trường Đã xuất trở thành một phần của lược đồ. Beam sẽ tự động suy luận lược đồ dựa trên các trường và thẻ trường của cấu trúc cũng như thứ tự của chúng

Trong Bản mô tả, các đối tượng JSON được sử dụng để biểu thị dữ liệu của lược đồ. Thật không may, thông tin loại trong Bản mô tả không được truyền tới lớp thời gian chạy, vì vậy nó cần được chỉ định thủ công ở một số nơi [e. g. khi sử dụng đường dẫn ngôn ngữ chéo]

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
559

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
560

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
561

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
562

Sử dụng các lớp JavaBean như trên là một cách để ánh xạ lược đồ tới các lớp Java. Tuy nhiên, nhiều lớp Java có thể có cùng một lược đồ, trong trường hợp đó, các kiểu Java khác nhau thường có thể được sử dụng thay thế cho nhau. Beam sẽ thêm các chuyển đổi ẩn giữa các loại có lược đồ phù hợp. Ví dụ: lớp

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5011 ở trên có cùng lược đồ với lớp sau

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
563

Vì vậy, nếu chúng ta có hai

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 như sau

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
564

Sau đó, hai

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 này sẽ có cùng một lược đồ, mặc dù các kiểu Java của chúng sẽ khác nhau. Điều này có nghĩa là ví dụ hai đoạn mã sau là hợp lệ

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
565

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
566

Mặc dù trong cả hai trường hợp, tham số

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
623 khác với loại Java của
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73, vì các lược đồ giống nhau, Beam sẽ tự động thực hiện chuyển đổi. Biến đổi
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5016 tích hợp sẵn cũng có thể được sử dụng để dịch giữa các loại lược đồ tương đương trong Java, như chi tiết bên dưới

6. 3. Định nghĩa lược đồ

Lược đồ cho một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 xác định các phần tử của
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 đó dưới dạng một danh sách có thứ tự các trường được đặt tên. Mỗi trường có một tên, một loại và có thể là một tập hợp các tùy chọn người dùng. Loại trường có thể là nguyên thủy hoặc hỗn hợp. Sau đây là các loại nguyên thủy hiện được Beam hỗ trợ

TypeDescriptionBYTEAMột giá trị có chữ ký 8 bitINT16A Giá trị có chữ ký 16 bitINT32A Giá trị có chữ ký 32 bitINT64A Giá trị có chữ ký 64 bitDECIMAMột loại thập phân có độ chính xác tùy ýFLOATA Số dấu phẩy động IEEE 754 32 bitDOUBLEA Số dấu phẩy động IEEE 754 64 bitSTRINGA chuỗiDATETIMEA Dấu thời gian được biểu thị . Trong trường hợp này, trường sẽ có loại ROW và lược đồ lồng nhau sẽ là một thuộc tính của loại trường này.

A field can also reference a nested schema. In this case, the field will have type ROW, and the nested schema will be an attribute of this field type.

Ba loại bộ sưu tập được hỗ trợ dưới dạng các loại trường. Mảng, ITERABLE và MAP

  • ARRAY Điều này đại diện cho một loại giá trị lặp lại, trong đó các phần tử được lặp lại có thể có bất kỳ loại được hỗ trợ nào. Mảng của các hàng lồng nhau được hỗ trợ, cũng như mảng của mảng
  • ITERABLE Điều này rất giống với kiểu mảng, nó đại diện cho một giá trị được lặp lại, nhưng một giá trị trong đó danh sách đầy đủ các mục không được biết cho đến khi được lặp lại. Điều này dành cho trường hợp một iterable có thể lớn hơn bộ nhớ khả dụng và được hỗ trợ bởi bộ nhớ ngoài [ví dụ: điều này có thể xảy ra với iterable được trả về bởi một
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    514]. Các phần tử lặp lại có thể có bất kỳ loại được hỗ trợ nào
  • MAP Điều này đại diện cho một bản đồ kết hợp từ khóa đến giá trị. Tất cả các loại lược đồ đều được hỗ trợ cho cả khóa và giá trị. Không thể sử dụng các giá trị chứa loại bản đồ làm khóa trong bất kỳ thao tác nhóm nào

6. 4. các loại logic

Người dùng có thể mở rộng hệ thống loại lược đồ để thêm các loại logic tùy chỉnh có thể được sử dụng làm trường. Một loại logic được xác định bởi một mã định danh duy nhất và một đối số. Loại logic cũng chỉ định loại lược đồ cơ bản được sử dụng để lưu trữ, cùng với các chuyển đổi đến và từ loại đó. Ví dụ: một liên kết logic luôn có thể được biểu diễn dưới dạng một hàng với các trường có thể null, trong đó người dùng đảm bảo rằng chỉ một trong các trường đó được đặt tại một thời điểm. Tuy nhiên, điều này có thể tẻ nhạt và phức tạp để quản lý. Loại lô-gic OneOf cung cấp một lớp giá trị giúp quản lý loại dưới dạng liên kết dễ dàng hơn, trong khi vẫn sử dụng một hàng có các trường có thể rỗng làm bộ lưu trữ cơ bản của nó. Mỗi loại logic cũng có một mã định danh duy nhất, vì vậy chúng cũng có thể được giải thích bằng các ngôn ngữ khác. Thêm ví dụ về các loại logic được liệt kê dưới đây

6. 4. 1. Định nghĩa kiểu logic

Để xác định loại logic, bạn phải chỉ định loại Lược đồ được sử dụng để biểu thị loại cơ bản cũng như mã định danh duy nhất cho loại đó. Một loại logic áp đặt ngữ nghĩa bổ sung lên trên một loại lược đồ. Ví dụ: một loại logic để biểu thị dấu thời gian nano giây được biểu diễn dưới dạng lược đồ chứa trường INT64 và INT32. Chỉ riêng lược đồ này không nói bất cứ điều gì về cách diễn giải loại này, tuy nhiên, loại logic cho bạn biết rằng lược đồ này biểu thị dấu thời gian nano giây, với trường INT64 biểu thị giây và trường INT32 biểu thị nano giây

Các kiểu logic cũng được chỉ định bởi một đối số, cho phép tạo một lớp gồm các kiểu liên quan. Ví dụ: loại thập phân có độ chính xác giới hạn sẽ có đối số số nguyên cho biết có bao nhiêu chữ số chính xác được biểu thị. Đối số được biểu thị bằng một loại lược đồ, vì vậy bản thân nó có thể là một loại phức tạp

Trong Java, một kiểu logic được chỉ định là một lớp con của lớp

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5020. Một lớp Java tùy chỉnh có thể được chỉ định để biểu diễn kiểu logic và các hàm chuyển đổi phải được cung cấp để chuyển đổi qua lại giữa lớp Java này và biểu diễn kiểu Lược đồ bên dưới. Ví dụ: loại logic biểu thị dấu thời gian nano giây có thể được triển khai như sau

Trong Go, một loại logic được chỉ định với triển khai tùy chỉnh của giao diện

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5021. Ví dụ: nhà cung cấp loại logic đại diện cho dấu thời gian nano giây có thể được triển khai như sau

Trong Bản mô tả, một loại logic được xác định bởi giao diện LogicalTypeInfo liên kết URN của một loại logic với biểu diễn của nó và chuyển đổi của nó sang và từ biểu diễn này

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
567

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
568

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
569

6. 4. 2. Các loại logic hữu ích

Hiện tại SDK Python cung cấp các loại logic tiện lợi tối thiểu, ngoài việc xử lý

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5022

Hiện tại, SDK Go cung cấp các loại logic tiện lợi tối thiểu, ngoài việc xử lý các nguyên hàm số nguyên bổ sung và

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5023

Kiểu liệt kê

Trình tạo tiện ích này chưa tồn tại cho Python SDK

Trình tạo tiện lợi này chưa tồn tại cho Go SDK

Kiểu logic này cho phép tạo một kiểu liệt kê bao gồm một tập hợp các hằng số được đặt tên

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
570

Giá trị của trường này được lưu trữ trong hàng dưới dạng một loại INT32, tuy nhiên, loại logic xác định một loại giá trị cho phép bạn truy cập vào bảng liệt kê dưới dạng một chuỗi hoặc một giá trị. Ví dụ

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
571

Đưa ra một đối tượng hàng có trường liệt kê, bạn cũng có thể trích xuất trường dưới dạng giá trị liệt kê

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
572

Suy luận lược đồ tự động từ Java POJO và JavaBeans tự động chuyển đổi Java enum thành kiểu logic EnumerationType

OneOfType

Trình tạo tiện ích này chưa tồn tại cho Python SDK

Trình tạo tiện lợi này chưa tồn tại cho Go SDK

OneOfType cho phép tạo một loại kết hợp rời rạc trên một tập hợp các trường lược đồ. Ví dụ

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
573

Giá trị của trường này được lưu trữ trong hàng dưới dạng một loại Hàng khác, trong đó tất cả các trường được đánh dấu là có thể rỗng. Tuy nhiên, loại logic xác định đối tượng Giá trị chứa giá trị liệt kê cho biết trường nào đã được đặt và chỉ cho phép nhận trường đó

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
574

Trong ví dụ trên, chúng tôi đã sử dụng tên trường trong câu lệnh chuyển đổi để rõ ràng, tuy nhiên, giá trị số nguyên enum cũng có thể được sử dụng

6. 5. Tạo lược đồ

Để tận dụng các lược đồ, các

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 của bạn phải có một lược đồ đi kèm với nó. Thông thường, bản thân nguồn sẽ đính kèm lược đồ vào PCollection. Ví dụ: khi sử dụng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5025 để đọc các tệp Avro, nguồn có thể tự động suy ra lược đồ Beam từ lược đồ Avro và đính kèm lược đồ đó vào Beam
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73. Tuy nhiên, không phải tất cả các nguồn đều tạo ra các lược đồ. Ngoài ra, các đường ống Beam thường có các giai đoạn và loại trung gian và những loại này cũng có thể được hưởng lợi từ tính biểu cảm của các lược đồ

6. 5. 1. Suy luận lược đồ

Thích ứng cho
  • SDK Java
  • SDK Python
  • Truy cập SDK
  • SDK TypeScript

Thật không may, Beam không thể truy cập thông tin loại TypeScript khi chạy. Các lược đồ phải được khai báo thủ công với

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5027. Mặt khác, các hoạt động nhận biết lược đồ như
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
687 có thể được sử dụng mà không cần khai báo lược đồ rõ ràng

Beam có thể suy ra các lược đồ từ nhiều loại Java phổ biến. Chú thích

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5029 có thể được sử dụng để yêu cầu Beam suy luận các lược đồ từ một loại cụ thể. Chú thích lấy một đối số là
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5030 và các lớp
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5030 đã được tích hợp sẵn cho các kiểu Java phổ biến.
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5032 cũng có thể được gọi theo chương trình đối với các trường hợp không thực tế để chú thích chính loại Java

Java POJO

POJO [Đối tượng Java cũ đơn giản] là một đối tượng Java không bị ràng buộc bởi bất kỳ hạn chế nào ngoài Đặc tả ngôn ngữ Java. Một POJO có thể chứa các biến thành viên là nguyên hàm, là các POJO khác hoặc là các bản đồ bộ sưu tập hoặc mảng của chúng. POJO không phải mở rộng các lớp được chỉ định trước hoặc mở rộng bất kỳ giao diện cụ thể nào

Nếu một lớp POJO được chú thích bằng

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5033, Beam sẽ tự động suy ra một lược đồ cho lớp này. Các lớp lồng nhau được hỗ trợ giống như các lớp có các trường
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
983, mảng và
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
667

Ví dụ: chú thích cho lớp sau yêu cầu Beam suy ra một lược đồ từ lớp POJO này và áp dụng nó cho bất kỳ

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5036 nào

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
575

Chú thích

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5037 cho Beam biết rằng hàm tạo này có thể được sử dụng để tạo các phiên bản của TransactionPojo, giả sử rằng các tham số của hàm tạo có cùng tên với tên trường.
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5037 cũng có thể được sử dụng để chú thích các phương thức tĩnh của nhà máy trên lớp, cho phép hàm tạo được giữ ở chế độ riêng tư. Nếu không có chú thích
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5037 thì tất cả các trường phải không phải là cuối cùng và lớp phải có hàm tạo đối số bằng 0

Có một số chú thích hữu ích khác ảnh hưởng đến cách Beam suy luận các lược đồ. Theo mặc định, tên trường lược đồ được suy luận sẽ khớp với tên trường lớp. Tuy nhiên, có thể sử dụng

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5040 để chỉ định một tên khác sẽ được sử dụng cho trường lược đồ.
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5041 có thể được sử dụng để đánh dấu các trường lớp cụ thể là loại trừ khỏi lược đồ được suy luận. Ví dụ: thông thường có các trường tạm thời trong một lớp không được đưa vào lược đồ [e. g. lưu trữ giá trị băm vào bộ đệm để ngăn việc tính toán lại giá trị băm tốn kém] và có thể sử dụng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5041 để loại trừ các trường này. Lưu ý rằng các trường bị bỏ qua sẽ không được đưa vào mã hóa của các bản ghi này

Trong một số trường hợp, việc chú thích lớp POJO không thuận tiện, ví dụ: nếu POJO nằm trong một gói khác không thuộc sở hữu của tác giả đường ống Beam. Trong những trường hợp này, suy luận lược đồ có thể được kích hoạt theo chương trình trong chức năng chính của đường ống như sau

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
576

Đậu Java

Đậu Java là một tiêu chuẩn thực tế để tạo các lớp thuộc tính có thể tái sử dụng trong Java. Mặc dù tiêu chuẩn đầy đủ có nhiều đặc điểm, nhưng đặc điểm chính là tất cả các thuộc tính được truy cập thông qua các lớp getter và setter và định dạng tên cho các getter và setter này được chuẩn hóa. Một lớp Java Bean có thể được chú thích bằng

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5043 và Beam sẽ tự động suy ra một lược đồ cho lớp này. Ví dụ

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
577

Chú thích

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5037 có thể được sử dụng để chỉ định một hàm tạo hoặc một phương thức tĩnh của nhà máy, trong trường hợp đó, có thể bỏ qua hàm setters và hàm tạo đối số 0

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
578

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5040 và
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5041 có thể được sử dụng để thay đổi lược đồ được suy ra, giống như với các lớp POJO

Giá trị tự động

Các lớp giá trị Java nổi tiếng là khó tạo chính xác. Có rất nhiều bản tóm tắt mà bạn phải tạo để triển khai đúng một lớp giá trị. AutoValue là một thư viện phổ biến để dễ dàng tạo các lớp như vậy bằng cách triển khai một lớp cơ sở trừu tượng đơn giản

Beam có thể suy ra lược đồ từ lớp AutoValue. Ví dụ

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
579

Đây là tất cả những gì cần thiết để tạo một lớp AutoValue đơn giản và chú thích

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5029 ở trên yêu cầu Beam suy ra một lược đồ từ nó. Điều này cũng cho phép các phần tử AutoValue được sử dụng bên trong
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73s

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5040 và
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5041 có thể được sử dụng để thay đổi lược đồ suy ra

Beam có một vài cơ chế khác nhau để suy luận các lược đồ từ mã Python

các lớp NamedTuple

Lớp NamedTuple là một lớp Python bao bọc một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
544, gán tên cho từng phần tử và giới hạn nó ở một loại cụ thể. Beam sẽ tự động suy ra lược đồ cho PCollections với các loại đầu ra
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5052. Ví dụ

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
580

chùm tia. Hàng và Chọn

Ngoài ra còn có các phương pháp để tạo khai báo lược đồ đặc biệt. Trước tiên, bạn có thể sử dụng lambda trả về các phiên bản của

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5053

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
581

Đôi khi có thể ngắn gọn hơn để diễn đạt logic tương tự với biến đổi

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5054

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
582

Lưu ý rằng những khai báo này không bao gồm bất kỳ thông tin cụ thể nào về các loại trường

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5055 và
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5056, vì vậy Beam sẽ cố gắng suy ra thông tin loại. Nếu không thể, nó sẽ trở lại loại chung chung
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5057. Đôi khi điều này không lý tưởng, bạn có thể sử dụng phép ép kiểu để đảm bảo Beam suy luận đúng loại với
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5053 hoặc với
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5054

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583

Beam hiện chỉ phỏng đoán các lược đồ cho các trường đã xuất trong cấu trúc Go

cấu trúc

Beam sẽ tự động suy ra các lược đồ cho tất cả các cấu trúc Go được sử dụng làm phần tử PCollection và mặc định mã hóa chúng bằng mã hóa lược đồ

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
584

Các trường chưa được xuất sẽ bị bỏ qua và không thể được tự động suy ra như một phần của giản đồ. Các trường kiểu func, kênh, không an toàn. Con trỏ hoặc uintptr sẽ bị bỏ qua khi suy luận. Các trường của loại giao diện bị bỏ qua, trừ khi nhà cung cấp lược đồ được đăng ký cho chúng

Theo mặc định, tên trường lược đồ sẽ khớp với tên trường cấu trúc đã xuất. Trong ví dụ trên, “Ngân hàng” và “Số tiền mua hàng” là tên trường lược đồ. Tên trường lược đồ có thể được ghi đè bằng thẻ cấu trúc cho trường

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
585

Việc ghi đè tên trường lược đồ rất hữu ích cho việc chuyển đổi ngôn ngữ chéo về tính tương thích, vì các trường lược đồ có thể có các yêu cầu hoặc hạn chế khác với các trường đã xuất của Go

6. 6. Sử dụng chuyển đổi lược đồ

Lược đồ trên

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 cho phép thực hiện nhiều biến đổi quan hệ phong phú. Thực tế là mỗi bản ghi bao gồm các trường được đặt tên cho phép các tập hợp đơn giản và dễ đọc, tham chiếu các trường theo tên, tương tự như các tập hợp trong biểu thức SQL

Beam chưa hỗ trợ biến đổi Schema nguyên bản trong Go. Tuy nhiên, nó sẽ được thực hiện với hành vi sau

6. 6. 1. Cú pháp chọn trường

Ưu điểm của lược đồ là chúng cho phép tham chiếu các trường phần tử theo tên. Beam cung cấp cú pháp lựa chọn cho các trường tham chiếu, bao gồm các trường lồng nhau và lặp lại. Cú pháp này được sử dụng bởi tất cả các biến đổi lược đồ khi tham chiếu các trường mà chúng hoạt động trên đó. Cú pháp cũng có thể được sử dụng bên trong DoFn để chỉ định các trường lược đồ nào sẽ xử lý

Việc đánh địa chỉ các trường theo tên vẫn đảm bảo an toàn cho loại vì Beam sẽ kiểm tra xem các lược đồ có khớp với nhau tại thời điểm biểu đồ đường ống được tạo không. Nếu một trường được chỉ định không tồn tại trong lược đồ, quy trình bán hàng sẽ không khởi chạy được. Ngoài ra, nếu một trường được chỉ định với loại không khớp với loại của trường đó trong giản đồ, quy trình bán hàng sẽ không khởi chạy được

Các ký tự sau không được phép trong tên trường. . * [ ] { }

Các trường cấp cao nhất

Để chọn một trường ở cấp cao nhất của lược đồ, tên của trường được chỉ định. Ví dụ: để chỉ chọn id người dùng từ

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 giao dịch mua, người ta sẽ viết [sử dụng biến đổi
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5054]

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
586

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
587

trường lồng nhau

Hỗ trợ cho các trường lồng nhau chưa được phát triển cho Python SDK

Hỗ trợ cho các trường lồng nhau chưa được phát triển cho Go SDK

Các trường lồng nhau riêng lẻ có thể được chỉ định bằng toán tử dấu chấm. Ví dụ: để chỉ chọn mã bưu chính từ địa chỉ giao hàng, người ta sẽ viết

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
588

ký tự đại diện

Hỗ trợ ký tự đại diện chưa được phát triển cho SDK Python

Hỗ trợ ký tự đại diện chưa được phát triển cho Go SDK

Toán tử * có thể được chỉ định ở bất kỳ cấp độ lồng nhau nào để biểu thị tất cả các trường ở cấp độ đó. Ví dụ: để chọn tất cả các trường địa chỉ giao hàng, người ta sẽ viết

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
589

Mảng

Trường mảng, trong đó kiểu phần tử mảng là một hàng, cũng có thể có các trường con của kiểu phần tử được xử lý. Khi được chọn, kết quả là một mảng của loại trường con đã chọn. Ví dụ

Hỗ trợ cho các trường Mảng chưa được phát triển cho Python SDK

Hỗ trợ cho các trường Mảng chưa được phát triển cho Go SDK

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
590

Sẽ dẫn đến một hàng chứa trường mảng với phần tử kiểu chuỗi, chứa danh sách các ngân hàng cho mỗi giao dịch

Mặc dù nên sử dụng dấu ngoặc [] trong bộ chọn, nhưng để làm rõ rằng các phần tử mảng đang được chọn, chúng có thể được bỏ qua cho ngắn gọn. Trong tương lai, tính năng cắt mảng sẽ được hỗ trợ, cho phép lựa chọn các phần của mảng

bản đồ

Trường bản đồ, trong đó loại giá trị là một hàng, cũng có thể có các trường con của loại giá trị được xử lý. Khi được chọn, kết quả là một bản đồ trong đó các phím giống như trong bản đồ gốc nhưng giá trị là loại được chỉ định. Tương tự như mảng, nên sử dụng dấu ngoặc nhọn {} trong bộ chọn, để làm rõ rằng các phần tử giá trị bản đồ đang được chọn, chúng có thể được bỏ qua cho ngắn gọn. Trong tương lai, bộ chọn phím bản đồ sẽ được hỗ trợ, cho phép chọn các phím cụ thể từ bản đồ. Ví dụ, đưa ra lược đồ sau

mua theo loại

Tên trườngLoại trườngmua hàngMAP{STRING, ROW{PURCHASE}

Phần sau

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
591

Hỗ trợ cho các trường Bản đồ chưa được phát triển cho Python SDK

Hỗ trợ cho các trường Bản đồ chưa được phát triển cho Go SDK

Sẽ dẫn đến một hàng chứa trường bản đồ với chuỗi loại khóa và chuỗi loại giá trị. Bản đồ đã chọn sẽ chứa tất cả các khóa từ bản đồ gốc và các giá trị sẽ là userId có trong bản ghi mua hàng

Mặc dù nên sử dụng dấu ngoặc {} trong bộ chọn, nhưng để làm rõ rằng các phần tử giá trị bản đồ đang được chọn, chúng có thể được bỏ qua cho ngắn gọn. Trong tương lai, tính năng cắt bản đồ sẽ được hỗ trợ, cho phép chọn các phím cụ thể từ bản đồ

6. 6. 2. Biến đổi lược đồ

Beam cung cấp một tập hợp các biến đổi hoạt động tự nhiên trên các lược đồ. Các biến đổi này rất biểu cảm, cho phép lựa chọn và tổng hợp theo các trường lược đồ được đặt tên. Sau đây là một số ví dụ về biến đổi lược đồ hữu ích

Chọn đầu vào

Thông thường, một tính toán chỉ quan tâm đến một tập hợp con của các trường trong đầu vào

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73. Biến đổi
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5054 cho phép một người dễ dàng chỉ chiếu ra các trường quan tâm. Kết quả
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 có một lược đồ chứa từng trường được chọn làm trường cấp cao nhất. Có thể chọn cả trường cấp cao nhất và trường lồng nhau. Ví dụ: trong lược đồ Mua hàng, người ta chỉ có thể chọn các trường userId và streetAddress như sau

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
592

Hỗ trợ cho các trường lồng nhau chưa được phát triển cho Python SDK

Hỗ trợ cho các trường lồng nhau chưa được phát triển cho Go SDK

Kết quả

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 sẽ có lược đồ sau

Field NameField TypeuserIdSTRINGstreetAddressSTRING

Điều này cũng đúng với các lựa chọn ký tự đại diện. Sau đây

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
593

Hỗ trợ cho Ký tự đại diện chưa được phát triển cho Python SDK

Hỗ trợ cho Ký tự đại diện chưa được phát triển cho Go SDK

Sẽ dẫn đến lược đồ sau

Field NameField TypeuserIdSTRINGstreetAddressSTRINGcitySTRINGstatenullable STRINGcountrySTRINGpostCodeSTRING

Khi chọn các trường được lồng bên trong một mảng, quy tắc tương tự sẽ áp dụng để mỗi trường được chọn xuất hiện riêng biệt dưới dạng trường cấp cao nhất trong hàng kết quả. Điều này có nghĩa là nếu nhiều trường được chọn từ cùng một hàng lồng nhau, thì mỗi trường được chọn sẽ xuất hiện dưới dạng trường mảng của riêng nó. Ví dụ

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
594

Hỗ trợ cho các trường lồng nhau chưa được phát triển cho SDK Python

Hỗ trợ cho các trường lồng nhau chưa được phát triển cho Go SDK

Sẽ dẫn đến lược đồ sau

Tên trườngField TypebankARRAY[STRING]purchaseAmountARRAY[DOUBLE]

Lựa chọn ký tự đại diện tương đương với việc chọn riêng từng trường.

Chọn các trường được lồng bên trong bản đồ có cùng ngữ nghĩa như mảng. Nếu bạn chọn nhiều trường từ bản đồ thì mỗi trường đã chọn sẽ được mở rộng thành bản đồ của riêng nó ở cấp cao nhất. Điều này có nghĩa là tập hợp các khóa bản đồ sẽ được sao chép một lần cho mỗi trường đã chọn

Đôi khi các hàng lồng nhau khác nhau sẽ có các trường có cùng tên. Việc chọn nhiều trường trong số này sẽ dẫn đến xung đột tên vì tất cả các trường đã chọn được đặt trong cùng một lược đồ hàng. Khi tình huống này phát sinh, có thể sử dụng phương thức trình tạo

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5067 để cung cấp tên thay thế cho trường đã chọn

Một cách sử dụng khác của phép biến đổi Select là làm phẳng một lược đồ lồng nhau thành một lược đồ phẳng duy nhất. Ví dụ

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
595

Hỗ trợ cho các trường lồng nhau chưa được phát triển cho SDK Python

Hỗ trợ cho các trường lồng nhau chưa được phát triển cho Go SDK

Sẽ dẫn đến lược đồ sau

Field NameField TypeuserIdSTRINGitemIdSTRINGshippingAddress_streetAddressSTRINGshippingAddress_citynullable STRINGshippingAddress_stateSTRINGshippingAddress_countrySTRINGshippingAddress_postCodeSTRINGchi phíCentsINT64transactions_bankARRAY[STRING]transactions_purchaseAmountARRAY[DOUBLE]
Nhóm tổng hợp

Biến đổi

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5068 cho phép chỉ cần nhóm dữ liệu theo bất kỳ số lượng trường nào trong lược đồ đầu vào, áp dụng các tập hợp cho các nhóm đó và lưu trữ kết quả của các tập hợp đó trong một trường lược đồ mới. Đầu ra của biến đổi
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5068 có một lược đồ với một trường tương ứng với mỗi tập hợp được thực hiện

Biến đổi

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
687 cho phép chỉ cần nhóm dữ liệu theo bất kỳ số lượng trường nào trong lược đồ đầu vào, áp dụng các tập hợp cho các nhóm đó và lưu trữ kết quả của các tập hợp đó trong một trường lược đồ mới. Đầu ra của phép biến đổi
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
687 có một lược đồ với một trường tương ứng với mỗi tập hợp được thực hiện

Cách sử dụng đơn giản nhất của

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5068 chỉ định không có tập hợp nào, trong trường hợp đó, tất cả các đầu vào khớp với tập hợp trường đã cung cấp được nhóm lại với nhau thành trường
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5073. Ví dụ

Cách sử dụng đơn giản nhất của

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
687 chỉ định không có tập hợp nào, trong trường hợp đó, tất cả các đầu vào khớp với tập hợp các trường được cung cấp được nhóm lại với nhau thành một trường
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5073. Ví dụ

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
596

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
597

Hỗ trợ cho nhóm nhận biết lược đồ chưa được phát triển cho Go SDK

Lược đồ đầu ra của cái này là

Tên trườngField TypekeyROW{userId. STRING, ngân hàng. STRING}valuesITERABLE[ROW[Purchase]]

Trường khóa chứa khóa nhóm và trường giá trị chứa danh sách tất cả các giá trị khớp với khóa đó.

Tên của các trường khóa và giá trị trong lược đồ đầu ra có thể được kiểm soát bằng cách sử dụng trình tạo withKeyField và withValueField này, như sau

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
598

Việc áp dụng một hoặc nhiều tập hợp cho kết quả được nhóm là khá phổ biến. Mỗi tập hợp có thể chỉ định một hoặc nhiều trường để tổng hợp, hàm tổng hợp và tên của trường kết quả trong lược đồ đầu ra. Ví dụ: ứng dụng sau tính toán ba tập hợp được nhóm theo userId, với tất cả các tập hợp được biểu thị trong một lược đồ đầu ra duy nhất

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
599

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
600

Hỗ trợ cho nhóm nhận biết lược đồ chưa được phát triển cho Go SDK

Kết quả của phép tổng hợp này sẽ có lược đồ sau

Tên trườngField TypekeyROW{userId. STRING}valueROW{numPurchases. INT64, tổngSpendCent. INT64, mua hàng đầu. ARRAY[INT64]}

Thường thì

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5076 sẽ được sử dụng để làm phẳng kết quả thành một lược đồ phẳng, không lồng nhau.

tham gia

Beam hỗ trợ các phép nối bằng nhau trên lược đồ

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
737 - cụ thể là các phép nối trong đó điều kiện nối phụ thuộc vào sự bằng nhau của một tập hợp con các trường. Ví dụ: các ví dụ sau sử dụng lược đồ Mua hàng để kết hợp các giao dịch với các bài đánh giá có khả năng được liên kết với giao dịch đó [cả người dùng và sản phẩm đều khớp với đánh giá đó trong giao dịch]. Đây là “liên kết tự nhiên” - một trong đó các tên trường giống nhau được sử dụng ở cả phía bên trái và bên phải của liên kết - và được chỉ định bằng từ khóa
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5078

Hỗ trợ tham gia chưa được phát triển cho Python SDK

Hỗ trợ tham gia chưa được phát triển cho Go SDK

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
601

Lược đồ kết quả như sau

Field NameField TypelhsROW{Transaction}rhsROW{Review}

Mỗi hàng kết quả chứa một Giao dịch và một Đánh giá phù hợp với điều kiện tham gia.

Nếu các trường khớp trong hai lược đồ có tên khác nhau thì có thể sử dụng hàm on. Ví dụ: nếu lược đồ Đánh giá đặt tên các trường đó khác với lược đồ Giao dịch, thì chúng ta có thể viết như sau

Hỗ trợ tham gia chưa được phát triển cho Python SDK

Hỗ trợ tham gia chưa được phát triển cho Go SDK

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
602

Ngoài các phép nối bên trong, phép biến đổi Join hỗ trợ các phép nối ngoài đầy đủ, phép nối ngoài bên trái và phép nối ngoài bên phải

liên kết phức tạp

Mặc dù hầu hết các phép nối có xu hướng là phép nối nhị phân - nối hai đầu vào với nhau - đôi khi bạn có nhiều hơn hai luồng đầu vào cần được nối trên một khóa chung. Biến đổi

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5079 cho phép nối nhiều
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
737 lại với nhau dựa trên sự bằng nhau của các trường lược đồ. Mỗi
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 có thể được đánh dấu là bắt buộc hoặc tùy chọn trong bản ghi nối cuối cùng, cung cấp sự tổng quát hóa các phép nối ngoài cho các phép nối có nhiều hơn hai
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 đầu vào. Đầu ra có thể được mở rộng tùy chọn - cung cấp các bản ghi được nối riêng lẻ, như trong biến đổi
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5083. Đầu ra cũng có thể được xử lý ở định dạng không mở rộng - cung cấp khóa tham gia cùng với Iterables của tất cả các bản ghi từ mỗi đầu vào khớp với khóa đó

Hỗ trợ tham gia chưa được phát triển cho Python SDK

Hỗ trợ tham gia chưa được phát triển cho Go SDK

Lọc sự kiện

Biến đổi

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
671 có thể được định cấu hình với một tập hợp các vị từ, mỗi biến dựa trên một trường được chỉ định. Chỉ những bản ghi mà tất cả các vị từ trả về true mới vượt qua bộ lọc. Ví dụ như sau

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
603

Sẽ sản xuất tất cả các giao dịch mua từ Đức với giá mua lớn hơn hai mươi xu

Thêm các trường vào lược đồ

Biến đổi AddFields có thể được sử dụng để mở rộng lược đồ với các trường mới. Các hàng đầu vào sẽ được mở rộng sang lược đồ mới bằng cách chèn các giá trị null cho các trường mới, mặc dù có thể chỉ định các giá trị mặc định thay thế; . Có thể thêm các trường con lồng nhau bằng cách sử dụng cú pháp chọn trường, bao gồm các trường lồng nhau bên trong các mảng hoặc giá trị bản đồ

Ví dụ, ứng dụng sau

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
604

Kết quả trong một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 với lược đồ mở rộng. Tất cả các hàng và trường của đầu vào, cũng như các trường đã chỉ định được thêm vào lược đồ. Tất cả các hàng kết quả sẽ có các giá trị null được điền vào timeOfDaySeconds và shippingAddress. các trường deliveryNotes và một giá trị sai được điền vào cho các giao dịch. trường được gắn cờ

Xóa các trường khỏi lược đồ

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5086 cho phép loại bỏ các trường cụ thể khỏi lược đồ. Các hàng đầu vào sẽ bị cắt bớt lược đồ và mọi giá trị cho các trường bị loại bỏ sẽ bị xóa khỏi đầu ra. Các trường lồng nhau cũng có thể bị loại bỏ bằng cú pháp chọn trường

Ví dụ, đoạn mã sau

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
605

Kết quả là một bản sao của đầu vào với hai trường đó và các giá trị tương ứng của chúng đã bị xóa

Đổi tên các trường lược đồ

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5087 cho phép đổi tên các trường cụ thể trong lược đồ. Các giá trị trường trong các hàng đầu vào không thay đổi, chỉ lược đồ được sửa đổi. Biến đổi này thường được sử dụng để chuẩn bị các bản ghi cho đầu ra cho phần chứa nhận biết lược đồ, chẳng hạn như RDBMS, để đảm bảo rằng các tên trường lược đồ
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 khớp với tên của đầu ra. Nó cũng có thể được sử dụng để đổi tên các trường được tạo bởi các biến đổi khác để làm cho chúng dễ sử dụng hơn [tương tự như SELECT AS trong SQL]. Các trường lồng nhau cũng có thể được đổi tên bằng cú pháp chọn trường

Ví dụ, đoạn mã sau

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
606

Kết quả trong cùng một tập hợp các yếu tố đầu vào chưa sửa đổi, tuy nhiên lược đồ trên PCollection đã được thay đổi để đổi tên userId thành userIdentifier và shippingAddress. đường phốĐịa chỉ giao hàngĐịa chỉ. đường phố

Chuyển đổi giữa các loại

Như đã đề cập, Beam có thể tự động chuyển đổi giữa các loại Java khác nhau, miễn là các loại đó có lược đồ tương đương. Một cách để làm điều này là sử dụng biến đổi

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5016, như sau

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
607

Beam sẽ xác thực rằng lược đồ được suy luận cho

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5090 khớp với lược đồ của đầu vào
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73, sau đó sẽ truyền tới một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5092

Vì lớp

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5093 có thể hỗ trợ bất kỳ lược đồ nào, bất kỳ
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 nào có lược đồ đều có thể được chuyển thành một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 hàng, như sau

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
608

Nếu loại nguồn là lược đồ một trường, Convert cũng sẽ chuyển đổi thành loại trường nếu được hỏi, mở hộp hiệu quả. Ví dụ: đưa ra một lược đồ có một trường INT64, phần sau đây sẽ chuyển đổi nó thành một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5096

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
609

Trong mọi trường hợp, việc kiểm tra loại được thực hiện khi xây dựng biểu đồ đường ống và nếu các loại không khớp với lược đồ thì đường ống sẽ không khởi chạy được

6. 6. 3. Lược đồ trong ParDo

Một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 với lược đồ có thể áp dụng một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556, giống như bất kỳ
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 nào khác. Tuy nhiên, trình chạy Beam biết về các lược đồ khi áp dụng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556, cho phép chức năng bổ sung

chuyển đổi đầu vào

Beam chưa hỗ trợ chuyển đổi đầu vào trong Go

Vì Beam biết lược đồ của nguồn

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73, nên nó có thể tự động chuyển đổi các phần tử thành bất kỳ loại Java nào mà lược đồ phù hợp được biết đến. Ví dụ: sử dụng lược đồ Giao dịch nêu trên, giả sử chúng ta có
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 sau

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
610

Nếu không có lược đồ, thì

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583 được áp dụng sẽ phải chấp nhận một phần tử kiểu
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5104. Tuy nhiên vì có lược đồ, bạn có thể áp dụng DoFn sau

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
611

Mặc dù tham số

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
623 không khớp với kiểu Java của
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73, nhưng vì nó có lược đồ phù hợp nên Beam sẽ tự động chuyển đổi các phần tử. Nếu lược đồ không khớp, Beam sẽ phát hiện điều này tại thời điểm xây dựng biểu đồ và sẽ không thực hiện được với lỗi loại

Vì mọi lược đồ có thể được biểu diễn bằng một loại Hàng, nên Hàng cũng có thể được sử dụng ở đây

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
612

Lựa chọn đầu vào

Vì đầu vào có lược đồ nên bạn cũng có thể tự động chọn các trường cụ thể để xử lý trong DoFn

Với các giao dịch mua ở trên

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73, giả sử bạn chỉ muốn xử lý các trường userId và itemId. Bạn có thể thực hiện những điều này bằng cách sử dụng các biểu thức lựa chọn được mô tả ở trên, như sau

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
613

Bạn cũng có thể chọn các trường lồng nhau, như sau

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
614

Để biết thêm thông tin, hãy xem phần về biểu thức chọn trường. Khi chọn các lược đồ con, Beam sẽ tự động chuyển đổi sang bất kỳ loại lược đồ phù hợp nào, giống như khi đọc toàn bộ hàng

7. Mã hóa dữ liệu và an toàn loại

Thích ứng cho
  • SDK Java
  • SDK Python
  • Truy cập SDK
  • SDK TypeScript

Khi các trình chạy Beam thực thi đường ống của bạn, chúng thường cần cụ thể hóa dữ liệu trung gian trong các

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 của bạn, dữ liệu này yêu cầu chuyển đổi các phần tử sang và từ các chuỗi byte. Beam SDK sử dụng các đối tượng có tên là
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
966 để mô tả cách các phần tử của một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 nhất định có thể được mã hóa và giải mã

Lưu ý rằng các lập trình viên không liên quan đến việc phân tích cú pháp hoặc định dạng dữ liệu khi tương tác với các nguồn hoặc dữ liệu bên ngoài. Việc phân tích cú pháp hoặc định dạng như vậy thường được thực hiện rõ ràng, sử dụng các phép biến đổi như

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556 hoặc
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
666

Trong Beam SDK cho Java, loại

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
966 cung cấp các phương thức cần thiết để mã hóa và giải mã dữ liệu. SDK cho Java cung cấp một số lớp con Coder hoạt động với nhiều loại Java tiêu chuẩn, chẳng hạn như Integer, Long, Double, StringUtf8, v.v. Bạn có thể tìm thấy tất cả các lớp con Coder có sẵn trong gói Coder

Trong Beam SDK cho Python, loại

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
966 cung cấp các phương thức cần thiết để mã hóa và giải mã dữ liệu. SDK cho Python cung cấp một số lớp con Coder hoạt động với nhiều loại Python tiêu chuẩn, chẳng hạn như các loại nguyên thủy, Tuple, Iterable, StringUtf8, v.v. Bạn có thể tìm thấy tất cả các lớp con Coder có sẵn trong apache_beam. gói mã hóa

Các loại Go tiêu chuẩn như

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
601,
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5116
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5117,
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5118 và
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
596, v.v. được mã hóa bằng bộ lập trình dựng sẵn. Cấu trúc và con trỏ tới cấu trúc mặc định sử dụng mã hóa Beam Schema Row. Tuy nhiên, người dùng có thể xây dựng và đăng ký lập trình viên tùy chỉnh với
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5120. Bạn có thể tìm thấy các hàm Coder có sẵn trong gói coder

Các loại TypeScript tiêu chuẩn như

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5121,
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5122 và
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
596, v.v. được mã hóa bằng các trình lập trình dựng sẵn. Các đối tượng và mảng JSON được mã hóa thông qua mã hóa BSON. Đối với các loại này, không cần chỉ định bộ mã hóa trừ khi tương tác với các biến đổi ngôn ngữ chéo. Người dùng có thể xây dựng bộ lập trình tùy chỉnh bằng cách mở rộng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5124 để sử dụng với
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5125, nhưng các loại logic thường được ưu tiên cho trường hợp này

Lưu ý rằng lập trình viên không nhất thiết phải có 1. 1 mối quan hệ với các loại. Ví dụ: loại Số nguyên có thể có nhiều bộ mã hóa hợp lệ và dữ liệu đầu vào và đầu ra có thể sử dụng các bộ mã hóa Số nguyên khác nhau. Biến đổi có thể có dữ liệu đầu vào được nhập theo kiểu Số nguyên sử dụng BigEndianIntegerCoder và dữ liệu đầu ra được nhập theo kiểu Số nguyên sử dụng VarIntCoder

7. 1. Chỉ định lập trình viên

Beam SDK yêu cầu một người viết mã cho mỗi

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 trong quy trình của bạn. Trong hầu hết các trường hợp, Beam SDK có thể tự động suy ra một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
966 cho một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 dựa trên loại phần tử của nó hoặc biến đổi tạo ra nó, tuy nhiên, trong một số trường hợp, tác giả quy trình sẽ cần chỉ định rõ ràng một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
966 hoặc phát triển một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
966 cho

Bạn có thể đặt bộ mã hóa một cách rõ ràng cho một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 hiện có bằng cách sử dụng phương pháp
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5132. Lưu ý rằng bạn không thể gọi
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5133 trên một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 đã được hoàn thiện [e. g. bằng cách gọi
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5135 trên đó]

Bạn có thể lấy bộ mã hóa cho một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 hiện có bằng cách sử dụng phương pháp
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5137. Phương pháp này sẽ thất bại với một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
826 nếu một bộ mã hóa chưa được thiết lập và không thể suy ra được cho
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 đã cho

Beam SDK sử dụng nhiều cơ chế khác nhau khi cố gắng tự động suy ra

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
966 cho một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73

Mỗi đối tượng đường ống có một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5142.
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5142 đại diện cho ánh xạ các loại Java tới các bộ lập trình mặc định mà đường dẫn nên sử dụng cho các
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 của từng loại

Beam SDK cho Python có một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5142 đại diện cho ánh xạ các loại Python tới bộ mã hóa mặc định sẽ được sử dụng cho các
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 của mỗi loại

Beam SDK for Go cho phép người dùng đăng ký triển khai bộ mã hóa mặc định với

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5120

Theo mặc định, Beam SDK cho Java tự động suy ra

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
966 cho các phần tử của
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 do
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
78 tạo ra bằng cách sử dụng tham số loại từ đối tượng hàm của biến đổi, chẳng hạn như
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583. Ví dụ, trong trường hợp của
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556, một đối tượng hàm
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5153 chấp nhận một phần tử đầu vào kiểu
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
600 và tạo ra một phần tử đầu ra kiểu
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
950. Trong trường hợp như vậy, SDK dành cho Java sẽ tự động suy ra giá trị mặc định
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
966 cho đầu ra
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5157 [trong đường dẫn mặc định
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5142, giá trị này là
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5159]

Theo mặc định, Beam SDK cho Python tự động suy ra

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
966 cho các thành phần của đầu ra
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 bằng cách sử dụng các gợi ý kiểu chữ từ đối tượng hàm của biến đổi, chẳng hạn như
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583. Trong trường hợp của
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556, ví dụ: một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583 với các gợi ý kiểu chữ
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5165 và
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5166 chấp nhận một phần tử đầu vào kiểu int và tạo ra một phần tử đầu ra kiểu str. Trong trường hợp như vậy, Beam SDK cho Python sẽ tự động suy ra giá trị mặc định là
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
966 cho đầu ra
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 [trong đường ống dẫn mặc định là
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5142, giá trị này là
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5170]

Theo mặc định, Beam SDK cho Go sẽ tự động suy ra

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
966 cho các thành phần của đầu ra
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 theo đầu ra của đối tượng chức năng của biến đổi, chẳng hạn như
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583. Trong trường hợp của
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556, ví dụ: một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583 với các tham số là
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5176 chấp nhận một phần tử đầu vào thuộc loại
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
601 và tạo ra một phần tử đầu ra thuộc loại
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
596. Trong trường hợp như vậy, Beam SDK for Go sẽ tự động suy ra
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
966 mặc định cho đầu ra
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 là bộ mã hóa
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5181

Ghi chú. Nếu bạn tạo

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 của mình từ dữ liệu trong bộ nhớ bằng cách sử dụng biến đổi
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
94, bạn không thể dựa vào suy luận của bộ mã hóa và bộ mã hóa mặc định.
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
94 không có quyền truy cập vào bất kỳ thông tin đánh máy nào cho các đối số của nó và có thể không suy ra được bộ mã hóa nếu danh sách đối số chứa một giá trị có lớp thời gian chạy chính xác không có bộ mã hóa mặc định được đăng ký

Khi sử dụng ________ 094, cách đơn giản nhất để đảm bảo rằng bạn có bộ mã hóa chính xác là gọi ________ 45186 khi bạn áp dụng biến đổi

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
94

7. 2. Bộ mã hóa mặc định và CoderRegistry

Mỗi đối tượng Đường ống có một đối tượng

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5142, ánh xạ các loại ngôn ngữ tới bộ mã hóa mặc định mà đường ống sẽ sử dụng cho các loại đó. Bạn có thể tự mình sử dụng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5142 để tra cứu bộ mã hóa mặc định cho một loại nhất định hoặc để đăng ký bộ mã hóa mặc định mới cho một loại nhất định

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5142 chứa ánh xạ mặc định của các lập trình viên sang các loại JavaPython tiêu chuẩn cho bất kỳ đường dẫn nào bạn tạo bằng cách sử dụng . Bảng sau đây cho thấy ánh xạ tiêu chuẩn. JavaPython. The following table shows the standard mapping:

Java TypeDefault CoderDoubleDoubleCoderInstantInstantCoderIntegerVarIntCoderIterableIterableCoderKVKvCoderListListCoderMapMapCoderLongVarLongCoderStringStringUtf8CoderTableRowTableRowJsonCoderVoidVoidVoidCoderbyte[ ]ByteArrayCoderTimestampedValueTimestampedValueCoderPython TypeDefault CoderintVarIntCoderfloatCoderbyte[ ]ByteArrayCoderTimestampedValueTimestampedValueCoderPython TypeDefault CoderintVarIntCoderfloatCoderTutesCoderTuple

7. 2. 1. Tra cứu một bộ mã hóa mặc định

Bạn có thể sử dụng phương pháp

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5191 để xác định Coder mặc định cho một loại Java. Bạn có thể truy cập vào
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5142 cho một quy trình nhất định bằng cách sử dụng phương pháp
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5193. Điều này cho phép bạn xác định [hoặc thiết lập] Coder mặc định cho một loại Java trên cơ sở từng đường ống. tôi. e. “đối với quy trình này, hãy xác minh rằng các giá trị Số nguyên được mã hóa bằng cách sử dụng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5194. ”

Bạn có thể sử dụng phương pháp

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5195 để xác định Coder mặc định cho loại Python. Bạn có thể sử dụng ________ 45196 để truy cập ________ 45142. Điều này cho phép bạn xác định [hoặc đặt] Coder mặc định cho loại Python

Bạn có thể sử dụng hàm

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5198 để xác định Coder mặc định cho loại Go

7. 2. 2. Đặt bộ mã hóa mặc định cho một loại

Để đặt Coder mặc định cho loại JavaPython cho một quy trình cụ thể, bạn có được và . Bạn sử dụng phương thức ____45193 ______45196 để lấy đối tượng

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5142, sau đó sử dụng phương thức
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5203
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5204
to register a new
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
966 for the target type.

Để đặt Coder mặc định cho loại Go, bạn sử dụng chức năng

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5120 để đăng ký chức năng bộ mã hóa và giải mã cho loại mục tiêu. Tuy nhiên, các loại dựng sẵn như
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
601,
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
596,
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5117, v.v. không thể để bộ lập trình của chúng ghi đè lên

Mã ví dụ sau minh họa cách đặt Coder mặc định, trong trường hợp này là

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5194, cho Số nguyênint values for a pipeline.

Mã ví dụ sau minh họa cách đặt Bộ mã hóa tùy chỉnh cho các phần tử

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5211

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
615

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
616

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
617

7. 2. 3. Chú thích một loại dữ liệu tùy chỉnh với một bộ mã hóa mặc định

Nếu chương trình đường ống của bạn xác định loại dữ liệu tùy chỉnh, bạn có thể sử dụng chú thích

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5212 để chỉ định bộ mã hóa sẽ sử dụng với loại đó. Theo mặc định, Beam sẽ sử dụng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5213 sử dụng tuần tự hóa Java, nhưng nó có nhược điểm

  1. Nó không hiệu quả về kích thước và tốc độ mã hóa. Xem phần so sánh các phương thức tuần tự hóa Java này

  2. Nó không xác định. nó có thể tạo ra các mã hóa nhị phân khác nhau cho hai đối tượng tương đương

    Đối với các cặp khóa/giá trị, tính chính xác của các hoạt động dựa trên khóa [GroupByKey, Combine] và Trạng thái trên mỗi khóa phụ thuộc vào việc có một trình mã hóa xác định cho khóa

Bạn có thể sử dụng chú thích

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5212 để đặt mặc định mới như sau

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
618

Nếu bạn đã tạo một bộ mã hóa tùy chỉnh để phù hợp với loại dữ liệu của mình và bạn muốn sử dụng chú thích

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5212, thì lớp bộ mã hóa của bạn phải triển khai một phương thức xuất xưởng tĩnh
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5216

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
619

SDK Beam dành cho PythonGo không hỗ trợ chú thích các loại dữ liệu bằng bộ mã hóa mặc định. Nếu bạn muốn đặt bộ mã hóa mặc định, hãy sử dụng phương pháp được mô tả trong phần trước, Đặt bộ mã hóa mặc định cho một loại.

8. cửa sổ

Cửa sổ chia nhỏ một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 theo dấu thời gian của các phần tử riêng lẻ của nó. Các phép biến đổi tổng hợp nhiều phần tử, chẳng hạn như
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
514 và
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
515, hoạt động hoàn toàn trên cơ sở mỗi cửa sổ — chúng xử lý từng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 dưới dạng chuỗi liên tiếp của nhiều cửa sổ hữu hạn, mặc dù bản thân toàn bộ bộ sưu tập có thể có kích thước không giới hạn

Một khái niệm liên quan, được gọi là trình kích hoạt, xác định thời điểm phát ra kết quả tổng hợp khi dữ liệu không giới hạn đến. Bạn có thể sử dụng trình kích hoạt để tinh chỉnh chiến lược cửa sổ cho

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 của mình. Trình kích hoạt cho phép bạn xử lý dữ liệu đến muộn hoặc cung cấp kết quả sớm. Xem phần trình kích hoạt để biết thêm thông tin

8. 1. Khái niệm cơ bản về cửa sổ

Một số biến đổi Beam, chẳng hạn như

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
514 và
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
515, nhóm nhiều phần tử bằng một khóa chung. Thông thường, thao tác nhóm đó sẽ nhóm tất cả các phần tử có cùng khóa trong toàn bộ tập dữ liệu. Với tập dữ liệu không giới hạn, không thể thu thập tất cả các phần tử, vì các phần tử mới liên tục được thêm vào và có thể nhiều vô hạn [e. g. truyền dữ liệu]. Nếu bạn đang làm việc với các
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 không giới hạn, việc tạo cửa sổ đặc biệt hữu ích

Trong mô hình Beam, bất kỳ

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 nào [bao gồm cả các
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 không giới hạn] đều có thể được chia nhỏ thành các cửa sổ logic. Mỗi phần tử trong
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 được gán cho một hoặc nhiều cửa sổ theo chức năng tạo cửa sổ của
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 và mỗi cửa sổ riêng lẻ chứa một số phần tử hữu hạn. Nhóm các biến đổi sau đó xem xét từng phần tử của
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 trên cơ sở mỗi cửa sổ. Ví dụ:
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
514, nhóm hoàn toàn các phần tử của
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 theo khóa và cửa sổ

thận trọng. Hành vi cửa sổ mặc định của Beam là gán tất cả các phần tử của một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 cho một cửa sổ chung, duy nhất và loại bỏ dữ liệu muộn, ngay cả đối với các
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 không bị chặn. Trước khi bạn sử dụng biến đổi nhóm chẳng hạn như
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
514 trên một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 không giới hạn, bạn phải thực hiện ít nhất một trong các thao tác sau

  • Đặt chức năng cửa sổ không toàn cầu. Xem Đặt chức năng cửa sổ của PCollection của bạn
  • Đặt trình kích hoạt không mặc định. Điều này cho phép cửa sổ chung đưa ra kết quả trong các điều kiện khác, vì hành vi cửa sổ mặc định [chờ tất cả dữ liệu đến] sẽ không bao giờ xảy ra

Nếu bạn không đặt chức năng cửa sổ không toàn cục hoặc trình kích hoạt không mặc định cho

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 không giới hạn của mình và sau đó sử dụng biến đổi nhóm chẳng hạn như
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
514 hoặc
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
515, quy trình của bạn sẽ tạo ra lỗi khi xây dựng và công việc của bạn sẽ thất bại

8. 1. 1. ràng buộc cửa sổ

Sau khi bạn đặt chức năng tạo cửa sổ cho

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73, cửa sổ của các phần tử sẽ được sử dụng vào lần tiếp theo bạn áp dụng biến đổi nhóm cho
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 đó. Nhóm cửa sổ xảy ra trên cơ sở khi cần thiết. Nếu bạn đặt chức năng tạo cửa sổ bằng cách sử dụng biến đổi
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5241, thì mỗi phần tử được gán cho một cửa sổ, nhưng các cửa sổ không được xem xét cho đến khi
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
514 hoặc
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
515 tổng hợp trên một cửa sổ và khóa. Điều này có thể có các hiệu ứng khác nhau trên quy trình của bạn. Xem xét ví dụ về đường ống dẫn trong hình bên dưới

Hình 3. Đường ống áp dụng cửa sổ

Trong quy trình trên, chúng tôi tạo một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 không giới hạn bằng cách đọc một tập hợp các cặp khóa/giá trị bằng cách sử dụng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5245, sau đó áp dụng chức năng tạo cửa sổ cho tập hợp đó bằng cách sử dụng biến đổi
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5241. Sau đó, chúng tôi áp dụng một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556 cho tập hợp, rồi sau đó nhóm kết quả của
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556 đó bằng cách sử dụng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
514. Chức năng tạo cửa sổ không ảnh hưởng đến biến đổi
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556, bởi vì các cửa sổ không thực sự được sử dụng cho đến khi chúng cần thiết cho biến đổi
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
514. Tuy nhiên, các biến đổi tiếp theo được áp dụng cho kết quả của
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
514 – dữ liệu được nhóm theo cả khóa và cửa sổ

8. 1. 2. Cửa sổ với PCollections giới hạn

Bạn có thể sử dụng tính năng tạo cửa sổ với các tập dữ liệu có kích thước cố định trong các

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 có giới hạn. Tuy nhiên, lưu ý rằng cửa sổ chỉ xem xét các dấu thời gian ẩn được đính kèm với từng phần tử của
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 và các nguồn dữ liệu tạo tập dữ liệu cố định [chẳng hạn như
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5255] gán cùng một dấu thời gian cho mọi phần tử. Điều này có nghĩa là tất cả các phần tử theo mặc định là một phần của một cửa sổ chung, duy nhất

Để sử dụng cửa sổ với các tập dữ liệu cố định, bạn có thể chỉ định dấu thời gian của riêng mình cho từng thành phần. Để gán dấu thời gian cho các phần tử, hãy sử dụng biến đổi

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556 với
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583 để xuất từng phần tử bằng dấu thời gian mới [ví dụ: biến đổi WithTimestamp trong Beam SDK cho Java]

Để minh họa cách cửa sổ có giới hạn

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 có thể ảnh hưởng đến cách quy trình xử lý dữ liệu của bạn, hãy xem xét quy trình sau

hinh 4.

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
514 và
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556 không có cửa sổ, trên tập hợp có giới hạn

Trong quy trình trên, chúng tôi tạo một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 có giới hạn bằng cách đọc các dòng từ một tệp bằng cách sử dụng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5255. Sau đó, chúng tôi nhóm bộ sưu tập bằng cách sử dụng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
514 và áp dụng biến đổi
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556 cho
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 được nhóm. Trong ví dụ này,
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
514 tạo một tập hợp các khóa duy nhất và sau đó,
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556 được áp dụng chính xác một lần cho mỗi khóa

Lưu ý rằng ngay cả khi bạn không đặt chức năng tạo cửa sổ thì vẫn có một cửa sổ – tất cả các phần tử trong

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 của bạn được gán cho một cửa sổ chung duy nhất

Bây giờ, hãy xem xét cùng một đường dẫn, nhưng sử dụng chức năng tạo cửa sổ

Hình 5.

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
514 và
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556 có cửa sổ, trên tập hợp có giới hạn

Như trước đây, đường dẫn tạo một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 có giới hạn bằng cách đọc các dòng từ một tệp. Sau đó, chúng tôi đặt chức năng tạo cửa sổ cho
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 đó. Biến đổi
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
514 nhóm các phần tử của
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 theo cả khóa và cửa sổ, dựa trên chức năng cửa sổ. Biến đổi
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556 tiếp theo được áp dụng nhiều lần cho mỗi khóa, một lần cho mỗi cửa sổ

8. 2. Chức năng cửa sổ được cung cấp

Bạn có thể xác định các loại cửa sổ khác nhau để phân chia các phần tử của

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73. Beam cung cấp một số chức năng cửa sổ, bao gồm

  • Cửa sổ thời gian cố định
  • Cửa sổ thời gian trượt
  • Windows mỗi phiên
  • Một cửa sổ toàn cầu
  • Windows dựa trên lịch [không được hỗ trợ bởi Beam SDK cho Python hoặc Go]

Bạn cũng có thể xác định

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
842 của riêng mình nếu bạn có nhu cầu phức tạp hơn

Lưu ý rằng mỗi phần tử có thể thuộc về nhiều hơn một cửa sổ, tùy thuộc vào chức năng tạo cửa sổ mà bạn sử dụng. Ví dụ, cửa sổ thời gian trượt có thể tạo các cửa sổ chồng chéo trong đó một phần tử có thể được gán cho nhiều cửa sổ. Tuy nhiên, mỗi phần tử trong

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 chỉ có thể nằm trong một cửa sổ, vì vậy nếu một phần tử được gán cho nhiều cửa sổ, phần tử đó được sao chép về mặt khái niệm vào từng cửa sổ và mỗi phần tử giống hệt nhau ngoại trừ cửa sổ của nó

8. 2. 1. Cửa sổ thời gian cố định

Hình thức cửa sổ đơn giản nhất là sử dụng cửa sổ thời gian cố định. được cung cấp một dấu thời gian

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 có thể được cập nhật liên tục, mỗi cửa sổ có thể chụp [ví dụ] tất cả các phần tử có dấu thời gian rơi vào khoảng thời gian 30 giây

Cửa sổ thời gian cố định thể hiện khoảng thời gian nhất quán, khoảng thời gian không trùng lặp trong luồng dữ liệu. Xem xét các cửa sổ có thời lượng 30 giây. tất cả các phần tử trong

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 không giới hạn của bạn với các giá trị dấu thời gian từ 0. 00. 00 đến [nhưng không bao gồm] 0. 00. 30 thuộc về cửa sổ đầu tiên, các phần tử có giá trị dấu thời gian từ 0. 00. 30 đến [nhưng không bao gồm] 0. 01. 00 thuộc về cửa sổ thứ hai, v.v.

Hình 6. Cửa sổ thời gian cố định, thời lượng 30 giây

8. 2. 2. cửa sổ thời gian trượt

Cửa sổ thời gian trượt cũng biểu thị các khoảng thời gian trong luồng dữ liệu; . Ví dụ: mỗi cửa sổ có thể thu thập dữ liệu trị giá 60 giây nhưng cứ sau 30 giây lại có một cửa sổ mới bắt đầu. Tần suất mà các cửa sổ trượt bắt đầu được gọi là khoảng thời gian. Do đó, ví dụ của chúng tôi sẽ có thời lượng cửa sổ là 60 giây và khoảng thời gian là 30 giây

Vì nhiều cửa sổ chồng lên nhau nên hầu hết các thành phần trong tập dữ liệu sẽ thuộc về nhiều cửa sổ. Loại cửa sổ này rất hữu ích để lấy dữ liệu trung bình đang chạy;

Hình 7. Cửa sổ thời gian trượt, với thời lượng cửa sổ 1 phút và khoảng thời gian cửa sổ 30 giây

8. 2. 3. cửa sổ phiên

Hàm cửa sổ phiên xác định các cửa sổ chứa các phần tử nằm trong khoảng thời gian khoảng cách nhất định của phần tử khác. Cửa sổ phiên áp dụng trên cơ sở từng khóa và hữu ích cho dữ liệu được phân phối không đều theo thời gian. Ví dụ: luồng dữ liệu biểu thị hoạt động chuột của người dùng có thể có thời gian dài không hoạt động xen kẽ với mật độ nhấp chuột cao. Nếu dữ liệu đến sau thời gian khoảng cách tối thiểu được chỉ định, điều này sẽ bắt đầu bắt đầu một cửa sổ mới

Hình 8. Thời lượng phiên, với thời lượng khoảng cách tối thiểu. Lưu ý cách mỗi khóa dữ liệu có các cửa sổ khác nhau, theo phân phối dữ liệu của nó

8. 2. 4. Cửa sổ toàn cầu duy nhất

Theo mặc định, tất cả dữ liệu trong

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 được gán cho một cửa sổ chung duy nhất và dữ liệu muộn sẽ bị loại bỏ. Nếu tập dữ liệu của bạn có kích thước cố định, bạn có thể sử dụng cửa sổ chung mặc định cho
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 của mình

Bạn có thể sử dụng một cửa sổ chung duy nhất nếu bạn đang làm việc với tập dữ liệu không giới hạn [e. g. từ nguồn dữ liệu phát trực tuyến] nhưng hãy thận trọng khi áp dụng các biến đổi tổng hợp, chẳng hạn như

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
514 và
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
515. Cửa sổ chung duy nhất với trình kích hoạt mặc định thường yêu cầu phải có toàn bộ tập dữ liệu trước khi xử lý, điều này không thể thực hiện được với dữ liệu cập nhật liên tục. Để thực hiện tổng hợp trên một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 không giới hạn sử dụng cửa sổ chung, bạn nên chỉ định trình kích hoạt không mặc định cho
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 đó

8. 3. Đặt chức năng cửa sổ của PCollection của bạn

Bạn có thể đặt chức năng tạo cửa sổ cho

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 bằng cách áp dụng biến đổi
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5241. Khi bạn áp dụng biến đổi
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5241, bạn phải cung cấp một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
842.
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
842 xác định chức năng cửa sổ mà
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 của bạn sẽ sử dụng cho các biến đổi nhóm tiếp theo, chẳng hạn như cửa sổ thời gian cố định hoặc trượt

Khi bạn đặt chức năng cửa sổ, bạn cũng có thể muốn đặt trình kích hoạt cho

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 của mình. Trình kích hoạt xác định thời điểm mỗi cửa sổ riêng lẻ được tổng hợp và phát ra, đồng thời giúp tinh chỉnh cách thức hoạt động của chức năng cửa sổ đối với dữ liệu trễ và tính toán kết quả sớm. Xem phần trình kích hoạt để biết thêm thông tin

8. 3. 1. cửa sổ thời gian cố định

Đoạn mã ví dụ sau đây cho biết cách áp dụng

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5241 để chia một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 thành các cửa sổ cố định, mỗi cửa sổ dài 60 giây

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
620

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
621

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
622

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
623

8. 3. 2. cửa sổ thời gian trượt

Mã ví dụ sau cho biết cách áp dụng

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5241 để chia một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 thành các cửa sổ thời gian trượt. Mỗi cửa sổ dài 30 giây và một cửa sổ mới bắt đầu cứ sau 5 giây

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
624

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
625

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
626

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
627

8. 3. 3. cửa sổ phiên

Mã ví dụ sau đây cho biết cách áp dụng

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5241 để chia
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 thành các cửa sổ phiên, trong đó mỗi phiên phải được phân tách bằng khoảng cách thời gian ít nhất 10 phút [600 giây]

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
628

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
629

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
630

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
631

Lưu ý rằng các phiên là theo từng khóa — mỗi khóa trong bộ sưu tập sẽ có các nhóm phiên riêng tùy thuộc vào phân phối dữ liệu

8. 3. 4. Cửa sổ toàn cầu duy nhất

Nếu

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 của bạn bị giới hạn [kích thước cố định], bạn có thể gán tất cả các phần tử cho một cửa sổ chung duy nhất. Mã ví dụ sau đây cho biết cách đặt một cửa sổ toàn cục duy nhất cho một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
632

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
633

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
634

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
635

8. 4. Hình mờ và dữ liệu muộn

Trong bất kỳ hệ thống xử lý dữ liệu nào, có một độ trễ nhất định giữa thời điểm một sự kiện dữ liệu xảy ra ["thời gian sự kiện", được xác định bởi dấu thời gian trên chính phần tử dữ liệu] và thời gian phần tử dữ liệu thực tế được xử lý ở bất kỳ giai đoạn nào trong . Ngoài ra, không có gì đảm bảo rằng các sự kiện dữ liệu sẽ xuất hiện trong quy trình bán hàng của bạn theo đúng thứ tự mà chúng được tạo

Ví dụ: giả sử chúng ta có một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 đang sử dụng cửa sổ thời gian cố định, với cửa sổ dài năm phút. Đối với mỗi cửa sổ, Beam phải thu thập tất cả dữ liệu có dấu thời gian của sự kiện trong phạm vi cửa sổ nhất định [từ 0. 00 và 4. 59 trong cửa sổ đầu tiên chẳng hạn]. Dữ liệu có dấu thời gian nằm ngoài phạm vi đó [dữ liệu từ 5. 00 trở lên] thuộc về một cửa sổ khác

Tuy nhiên, dữ liệu không phải lúc nào cũng được đảm bảo đến theo một đường ống theo thứ tự thời gian hoặc luôn đến theo các khoảng thời gian có thể dự đoán được. Beam theo dõi một hình mờ, đó là khái niệm của hệ thống về thời điểm tất cả dữ liệu trong một cửa sổ nhất định có thể được đưa vào đường ống. Sau khi hình mờ đi qua cuối cửa sổ, bất kỳ phần tử nào khác xuất hiện cùng với dấu thời gian trong cửa sổ đó đều được coi là dữ liệu muộn

Từ ví dụ của chúng tôi, giả sử chúng tôi có một hình mờ đơn giản giả định thời gian trễ khoảng 30 giây giữa dấu thời gian dữ liệu [thời gian sự kiện] và thời gian dữ liệu xuất hiện trong đường ống [thời gian xử lý], sau đó Beam sẽ đóng cửa sổ đầu tiên ở mức 5. 30. Nếu một bản ghi dữ liệu đến lúc 5. 34, nhưng với dấu thời gian sẽ đưa nó vào 0. 00-4. 59 cửa sổ [giả sử, 3. 38], thì bản ghi đó là dữ liệu trễ

Ghi chú. Để đơn giản, chúng tôi giả định rằng chúng tôi đang sử dụng một hình mờ rất đơn giản để ước tính thời gian trễ. Trên thực tế, nguồn dữ liệu của

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 của bạn xác định hình mờ và hình mờ có thể chính xác hoặc phức tạp hơn

Cấu hình cửa sổ mặc định của Beam cố gắng xác định thời điểm tất cả dữ liệu đã đến [dựa trên loại nguồn dữ liệu] và sau đó chuyển hình mờ qua cuối cửa sổ. Cấu hình mặc định này không cho phép dữ liệu trễ. Trình kích hoạt cho phép bạn sửa đổi và tinh chỉnh chiến lược tạo cửa sổ cho một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73. Bạn có thể sử dụng trình kích hoạt để quyết định thời điểm mỗi cửa sổ riêng lẻ tổng hợp và báo cáo kết quả của nó, bao gồm cả cách cửa sổ phát ra các phần tử muộn

8. 4. 1. Quản lý dữ liệu muộn

Bạn có thể cho phép dữ liệu trễ bằng cách gọi hoạt động

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5305 khi bạn đặt chiến lược cửa sổ của
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73. Ví dụ mã sau minh họa chiến lược tạo cửa sổ sẽ cho phép dữ liệu trễ tối đa hai ngày sau khi kết thúc cửa sổ

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
636

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
637

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
638

Khi bạn đặt

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5305 trên một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73, độ trễ được phép đó sẽ lan truyền tới bất kỳ
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 tiếp theo nào bắt nguồn từ
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 đầu tiên mà bạn đã áp dụng độ trễ được phép cho. Nếu bạn muốn thay đổi độ trễ được phép sau này trong quy trình bán hàng của mình, bạn phải làm như vậy một cách rõ ràng bằng cách áp dụng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5311

8. 5. Thêm dấu thời gian vào các phần tử của PCollection

Nguồn không giới hạn cung cấp dấu thời gian cho từng phần tử. Tùy thuộc vào nguồn không giới hạn của bạn, bạn có thể cần định cấu hình cách trích xuất dấu thời gian từ luồng dữ liệu thô

Tuy nhiên, các nguồn có giới hạn [chẳng hạn như tệp từ

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5255] không cung cấp dấu thời gian. Nếu bạn cần dấu thời gian, bạn phải thêm chúng vào các phần tử của
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73

Bạn có thể gán dấu thời gian mới cho các phần tử của

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 bằng cách áp dụng biến đổi ParDo để xuất ra các phần tử mới có dấu thời gian mà bạn đã đặt

Một ví dụ có thể là nếu quy trình của bạn đọc các bản ghi nhật ký từ một tệp đầu vào và mỗi bản ghi nhật ký bao gồm một trường dấu thời gian; . Bạn có thể phân tích cú pháp trường dấu thời gian từ mỗi bản ghi và sử dụng biến đổi

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556 với
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583 để đính kèm dấu thời gian vào từng thành phần trong
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 của bạn

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
639

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
640

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
641

9. Gây nên

Ghi chú. API kích hoạt trong Beam SDK for Go hiện đang thử nghiệm và có thể thay đổi

Khi thu thập và nhóm dữ liệu vào các cửa sổ, Beam sử dụng trình kích hoạt để xác định thời điểm phát ra kết quả tổng hợp của từng cửa sổ [được gọi là ngăn]. Nếu bạn sử dụng cấu hình cửa sổ mặc định và trình kích hoạt mặc định của Beam, thì Beam sẽ xuất kết quả tổng hợp khi ước tính tất cả dữ liệu đã đến và loại bỏ tất cả dữ liệu tiếp theo cho cửa sổ đó

Bạn có thể đặt trình kích hoạt cho các

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 của mình để thay đổi hành vi mặc định này. Beam cung cấp một số trình kích hoạt dựng sẵn mà bạn có thể đặt

  • Trình kích hoạt thời gian sự kiện. Các trình kích hoạt này hoạt động theo thời gian của sự kiện, như được biểu thị bằng dấu thời gian trên mỗi phần tử dữ liệu. Trình kích hoạt mặc định của Beam dựa trên thời gian của sự kiện
  • Kích hoạt thời gian xử lý. Các trình kích hoạt này hoạt động theo thời gian xử lý – thời điểm phần tử dữ liệu được xử lý ở bất kỳ giai đoạn cụ thể nào trong quy trình
  • Trình kích hoạt theo hướng dữ liệu. Các trình kích hoạt này hoạt động bằng cách kiểm tra dữ liệu khi dữ liệu đến trong mỗi cửa sổ và kích hoạt khi dữ liệu đó đáp ứng một thuộc tính nhất định. Hiện tại, trình kích hoạt theo hướng dữ liệu chỉ hỗ trợ kích hoạt sau một số phần tử dữ liệu nhất định
  • kích hoạt tổng hợp. Các trình kích hoạt này kết hợp nhiều trình kích hoạt theo nhiều cách khác nhau

Ở cấp độ cao, trình kích hoạt cung cấp hai khả năng bổ sung so với việc chỉ xuất ra ở cuối cửa sổ

  • Trình kích hoạt cho phép Beam phát ra kết quả sớm, trước khi tất cả dữ liệu trong một cửa sổ nhất định đến. Ví dụ: phát ra sau một khoảng thời gian nhất định hoặc sau khi một số phần tử nhất định đến
  • Trình kích hoạt cho phép xử lý dữ liệu muộn bằng cách kích hoạt sau khi hình mờ thời gian sự kiện đi qua cuối cửa sổ

Những khả năng này cho phép bạn kiểm soát luồng dữ liệu của mình và cân bằng giữa các yếu tố khác nhau tùy thuộc vào trường hợp sử dụng của bạn

  • sự hoàn thiện. Việc có tất cả dữ liệu trước khi tính toán kết quả quan trọng như thế nào?
  • độ trễ. Bạn muốn chờ dữ liệu trong bao lâu?
  • Phí tổn. Bạn sẵn sàng chi bao nhiêu tiền/sức mạnh tính toán để giảm độ trễ?

Ví dụ: một hệ thống yêu cầu các bản cập nhật nhạy cảm với thời gian có thể sử dụng trình kích hoạt dựa trên thời gian nghiêm ngặt phát ra một cửa sổ sau mỗi N giây, đánh giá tính kịp thời hơn tính đầy đủ của dữ liệu. Một hệ thống coi trọng tính đầy đủ của dữ liệu hơn thời gian chính xác của kết quả có thể chọn sử dụng trình kích hoạt mặc định của Beam, kích hoạt ở cuối cửa sổ

Bạn cũng có thể đặt trình kích hoạt cho một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 không giới hạn sử dụng một cửa sổ chung duy nhất cho chức năng tạo cửa sổ của nó. Điều này có thể hữu ích khi bạn muốn quy trình của mình cung cấp các bản cập nhật định kỳ trên tập dữ liệu không giới hạn — ví dụ: mức trung bình đang chạy của tất cả dữ liệu được cung cấp cho thời điểm hiện tại, được cập nhật N giây hoặc mỗi N phần tử

9. 1. Trình kích hoạt thời gian sự kiện

Trình kích hoạt

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5320 hoạt động vào thời gian diễn ra sự kiện. Trình kích hoạt
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5320 phát ra nội dung của cửa sổ sau khi hình mờ đi qua cuối cửa sổ, dựa trên dấu thời gian được đính kèm với các phần tử dữ liệu. Hình mờ là thước đo tiến độ toàn cầu và là khái niệm của Beam về tính đầy đủ của đầu vào trong quy trình của bạn tại bất kỳ điểm nào. ______45322
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5320
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5324
chỉ kích hoạt khi hình mờ đi qua cuối cửa sổ.

Ngoài ra, bạn có thể định cấu hình trình kích hoạt kích hoạt nếu quy trình của bạn nhận dữ liệu trước hoặc sau khi kết thúc cửa sổ

Ví dụ sau đây cho thấy một kịch bản thanh toán và sử dụng cả kích hoạt sớm và muộn

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
642

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
643

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
644

9. 1. 1. Trình kích hoạt mặc định

Trình kích hoạt mặc định cho

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 dựa trên thời gian của sự kiện và phát ra kết quả của cửa sổ khi hình mờ của Beam đi qua cuối cửa sổ, sau đó kích hoạt mỗi khi có dữ liệu trễ

Tuy nhiên, nếu bạn đang sử dụng cả cấu hình cửa sổ mặc định và trình kích hoạt mặc định, trình kích hoạt mặc định sẽ phát chính xác một lần và dữ liệu muộn sẽ bị loại bỏ. Điều này là do cấu hình cửa sổ mặc định có giá trị độ trễ cho phép là 0. Xem phần Xử lý dữ liệu muộn để biết thông tin về cách sửa đổi hành vi này

9. 2. Kích hoạt thời gian xử lý

Trình kích hoạt

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5326 hoạt động theo thời gian xử lý. Ví dụ: trình kích hoạt ____45327 ______45326 ____45329 phát ra một cửa sổ sau một khoảng thời gian nhất định . Thời gian xử lý được xác định bởi đồng hồ hệ thống, thay vì dấu thời gian của phần tử dữ liệu.

Trình kích hoạt

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5326 hữu ích để kích hoạt kết quả sớm từ một cửa sổ, đặc biệt là cửa sổ có khung thời gian lớn, chẳng hạn như một cửa sổ toàn cầu

9. 3. Trình kích hoạt theo hướng dữ liệu

Beam cung cấp một trình kích hoạt theo hướng dữ liệu, ______45331 ____45332

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5333. This trigger works on an element count; it fires after the current pane has collected at least N elements. This allows a window to emit early results [before all the data has accumulated], which can be particularly useful if you are using a single global window.

Ví dụ: điều quan trọng cần lưu ý là nếu bạn chỉ định ____45334 AfterCount[50] . Nếu 32 yếu tố quan trọng đối với bạn, hãy cân nhắc sử dụng trình kích hoạt tổng hợp để kết hợp nhiều điều kiện. Điều này cho phép bạn chỉ định nhiều điều kiện bắn, chẳng hạn như “bắn khi tôi nhận được 50 phần tử hoặc cứ sau 1 giây”. and only 32 elements arrive, those 32 elements sit around forever. If the 32 elements are important to you, consider using composite triggers to combine multiple conditions. This allows you to specify multiple firing conditions such as “fire either when I receive 50 elements, or every 1 second”.

9. 4. Đặt trình kích hoạt

Khi bạn đặt chức năng tạo cửa sổ cho

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 bằng cách sử dụng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5241
____45338
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5339
transform, you can also specify a trigger.

Bạn đặt [các] trình kích hoạt cho một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 bằng cách gọi phương thức
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5341 dựa trên kết quả của biến đổi
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5342 của bạn. Mẫu mã này đặt trình kích hoạt dựa trên thời gian cho
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73, trình kích hoạt này sẽ đưa ra kết quả một phút sau khi phần tử đầu tiên trong cửa sổ đó được xử lý. Dòng cuối cùng trong mẫu mã,
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5344, đặt chế độ tích lũy của cửa sổ

Bạn đặt [các] trình kích hoạt cho một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 bằng cách đặt tham số
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5346 khi bạn sử dụng biến đổi
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5338. Mẫu mã này đặt trình kích hoạt dựa trên thời gian cho
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73, trình kích hoạt này sẽ đưa ra kết quả một phút sau khi phần tử đầu tiên trong cửa sổ đó được xử lý. Tham số
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5349 đặt chế độ tích lũy của cửa sổ

Bạn đặt [các] trình kích hoạt cho một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 bằng cách chuyển tham số
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5351 khi bạn sử dụng biến đổi
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5339. Mẫu mã này đặt trình kích hoạt dựa trên thời gian cho
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73, trình kích hoạt này sẽ đưa ra kết quả một phút sau khi phần tử đầu tiên trong cửa sổ đó được xử lý. Tham số
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5354 đặt chế độ tích lũy của cửa sổ

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
645

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
646

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
647

9. 4. 1. Chế độ tích lũy cửa sổ

Khi bạn chỉ định trình kích hoạt, bạn cũng phải đặt chế độ tích lũy của cửa sổ. Khi trình kích hoạt kích hoạt, nó sẽ phát ra nội dung hiện tại của cửa sổ dưới dạng một ngăn. Vì trình kích hoạt có thể kích hoạt nhiều lần nên chế độ tích lũy sẽ xác định xem hệ thống có tích lũy các ô cửa sổ khi trình kích hoạt kích hoạt hay loại bỏ chúng

Để đặt một cửa sổ tích lũy các ô được tạo khi trình kích hoạt kích hoạt, hãy gọi

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5355 khi bạn đặt trình kích hoạt. Để đặt một cửa sổ loại bỏ các ô đã kích hoạt, hãy gọi
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5344

Để đặt cửa sổ tích lũy các ô được tạo khi trình kích hoạt kích hoạt, hãy đặt tham số

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5349 thành
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5358 khi bạn đặt kích hoạt. Để đặt một cửa sổ loại bỏ các ô đã bắn, hãy đặt
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5349 thành
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5360

Để đặt cửa sổ tích lũy các ô được tạo khi trình kích hoạt kích hoạt, hãy đặt tham số

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5354 thành
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5362 khi bạn đặt trình kích hoạt. Để đặt một cửa sổ loại bỏ các ô đã bắn, hãy đặt
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5354 thành
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5364

Hãy xem một ví dụ sử dụng

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 với cửa sổ thời gian cố định và trình kích hoạt dựa trên dữ liệu. Đây là điều bạn có thể làm nếu, ví dụ: mỗi cửa sổ biểu thị mức trung bình đang chạy trong mười phút, nhưng bạn muốn hiển thị giá trị hiện tại của mức trung bình trong giao diện người dùng thường xuyên hơn mười phút một lần. Chúng tôi sẽ giả định các điều kiện sau

  • await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    73 sử dụng cửa sổ thời gian cố định 10 phút
  • await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    73 có trình kích hoạt lặp lại sẽ kích hoạt mỗi khi 3 phần tử đến

Sơ đồ sau hiển thị các sự kiện dữ liệu cho khóa X khi chúng đến PCollection và được gán cho các cửa sổ. Để sơ đồ đơn giản hơn một chút, chúng ta sẽ giả định rằng tất cả các sự kiện đều đến trong quy trình theo thứ tự

9. 4. 1. 1. chế độ tích lũy

Nếu trình kích hoạt của chúng tôi được đặt ở chế độ tích lũy, thì trình kích hoạt sẽ phát ra các giá trị sau mỗi lần kích hoạt. Hãy nhớ rằng trình kích hoạt sẽ kích hoạt mỗi khi ba yếu tố đến

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
6489. 4. 1. 2. chế độ loại bỏ

Nếu trình kích hoạt của chúng tôi được đặt ở chế độ loại bỏ, trình kích hoạt sẽ phát ra các giá trị sau trên mỗi lần kích hoạt

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
649

9. 4. 2. Xử lý dữ liệu muộn

Nếu bạn muốn quy trình của mình xử lý dữ liệu đến sau khi hình mờ đi qua cuối cửa sổ, bạn có thể áp dụng độ trễ cho phép khi đặt cấu hình cửa sổ của mình. Điều này giúp trình kích hoạt của bạn có cơ hội phản ứng với dữ liệu muộn. Nếu độ trễ cho phép được đặt, trình kích hoạt mặc định sẽ đưa ra kết quả mới ngay lập tức bất cứ khi nào có dữ liệu trễ

Bạn đặt độ trễ cho phép bằng cách sử dụng ______45368 ____45369

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5370 when you set your windowing function:

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
650

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
651

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
652

Độ trễ cho phép này lan truyền đến tất cả các

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 được tạo ra do áp dụng các phép biến đổi cho
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 ban đầu. Nếu bạn muốn thay đổi độ trễ được phép sau này trong quy trình bán hàng của mình, bạn có thể đăng ký ____45311 ____45369
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5370
again, explicitly.

9. 5. kích hoạt tổng hợp

Bạn có thể kết hợp nhiều trình kích hoạt để tạo thành trình kích hoạt tổng hợp và có thể chỉ định trình kích hoạt để phát ra kết quả nhiều lần, nhiều nhất một lần hoặc trong các điều kiện tùy chỉnh khác

9. 5. 1. Các loại kích hoạt tổng hợp

Beam bao gồm các kích hoạt tổng hợp sau

  • Bạn có thể thêm các lần kích hoạt sớm hoặc kích hoạt muộn bổ sung cho
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    5376 qua
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    5377 và
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    5378
  • await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    5379 chỉ định trình kích hoạt thực thi mãi mãi. Bất cứ khi nào các điều kiện của trình kích hoạt được đáp ứng, nó sẽ khiến một cửa sổ phát ra kết quả rồi đặt lại và bắt đầu lại. Có thể hữu ích khi kết hợp
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    5379 với
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    5381 để chỉ định một điều kiện khiến trình kích hoạt lặp lại dừng lại
  • await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    5382 kết hợp nhiều trình kích hoạt để kích hoạt theo trình tự cụ thể. Mỗi lần một trình kích hoạt trong chuỗi phát ra một cửa sổ, trình tự sẽ chuyển sang trình kích hoạt tiếp theo
  • await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    5383 nhận nhiều trình kích hoạt và phát ra lần đầu tiên bất kỳ trình kích hoạt đối số nào của nó được thỏa mãn. Điều này tương đương với phép toán OR logic cho nhiều trình kích hoạt
  • await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    5384 nhận nhiều trình kích hoạt và phát ra khi tất cả các trình kích hoạt đối số của nó được thỏa mãn. Điều này tương đương với phép toán AND logic cho nhiều trình kích hoạt
  • await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    5385 có thể đóng vai trò là điều kiện cuối cùng để khiến bất kỳ trình kích hoạt nào kích hoạt lần cuối và không bao giờ kích hoạt nữa

9. 5. 2. Thành phần với AfterWatermark

Một số trình kích hoạt tổng hợp hữu ích nhất kích hoạt một lần duy nhất khi Beam ước tính rằng tất cả dữ liệu đã đến [i. e. khi hình mờ đi qua cuối cửa sổ] kết hợp với một trong hai hoặc cả hai điều sau

  • Các lần kích hoạt đầu cơ trước khi hình mờ đi qua cuối cửa sổ để cho phép xử lý một phần kết quả nhanh hơn

  • Các lần kích hoạt muộn xảy ra sau khi hình mờ đi qua cuối cửa sổ, để cho phép xử lý dữ liệu đến muộn

Bạn có thể thể hiện mẫu này bằng cách sử dụng

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5320. Ví dụ: mã kích hoạt ví dụ sau kích hoạt trong các điều kiện sau

  • Theo ước tính của Beam, tất cả dữ liệu đã đến [hình mờ vượt qua cuối cửa sổ]

  • Bất cứ lúc nào dữ liệu đến trễ, sau mười phút chậm trễ

  • Sau hai ngày, chúng tôi cho rằng sẽ không có thêm dữ liệu quan tâm nào đến và trình kích hoạt sẽ ngừng thực thi

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
653

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
654

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
655

9. 5. 3. Các kích hoạt tổng hợp khác

Bạn cũng có thể xây dựng các loại trình kích hoạt tổng hợp khác. Mã ví dụ sau hiển thị trình kích hoạt tổng hợp đơn giản kích hoạt bất cứ khi nào ngăn có ít nhất 100 phần tử hoặc sau một phút

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
656

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
657

10. số liệu

Trong mô hình Beam, các chỉ số cung cấp một số thông tin chi tiết về trạng thái hiện tại của quy trình người dùng, có thể xảy ra trong khi quy trình đang chạy. Có thể có những lý do khác nhau cho điều đó, ví dụ

  • Kiểm tra số lỗi gặp phải khi chạy một bước cụ thể trong quy trình;
  • Theo dõi số lượng RPC được thực hiện cho dịch vụ phụ trợ;
  • Truy xuất số lượng chính xác số lượng phần tử đã được xử lý;
  • …và như thế

10. 1. Các khái niệm chính về chỉ số Beam

  • được đặt tên. Mỗi chỉ số có một tên bao gồm một không gian tên và một tên thực tế. Không gian tên có thể được sử dụng để phân biệt giữa nhiều chỉ số có cùng tên và cũng cho phép truy vấn tất cả các chỉ số trong một không gian tên cụ thể
  • phạm vi. Mỗi số liệu được báo cáo theo một bước cụ thể trong quy trình bán hàng, cho biết mã nào đang chạy khi số liệu đó tăng lên
  • Được tạo động. Các chỉ số có thể được tạo trong thời gian chạy mà không cần khai báo trước chúng, giống như cách tạo một trình ghi nhật ký. Điều này giúp tạo ra các số liệu trong mã tiện ích dễ dàng hơn và báo cáo chúng một cách hữu ích
  • xuống cấp một cách duyên dáng. Nếu một người chạy không hỗ trợ một số phần của báo cáo chỉ số, thì hành vi dự phòng là bỏ cập nhật chỉ số thay vì làm hỏng quy trình. Nếu một trình chạy không hỗ trợ một số phần của số liệu truy vấn, thì trình chạy sẽ không trả về dữ liệu được liên kết

Các chỉ số được báo cáo hoàn toàn nằm trong phạm vi biến đổi trong quy trình đã báo cáo các chỉ số đó. Điều này cho phép báo cáo cùng một tên chỉ số ở nhiều nơi và xác định giá trị mà mỗi biến đổi được báo cáo, cũng như tổng hợp chỉ số trên toàn bộ quy trình

Ghi chú. Việc các số liệu có thể truy cập được trong quá trình thực thi đường ống hay chỉ sau khi các công việc đã hoàn thành là phụ thuộc vào người chạy.

10. 2. Các loại chỉ số

Có ba loại số liệu được hỗ trợ tại thời điểm này.

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5387,
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5388 và
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5389

Trong Beam SDK for Go, một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
410 do khung cung cấp phải được chuyển đến chỉ số, nếu không giá trị chỉ số sẽ không được ghi lại. Khung sẽ tự động cung cấp một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
410 hợp lệ đến
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
636 và các phương thức tương tự khi đó là tham số đầu tiên

Phản đối. Số liệu báo cáo một giá trị dài duy nhất và có thể tăng hoặc giảm

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
658

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
659

Phân bổ. Một số liệu báo cáo thông tin về việc phân phối các giá trị được báo cáo

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
660

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
661

máy đo. Số liệu báo cáo giá trị mới nhất trong số các giá trị được báo cáo. Vì các số liệu được thu thập từ nhiều công nhân nên giá trị có thể không phải là giá trị cuối cùng tuyệt đối mà là một trong những giá trị mới nhất

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
662

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
663

10. 3. Số liệu truy vấn

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5393 có một phương thức
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5394 trả về một đối tượng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5395 cho phép truy cập các chỉ số. Phương pháp chính có sẵn trong
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5395 cho phép truy vấn tất cả các chỉ số phù hợp với một bộ lọc nhất định

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5397 có một phương thức
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5398 trả về một đối tượng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5399 cho phép truy cập các chỉ số. Phương pháp chính có sẵn trong
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5399 cho phép truy vấn tất cả các chỉ số phù hợp với một bộ lọc nhất định. Nó nhận một biến vị ngữ với loại tham số
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5401, có thể được sử dụng cho các bộ lọc tùy chỉnh

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
664

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
665

10. 4. Sử dụng số liệu trong quy trình

Dưới đây là một ví dụ đơn giản về cách sử dụng chỉ số

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5387 trong quy trình người dùng

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
666

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
667

10. 5. Xuất chỉ số

Số liệu chùm tia có thể được xuất sang các phần chìm bên ngoài. Nếu một số liệu chìm được thiết lập trong cấu hình, người chạy sẽ đẩy các số liệu tới nó trong khoảng thời gian 5 giây mặc định. Cấu hình được giữ trong lớp MetricsOptions. Nó chứa cấu hình thời gian đẩy và cũng có các tùy chọn cụ thể chìm như loại và URL. Hiện tại, chỉ có REST HTTP và các phần chìm Graphite được hỗ trợ và chỉ các trình chạy Flink và Spark hỗ trợ xuất số liệu

Ngoài ra, các số liệu Beam được xuất sang bảng điều khiển Spark và Flink bên trong để được tư vấn trong giao diện người dùng tương ứng của chúng

11. Trạng thái và bộ hẹn giờ

Các cơ sở kích hoạt và cửa sổ của Beam cung cấp khả năng trừu tượng hóa mạnh mẽ để nhóm và tổng hợp dữ liệu đầu vào không giới hạn dựa trên dấu thời gian. Tuy nhiên, có những trường hợp sử dụng tổng hợp mà nhà phát triển có thể yêu cầu mức độ kiểm soát cao hơn mức độ kiểm soát do cửa sổ và trình kích hoạt cung cấp. Beam cung cấp API để quản lý trạng thái theo từng khóa theo cách thủ công, cho phép kiểm soát chi tiết các tập hợp

Trạng thái mô hình API trạng thái của Beam trên mỗi khóa. Để sử dụng API trạng thái, bạn bắt đầu với một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 có khóa, trong Java được mô hình hóa như một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
710. Một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556 đang xử lý
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 này hiện có thể khai báo các biến trạng thái. Bên trong
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556, các biến trạng thái này có thể được sử dụng để ghi hoặc cập nhật trạng thái cho khóa hiện tại hoặc để đọc trạng thái trước đó được ghi cho khóa đó. Trạng thái luôn chỉ nằm trong phạm vi đầy đủ đối với khóa xử lý hiện tại

Cửa sổ vẫn có thể được sử dụng cùng với xử lý trạng thái. Tất cả trạng thái cho một khóa nằm trong phạm vi cửa sổ hiện tại. Điều này có nghĩa là lần đầu tiên một khóa được nhìn thấy cho một cửa sổ nhất định, bất kỳ trạng thái nào được đọc sẽ trả về trạng thái trống và trình chạy có thể thu gom rác trạng thái khi một cửa sổ hoàn thành. Nó cũng thường hữu ích khi sử dụng các tập hợp cửa sổ của Beam trước toán tử trạng thái. Ví dụ: sử dụng bộ kết hợp để tổng hợp trước dữ liệu, sau đó lưu trữ dữ liệu đã tổng hợp bên trong trạng thái. Các cửa sổ hợp nhất hiện không được hỗ trợ khi sử dụng trạng thái và bộ hẹn giờ

Đôi khi xử lý trạng thái được sử dụng để triển khai xử lý kiểu máy trạng thái bên trong một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583. Khi thực hiện việc này, cần phải lưu ý rằng các thành phần trong PCCollection đầu vào không có thứ tự được đảm bảo và để đảm bảo rằng logic chương trình có khả năng phục hồi với điều này. Các bài kiểm tra đơn vị được viết bằng DirectRunner sẽ xáo trộn thứ tự xử lý phần tử và được khuyến nghị để kiểm tra tính chính xác

Trong Java, DoFn tuyên bố các trạng thái sẽ được truy cập bằng cách tạo các biến thành viên

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5409 cuối cùng đại diện cho mỗi trạng thái. Mỗi tiểu bang phải được đặt tên bằng cách sử dụng chú thích
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5410; . Một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583 có thể khai báo nhiều biến trạng thái

Trong Python, DoFn khai báo các trạng thái sẽ được truy cập bằng cách tạo các biến thành viên lớp

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5409 đại diện cho từng trạng thái. Mỗi
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5409 được khởi tạo với một tên, tên này là duy nhất cho một ParDo trong biểu đồ và không liên quan đến các nút khác trong biểu đồ. Một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583 có thể khai báo nhiều biến trạng thái

Trong Go, DoFn khai báo các trạng thái sẽ được truy cập bằng cách tạo các biến thành viên cấu trúc trạng thái đại diện cho từng trạng thái. Mỗi biến trạng thái được khởi tạo bằng một khóa, khóa này là duy nhất cho một ParDo trong biểu đồ và không liên quan đến các nút khác trong biểu đồ. Nếu không cung cấp tên, khóa sẽ mặc định là tên của biến thành viên. Một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583 có thể khai báo nhiều biến trạng thái

Ghi chú. Beam SDK cho Bản mô tả chưa hỗ trợ API Trạng thái và Hẹn giờ, nhưng có thể sử dụng các tính năng này từ các đường dẫn ngôn ngữ chéo [xem bên dưới]

11. 1. Các loại trạng thái

Beam cung cấp một số loại trạng thái

ValueState

ValueState là một giá trị trạng thái vô hướng. Đối với mỗi khóa trong đầu vào, một ValueState sẽ lưu trữ một giá trị đã nhập có thể được đọc và sửa đổi bên trong các phương thức

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
912 hoặc
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
441 của DoFn. Nếu loại ValueState có bộ mã hóa được đăng ký, thì Beam sẽ tự động suy ra bộ mã hóa cho giá trị trạng thái. Mặt khác, một bộ mã hóa có thể được chỉ định rõ ràng khi tạo ValueState. Ví dụ: ParDo sau đây tạo một biến trạng thái duy nhất tích lũy số lượng phần tử được nhìn thấy

Ghi chú.

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5418 được gọi là
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5419 trong Python SDK

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
668

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
669

Beam cũng cho phép chỉ định rõ ràng một bộ mã hóa cho các giá trị

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5418. Ví dụ

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
670

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
671

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
672

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
673

Kết hợpTrạng thái

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5421 cho phép bạn tạo đối tượng trạng thái được cập nhật bằng bộ kết hợp Beam. Ví dụ: ví dụ
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5418 trước đó có thể được viết lại để sử dụng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5421

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
674

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
675

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
676

TúiBang

Một trường hợp sử dụng phổ biến cho trạng thái là tích lũy nhiều phần tử.

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5424 cho phép tích lũy một tập hợp các phần tử không có thứ tự. Điều này cho phép thêm các phần tử vào bộ sưu tập mà không yêu cầu đọc toàn bộ bộ sưu tập trước, đây là một hiệu quả đạt được. Ngoài ra, các vận động viên hỗ trợ đọc theo trang có thể cho phép các túi riêng lẻ lớn hơn bộ nhớ khả dụng

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
677

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
678

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
535

11. 2. Đọc trạng thái hoãn lại

Khi một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583 chứa nhiều thông số trạng thái, việc đọc từng thông số theo thứ tự có thể chậm. Gọi hàm
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5426 ở trạng thái có thể khiến người chạy thực hiện thao tác chặn đọc. Thực hiện nhiều lần đọc chặn theo trình tự sẽ thêm độ trễ cho quá trình xử lý phần tử. Nếu bạn biết rằng một trạng thái sẽ luôn được đọc, bạn có thể chú thích trạng thái đó là @AlwaysFetched, sau đó trình chạy có thể tìm nạp trước tất cả các trạng thái cần thiết. Ví dụ

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
680

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
681

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
682

Tuy nhiên, nếu có các đường dẫn mã trong đó các trạng thái không được tìm nạp, thì việc chú thích bằng @AlwaysFetched sẽ thêm tính năng tìm nạp không cần thiết cho các đường dẫn đó. Trong trường hợp này, phương thức readLater cho phép người chạy biết rằng trạng thái sẽ được đọc trong tương lai, cho phép nhiều lần đọc trạng thái được gộp lại với nhau

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
683

11. 3. hẹn giờ

Beam cung cấp API gọi lại hẹn giờ cho mỗi phím. Điều này cho phép xử lý chậm dữ liệu được lưu trữ bằng API trạng thái. Bộ hẹn giờ có thể được đặt thành gọi lại tại thời điểm sự kiện hoặc dấu thời gian xử lý. Mỗi bộ đếm thời gian được xác định bằng TimerId. Chỉ có thể đặt bộ hẹn giờ nhất định cho một phím cho một dấu thời gian. Cuộc gọi được đặt trên bộ hẹn giờ sẽ ghi đè thời gian kích hoạt trước đó cho bộ hẹn giờ của phím đó

11. 3. 1. bộ hẹn giờ sự kiện

Bộ hẹn giờ thời gian sự kiện kích hoạt khi hình mờ đầu vào cho DoFn vượt qua thời gian mà bộ hẹn giờ được đặt, nghĩa là người chạy tin rằng không có thêm yếu tố nào được xử lý bằng dấu thời gian trước dấu thời gian của bộ hẹn giờ. Điều này cho phép tổng hợp thời gian sự kiện

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
684

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
685

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
686

11. 3. 2. bộ định thời gian xử lý

Bộ hẹn giờ thời gian xử lý kích hoạt khi thời gian thực của đồng hồ treo tường trôi qua. Điều này thường được sử dụng để tạo các lô dữ liệu lớn hơn trước khi xử lý. Nó cũng có thể được sử dụng để lên lịch các sự kiện sẽ xảy ra vào một thời điểm cụ thể. Cũng giống như với bộ hẹn giờ thời gian sự kiện, bộ hẹn giờ thời gian xử lý là trên mỗi khóa - mỗi khóa có một bản sao riêng của bộ hẹn giờ

Mặc dù bộ hẹn giờ thời gian xử lý có thể được đặt thành dấu thời gian tuyệt đối, nhưng rất phổ biến để đặt chúng thành phần bù so với thời gian hiện tại. Trong Java, các phương thức

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5427 và
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5428 có thể được sử dụng để thực hiện điều này

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
687

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
688

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
686

11. 3. 3. Thẻ hẹn giờ động

Beam cũng hỗ trợ tự động thiết lập thẻ hẹn giờ bằng cách sử dụng

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5429 trong SDK Java. Điều này cho phép đặt nhiều bộ hẹn giờ khác nhau trong một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583 và cho phép các thẻ bộ hẹn giờ được chọn động - e. g. dựa trên dữ liệu trong các yếu tố đầu vào. Chỉ có thể đặt bộ hẹn giờ với một thẻ cụ thể thành một dấu thời gian duy nhất, do đó, việc đặt lại bộ hẹn giờ có tác dụng ghi đè thời gian hết hạn trước đó cho bộ hẹn giờ với thẻ đó. Mỗi
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5429 được xác định bằng id dòng hẹn giờ và các bộ hẹn giờ trong các họ hẹn giờ khác nhau là độc lập

Trong SDK Python, thẻ hẹn giờ động có thể được chỉ định trong khi gọi

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5432 hoặc
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5433. Theo mặc định, thẻ hẹn giờ là một chuỗi rỗng nếu không được chỉ định

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
690

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
691

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
686

11. 3. 4. Dấu thời gian đầu ra của bộ hẹn giờ

Theo mặc định, bộ hẹn giờ theo thời gian sự kiện sẽ giữ hình mờ đầu ra của

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556 với dấu thời gian của bộ hẹn giờ. Điều này có nghĩa là nếu bộ hẹn giờ được đặt thành 12 giờ đêm, thì bất kỳ tập hợp cửa sổ hoặc bộ hẹn giờ sự kiện nào sau này trong biểu đồ quy trình kết thúc sau 12 giờ đêm sẽ không hết hạn. Dấu thời gian của bộ hẹn giờ cũng là dấu thời gian đầu ra mặc định cho lệnh gọi lại bộ hẹn giờ. Điều này có nghĩa là bất kỳ phần tử nào xuất ra từ phương thức onTimer sẽ có dấu thời gian bằng với dấu thời gian của bộ hẹn giờ kích hoạt. Đối với bộ hẹn giờ thời gian xử lý, dấu thời gian đầu ra mặc định và giữ hình mờ là giá trị của hình mờ đầu vào tại thời điểm bộ hẹn giờ được đặt

Trong một số trường hợp, DoFn cần xuất dấu thời gian sớm hơn thời gian hết hạn của bộ hẹn giờ và do đó cũng cần giữ hình mờ đầu ra của nó đối với các dấu thời gian đó. Ví dụ: hãy xem xét quy trình sau tạm thời nhóm các bản ghi vào trạng thái và đặt bộ hẹn giờ để thoát trạng thái. Mã này có thể xuất hiện đúng, nhưng sẽ không hoạt động bình thường

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
693

Vấn đề với mã này là ParDo đang đệm các phần tử, tuy nhiên không có gì ngăn hình mờ vượt qua dấu thời gian của các phần tử đó, vì vậy tất cả các phần tử đó có thể bị loại bỏ dưới dạng dữ liệu muộn. Để ngăn điều này xảy ra, dấu thời gian đầu ra cần được đặt trên bộ hẹn giờ để ngăn hình mờ vượt qua dấu thời gian của phần tử tối thiểu. Đoạn mã sau chứng minh điều này

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
694

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
695

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
686

11. 4. Tình trạng thu gom rác

Trạng thái trên mỗi khóa cần được thu gom rác hoặc cuối cùng kích thước ngày càng tăng của trạng thái có thể tác động tiêu cực đến hiệu suất. Có hai chiến lược phổ biến cho trạng thái thu gom rác

11. 4. 1. Sử dụng cửa sổ để thu gom rác

Tất cả trạng thái và bộ hẹn giờ cho một khóa nằm trong phạm vi cửa sổ chứa khóa đó. Điều này có nghĩa là tùy thuộc vào dấu thời gian của phần tử đầu vào, ParDo sẽ thấy các giá trị khác nhau cho trạng thái tùy thuộc vào cửa sổ mà phần tử đó rơi vào. Ngoài ra, khi hình mờ đầu vào đi qua cuối cửa sổ, trình chạy sẽ thu thập tất cả trạng thái cho cửa sổ đó. [Ghi chú. nếu độ trễ cho phép được đặt thành giá trị dương cho cửa sổ, người chạy phải đợi hình mờ đi qua cuối cửa sổ cộng với độ trễ cho phép trước trạng thái thu gom rác]. Điều này có thể được sử dụng như một chiến lược thu gom rác

Ví dụ, được đưa ra sau đây

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
697

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
698

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
699

Trạng thái cửa hàng

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
556 này mỗi ngày. Khi đường ống xử lý xong dữ liệu cho một ngày nhất định, tất cả trạng thái của ngày đó sẽ được thu gom rác

11. 4. 1. Sử dụng bộ hẹn giờ để thu gom rác

Trong một số trường hợp, rất khó để tìm ra chiến lược cửa sổ mô hình hóa chiến lược thu gom rác mong muốn. Ví dụ: mong muốn chung là chuyển trạng thái thu gom rác cho một khóa sau khi không thấy hoạt động nào trên khóa trong một thời gian. Điều này có thể được thực hiện bằng cách cập nhật bộ đếm thời gian mà trạng thái thu gom rác. Ví dụ

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
00

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
01

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
686

11. 5. Ví dụ về trạng thái và bộ hẹn giờ

Sau đây là một số ví dụ sử dụng trạng thái và bộ hẹn giờ

11. 5. 1. Kết hợp các nhấp chuột và lượt xem

Trong ví dụ này, quy trình đang xử lý dữ liệu từ trang chủ của trang thương mại điện tử. Có hai luồng đầu vào. luồng lượt xem, biểu thị các liên kết sản phẩm được đề xuất hiển thị cho người dùng trên trang chủ và luồng lượt nhấp, biểu thị lượt nhấp thực tế của người dùng vào các liên kết này. Mục tiêu của quy trình là kết hợp các sự kiện nhấp chuột với các sự kiện xem, xuất ra một sự kiện đã tham gia mới chứa thông tin từ cả hai sự kiện. Mỗi liên kết có một mã định danh duy nhất có trong cả sự kiện xem và sự kiện tham gia

Nhiều sự kiện xem sẽ không bao giờ được theo dõi bằng các nhấp chuột. Đường ống này sẽ đợi một giờ cho một nhấp chuột, sau đó nó sẽ từ bỏ tham gia này. Mặc dù mỗi sự kiện nhấp chuột phải có một sự kiện xem, nhưng một số ít sự kiện xem có thể bị mất và không bao giờ được đưa vào quy trình Beam; . Các sự kiện đầu vào không được sắp xếp - có thể thấy sự kiện nhấp chuột trước sự kiện xem. Thời gian chờ tham gia một giờ phải dựa trên thời gian sự kiện, không phải thời gian xử lý

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
03

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
04

11. 5. 2. RPC theo đợt

Trong ví dụ này, các yếu tố đầu vào đang được chuyển tiếp đến một dịch vụ RPC bên ngoài. RPC chấp nhận các yêu cầu hàng loạt - nhiều sự kiện cho cùng một người dùng có thể được xử lý theo đợt trong một lệnh gọi RPC. Vì dịch vụ RPC này cũng áp đặt giới hạn tốc độ nên chúng tôi muốn gộp các sự kiện có giá trị 10 giây lại với nhau để giảm số lượng cuộc gọi

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
05

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
06

12. Có thể chia tách
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
67

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583 có thể chia được [SDF] cho phép người dùng tạo các thành phần mô-đun có chứa I/O [và một số trường hợp sử dụng không phải I/O nâng cao]. Việc có các thành phần I/O dạng mô-đun có thể được kết nối với nhau giúp đơn giản hóa các mẫu điển hình mà người dùng muốn. Ví dụ: trường hợp sử dụng phổ biến là đọc tên tệp từ hàng đợi tin nhắn, sau đó phân tích cú pháp các tệp đó. Theo truyền thống, người dùng được yêu cầu viết một trình kết nối I/O duy nhất chứa logic cho hàng đợi tin nhắn và trình đọc tệp [độ phức tạp tăng lên] hoặc chọn sử dụng lại I/O hàng đợi tin nhắn theo sau bởi một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583 thông thường đọc tệp [ . Với SDF, chúng tôi mang đến sự phong phú của các API I/O của Apache Beam cho một mô-đun cho phép
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583 trong khi vẫn duy trì hiệu suất của các trình kết nối I/O truyền thống

12. 1. Khái niệm cơ bản về SDF

Ở cấp độ cao, SDF chịu trách nhiệm xử lý các cặp phần tử và giới hạn. Một hạn chế đại diện cho một tập hợp con công việc cần thiết phải được thực hiện khi xử lý phần tử

Thực hiện một SDF theo các bước sau

  1. Mỗi phần tử được ghép nối với một hạn chế [e. g. tên tệp được ghép nối với phạm vi bù đại diện cho toàn bộ tệp]
  2. Mỗi phần tử và cặp hạn chế được tách ra [e. g. phạm vi bù được chia thành các phần nhỏ hơn]
  3. Người chạy phân phối lại các cặp phần tử và hạn chế cho một số công nhân
  4. Các cặp phần tử và giới hạn được xử lý song song [e. g. tập tin được đọc]. Trong bước cuối cùng này, cặp phần tử và giới hạn có thể tạm dừng quá trình xử lý của chính nó và/hoặc được chia thành các cặp phần tử và giới hạn khác

12. 1. 1. Một SDF cơ bản

Một SDF cơ bản bao gồm ba phần. hạn chế, nhà cung cấp hạn chế và trình theo dõi hạn chế. Nếu bạn muốn kiểm soát hình mờ, đặc biệt là trong đường ống phát trực tuyến, cần có thêm hai thành phần. nhà cung cấp công cụ ước tính thủy vân và công cụ ước tính thủy vân

Hạn chế là một đối tượng do người dùng định nghĩa được sử dụng để biểu thị một tập hợp con công việc cho một phần tử nhất định. Ví dụ: chúng tôi đã xác định

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5440 là một hạn chế để biểu thị các vị trí bù trong Java và Python

Trình cung cấp hạn chế cho phép các tác giả SDF ghi đè các triển khai mặc định, bao gồm cả các triển khai để phân tách và định cỡ. Trong Java và Go, đây là

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583. Python có loại
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5442 chuyên dụng

Trình theo dõi hạn chế chịu trách nhiệm theo dõi tập hợp con nào của hạn chế đã được hoàn thành trong quá trình xử lý. Để biết chi tiết về API, hãy đọc tài liệu tham khảo Java và Python

Có một số triển khai

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5443 tích hợp được định nghĩa trong Java

  1. Bù đắpPhạm viTracker
  2. GrowableOffsetRangeTracker
  3. ByteKeyRangeTracker

SDF cũng có triển khai

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5443 tích hợp sẵn trong Python

  1. Bù đắpPhạm viTracker

Go cũng có loại

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5443 tích hợp

  1. Bù đắpPhạm viTracker

Trạng thái hình mờ là một đối tượng do người dùng xác định được sử dụng để tạo một

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5446 từ một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5447. Trạng thái hình mờ đơn giản nhất có thể là một
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5448

Nhà cung cấp công cụ ước tính hình mờ cho phép các tác giả SDF xác định cách khởi tạo trạng thái hình mờ và tạo công cụ ước tính hình mờ. Trong Java và Go, đây là

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583. Python có loại
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5447 chuyên dụng

Công cụ ước tính thủy vân theo dõi thủy vân khi một cặp hạn chế phần tử đang được tiến hành. Để biết chi tiết về API, hãy đọc tài liệu tham khảo Java, Python và Go

Có một số triển khai

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5446 tích hợp sẵn trong Java

  1. Thủ công
  2. tăng đơn điệu
  3. Thời gian tường

Cùng với

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5447 mặc định, có cùng một bộ triển khai
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5446 tích hợp sẵn trong Python

  1. Hướng dẫn sử dụng WatermarkEstimator
  2. Công cụ ước tính MonotonicWatermark
  3. WalltimeWatermarkCông cụ ước tính

Các loại

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5446 sau đây được triển khai trong Go

  1. Dấu thời gianQuan sát ước tính
  2. WalltimeWatermarkCông cụ ước tính

Để xác định SDF, bạn phải chọn xem SDF có giới hạn [mặc định] hay không giới hạn và xác định cách khởi tạo giới hạn ban đầu cho một phần tử. Sự phân biệt dựa trên cách thể hiện khối lượng công việc

  • DoFn có giới hạn là những DoFn mà công việc được đại diện bởi một phần tử đã được biết trước và có kết thúc. Ví dụ về các phần tử được giới hạn bao gồm một tệp hoặc nhóm tệp
  • DoFns không giới hạn là những DoFn mà số lượng công việc không có điểm kết thúc cụ thể hoặc số lượng công việc không được biết trước. Ví dụ về các phần tử không giới hạn bao gồm chủ đề Kafka hoặc PubSub

Trong Java, bạn có thể sử dụng @UnboundedPerElement hoặc @BoundedPerElement để chú thích

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583 của mình. Trong Python, bạn có thể sử dụng @unbounded_per_element để chú thích
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
07

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
08

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
09

Tại thời điểm này, chúng tôi có một SDF hỗ trợ phân tách do người chạy bắt đầu cho phép tái cân bằng công việc động. Để tăng tốc độ xảy ra song song hóa công việc ban đầu hoặc đối với những người chạy không hỗ trợ phân tách do người chạy bắt đầu, chúng tôi khuyên bạn nên cung cấp một tập hợp các lần phân tách ban đầu

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
10

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
11

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
12

12. 2. Định cỡ và tiến độ

Định cỡ và tiến độ được sử dụng trong quá trình thực thi SDF để thông báo cho người chạy để họ có thể thực hiện các quyết định thông minh về việc phân chia những hạn chế nào và cách song song hóa công việc

Trước khi xử lý một phần tử và hạn chế, người chạy có thể sử dụng kích thước ban đầu để chọn cách thức và người xử lý các hạn chế nhằm cải thiện sự cân bằng ban đầu và song song hóa công việc. Trong quá trình xử lý một phần tử và hạn chế, định cỡ và tiến trình được sử dụng để chọn phân chia hạn chế nào và ai sẽ xử lý chúng

Theo mặc định, chúng tôi sử dụng ước tính của trình theo dõi hạn chế cho công việc còn lại dựa trên giả định rằng tất cả các hạn chế đều có chi phí bằng nhau. Để ghi đè mặc định, tác giả SDF có thể cung cấp phương pháp thích hợp trong nhà cung cấp hạn chế. Các tác giả SDF cần lưu ý rằng phương pháp định cỡ sẽ được gọi đồng thời trong quá trình xử lý gói do quá trình phân tách và ước tính tiến độ bắt đầu của người chạy

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
13

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
14

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
15

12. 3. Điểm kiểm tra do người dùng khởi tạo

Một số I/O không thể tạo ra tất cả dữ liệu cần thiết để hoàn thành một hạn chế trong thời gian tồn tại của một gói. Điều này thường xảy ra với các hạn chế không giới hạn, nhưng cũng có thể xảy ra với các hạn chế có giới hạn. Ví dụ: có thể có nhiều dữ liệu cần nhập hơn nhưng chưa có sẵn. Một nguyên nhân khác của trường hợp này là do hệ thống nguồn điều chỉnh dữ liệu của bạn

SDF của bạn có thể báo hiệu cho bạn biết rằng bạn chưa xử lý xong hạn chế hiện tại. Tín hiệu này có thể gợi ý thời gian để tiếp tục tại. Trong khi người chạy cố gắng tôn trọng thời gian tiếp tục, điều này không được đảm bảo. Điều này cho phép thực thi tiếp tục trên một hạn chế có sẵn công việc cải thiện việc sử dụng tài nguyên

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
16

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
17

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
18

12. 4. Runner-khởi xướng tách

Người chạy bất cứ lúc nào cũng có thể cố gắng tách một giới hạn trong khi nó đang được xử lý. Điều này cho phép người chạy tạm dừng xử lý hạn chế để có thể thực hiện công việc khác [phổ biến đối với các hạn chế không giới hạn để hạn chế lượng đầu ra và/hoặc cải thiện độ trễ] hoặc chia hạn chế thành hai phần, tăng khả năng song song có sẵn trong hệ thống. vận động viên khác nhau [e. g. , Dataflow, Flink, Spark] có các chiến lược khác nhau để phân tách theo đợt và thực thi trực tuyến

Hãy ghi nhớ điều này khi viết một SDF vì thời điểm kết thúc hạn chế có thể thay đổi. Khi viết vòng lặp xử lý, hãy sử dụng kết quả từ việc cố gắng yêu cầu một phần của hạn chế thay vì cho rằng bạn có thể xử lý cho đến khi kết thúc

Một ví dụ không chính xác có thể là

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
19

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
20

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
21

12. 5. ước tính hình mờ

Công cụ ước tính hình mờ mặc định không tạo ra ước tính hình mờ. Do đó, hình mờ đầu ra chỉ được tính bằng số lượng hình mờ ngược dòng tối thiểu

Một SDF có thể nâng cao hình mờ đầu ra bằng cách chỉ định giới hạn dưới cho tất cả đầu ra trong tương lai mà phần tử này và cặp hạn chế sẽ tạo ra. Người chạy tính toán hình mờ đầu ra tối thiểu bằng cách lấy giá trị tối thiểu trên tất cả các hình mờ ngược dòng và giá trị tối thiểu được báo cáo bởi từng phần tử và cặp giới hạn. Hình mờ được báo cáo phải tăng đơn điệu cho từng phần tử và cặp hạn chế trên các ranh giới gói. Khi một phần tử và cặp hạn chế ngừng xử lý hình mờ của nó, nó không còn được coi là một phần của phép tính trên

Lời khuyên

  • Nếu bạn tạo một SDF xuất các bản ghi có dấu thời gian, bạn nên đưa ra các cách để cho phép người dùng SDF này định cấu hình công cụ ước tính hình mờ nào sẽ sử dụng
  • Bất kỳ dữ liệu nào được tạo ra trước hình mờ có thể được coi là muộn. Xem hình mờ và dữ liệu muộn để biết thêm chi tiết

12. 5. 1. Kiểm soát hình mờ

Có hai loại công cụ ước tính thủy vân chung. quan sát dấu thời gian và quan sát đồng hồ bên ngoài. Công cụ ước tính hình mờ quan sát dấu thời gian sử dụng dấu thời gian đầu ra của mỗi bản ghi để tính toán ước tính hình mờ trong khi công cụ ước tính hình mờ quan sát đồng hồ bên ngoài kiểm soát hình mờ bằng cách sử dụng đồng hồ không được liên kết với bất kỳ đầu ra riêng lẻ nào, chẳng hạn như đồng hồ cục bộ của máy hoặc đồng hồ tiếp xúc

Nhà cung cấp công cụ ước tính hình mờ cho phép bạn ghi đè logic ước tính hình mờ mặc định và sử dụng triển khai công cụ ước tính hình mờ hiện có. Bạn cũng có thể cung cấp triển khai ước tính hình mờ của riêng mình

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
22

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
23

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
24

12. 6. Cắt ngắn trong quá trình thoát nước

Người chạy hỗ trợ đường ống thoát nước cần có khả năng thoát SDF; . Theo mặc định, các hạn chế có giới hạn xử lý phần còn lại của hạn chế trong khi các hạn chế không có giới hạn kết thúc quá trình xử lý tại điểm kiểm tra do SDF bắt đầu tiếp theo hoặc phân tách do người chạy bắt đầu. Bạn có thể ghi đè hành vi mặc định này bằng cách xác định phương thức thích hợp trên trình cung cấp hạn chế

Ghi chú. Khi quá trình thoát đường ống bắt đầu và biến đổi hạn chế cắt ngắn được kích hoạt,

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5457 sẽ không được lên lịch lại

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
25

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
26

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
27

12. 7. Quyết toán gói

Hoàn thiện gói cho phép

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
583 thực hiện các tác dụng phụ bằng cách đăng ký gọi lại. Cuộc gọi lại được gọi sau khi người chạy đã thừa nhận rằng nó đã duy trì đầu ra một cách lâu dài. Ví dụ: một hàng đợi tin nhắn có thể cần xác nhận các tin nhắn mà nó đã nhập vào đường dẫn. Quyết toán gói không giới hạn ở SDF nhưng được gọi ra ở đây vì đây là trường hợp sử dụng chính

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
28

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
29

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
30

13. Đường ống đa ngôn ngữ

Phần này cung cấp tài liệu toàn diện về các đường dẫn đa ngôn ngữ. Để bắt đầu tạo một kênh dẫn đa ngôn ngữ, hãy xem

  • Khởi động nhanh đường dẫn đa ngôn ngữ Python
  • Khởi động nhanh đường dẫn đa ngôn ngữ Java

Beam cho phép bạn kết hợp các biến đổi được viết bằng bất kỳ ngôn ngữ SDK được hỗ trợ nào [hiện tại là Java và Python] và sử dụng chúng trong một kênh dẫn đa ngôn ngữ. Khả năng này giúp dễ dàng cung cấp chức năng mới đồng thời trong các Apache Beam SDK khác nhau thông qua một chuyển đổi ngôn ngữ chéo duy nhất. Ví dụ: trình kết nối Apache Kafka và chuyển đổi SQL từ SDK Java có thể được sử dụng trong các đường dẫn Python

Các quy trình sử dụng biến đổi từ nhiều ngôn ngữ SDK được gọi là quy trình đa ngôn ngữ

13. 1. Tạo chuyển đổi ngôn ngữ chéo

Để cung cấp các biến đổi được viết bằng một ngôn ngữ cho các quy trình được viết bằng ngôn ngữ khác, Beam sử dụng một dịch vụ mở rộng, dịch vụ này tạo và đưa các đoạn quy trình dành riêng cho ngôn ngữ thích hợp vào quy trình

Trong ví dụ sau, một đường ống Beam Python khởi động một dịch vụ mở rộng Java cục bộ để tạo và thêm các đoạn đường ống Java thích hợp để thực thi chuyển đổi ngôn ngữ chéo Java Kafka thành đường ống Python. SDK sau đó tải xuống và tạo các giai đoạn phụ thuộc Java cần thiết để thực hiện các biến đổi này

Khi chạy, trình chạy Beam sẽ thực thi cả hai phép biến đổi Python và Java để chạy đường dẫn

Trong phần này, chúng tôi sẽ sử dụng KafkaIO. Đọc để minh họa cách tạo chuyển đổi ngôn ngữ chéo cho Java và ví dụ thử nghiệm cho Python

13. 1. 1. Tạo các biến đổi Java đa ngôn ngữ

Có hai cách để cung cấp các biến đổi Java cho các SDK khác

  • lựa chọn 1. Trong một số trường hợp, bạn có thể sử dụng các biến đổi Java hiện có từ các SDK khác mà không cần viết thêm bất kỳ mã Java nào
  • Lựa chọn 2. Bạn có thể sử dụng các biến đổi Java tùy ý từ các SDK khác bằng cách thêm một vài lớp Java
13. 1. 1. 1 Sử dụng các biến đổi Java hiện có mà không cần viết thêm mã Java

Bắt đầu với Beam 2. 34. 0, người dùng SDK Python có thể sử dụng một số biến đổi Java mà không cần viết mã Java bổ sung. Điều này có thể hữu ích trong nhiều trường hợp. Ví dụ

  • Nhà phát triển không quen thuộc với Java có thể cần sử dụng biến đổi Java hiện có từ đường dẫn Python
  • Một nhà phát triển có thể cần cung cấp một biến đổi Java hiện có cho một đường dẫn Python mà không cần viết/phát hành thêm mã Java

Ghi chú. Tính năng này hiện chỉ khả dụng khi sử dụng các biến đổi Java từ một đường dẫn Python

Để đủ điều kiện sử dụng trực tiếp, API của biến đổi Java phải đáp ứng các yêu cầu sau

  1. Biến đổi Java có thể được xây dựng bằng cách sử dụng hàm tạo công khai có sẵn hoặc phương thức tĩnh công khai [phương thức tạo] trong cùng một lớp Java
  2. Biến đổi Java có thể được cấu hình bằng một hoặc nhiều phương thức trình tạo. Mỗi phương thức của trình tạo phải ở chế độ công khai và sẽ trả về một phiên bản của biến đổi Java

Đây là một lớp Java mẫu có thể được sử dụng trực tiếp từ API Python

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
31

Để biết ví dụ hoàn chỉnh, hãy xem JavaDataGenerator

Để sử dụng một lớp Java tuân thủ các yêu cầu trên từ đường dẫn SDK Python, hãy làm theo các bước sau

  1. Tạo danh sách cho phép yaml mô tả các lớp và phương thức biến đổi Java sẽ được truy cập trực tiếp từ Python
  2. Bắt đầu một dịch vụ mở rộng, sử dụng tùy chọn
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    5459 để chuyển đường dẫn đến danh sách cho phép
  3. Sử dụng API JavaExternalTransform của Python để truy cập trực tiếp các biến đổi Java được xác định trong danh sách cho phép từ phía Python

Bắt đầu với Beam 2. 36. 0, có thể bỏ qua bước 1 và 2, như được mô tả trong các phần tương ứng bên dưới

Bước 1

Để sử dụng biến đổi Java đủ điều kiện từ Python, hãy xác định danh sách cho phép yaml. Danh sách cho phép này liệt kê tên lớp, phương thức hàm tạo và phương thức trình tạo có sẵn trực tiếp để sử dụng từ phía Python

Bắt đầu với Beam 2. 35. 0, bạn có tùy chọn chuyển

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5006 sang tùy chọn
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5459 thay vì xác định danh sách cho phép thực tế.
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5006 chỉ định rằng tất cả các biến đổi được hỗ trợ trong đường dẫn lớp của dịch vụ mở rộng có thể được truy cập thông qua API. Chúng tôi khuyến khích sử dụng danh sách cho phép thực tế để sản xuất, vì việc cho phép khách hàng truy cập các lớp Java tùy ý có thể gây ra rủi ro bảo mật

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
32

Bước 2

Cung cấp danh sách cho phép làm đối số khi khởi động dịch vụ mở rộng Java. Ví dụ: bạn có thể bắt đầu dịch vụ mở rộng dưới dạng quy trình Java cục bộ bằng cách sử dụng lệnh sau

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
33

Bắt đầu với Beam 2. 36. 0, API

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5463 sẽ tự động khởi động dịch vụ mở rộng với phần phụ thuộc tệp
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5464 nhất định nếu địa chỉ dịch vụ mở rộng không được cung cấp

Bước 3

Bạn có thể sử dụng lớp Java trực tiếp từ đường dẫn Python của mình bằng cách sử dụng một biến đổi sơ khai được tạo từ API

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5463. API này cho phép bạn xây dựng biến đổi bằng cách sử dụng tên lớp Java và cho phép bạn gọi các phương thức của trình tạo để định cấu hình lớp

Các loại tham số của hàm tạo và phương thức được ánh xạ giữa Python và Java bằng cách sử dụng lược đồ Beam. Lược đồ được tạo tự động bằng cách sử dụng các loại đối tượng được cung cấp ở phía Python. Nếu phương thức hàm tạo lớp Java hoặc phương thức trình tạo chấp nhận bất kỳ loại đối tượng phức tạp nào, hãy đảm bảo rằng lược đồ Beam cho các đối tượng này đã được đăng ký và sẵn dùng cho dịch vụ mở rộng Java. Nếu một lược đồ chưa được đăng ký, dịch vụ mở rộng Java sẽ cố gắng đăng ký một lược đồ bằng cách sử dụng JavaFieldSchema. Trong Python, các đối tượng tùy ý có thể được biểu diễn bằng cách sử dụng các

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5052, sẽ được biểu diễn dưới dạng các hàng Beam trong lược đồ. Đây là một biến đổi sơ khai Python đại diện cho biến đổi Java đã đề cập ở trên

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
34

Bạn có thể sử dụng biến đổi này trong một đường dẫn Python cùng với các biến đổi Python khác. Để biết ví dụ hoàn chỉnh, hãy xem javadatagenerator. py

13. 1. 1. 2 Sử dụng API để cung cấp các biến đổi Java hiện có cho các SDK khác

Để làm cho Beam Java SDK của bạn có thể chuyển đổi linh hoạt trên các ngôn ngữ SDK, bạn phải triển khai hai giao diện. ExternalTransformBuilder và ExternalTransformRegistrar. Giao diện

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5467 xây dựng chuyển đổi ngôn ngữ chéo bằng cách sử dụng các giá trị cấu hình được truyền vào từ đường ống và giao diện
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5468 đăng ký chuyển đổi ngôn ngữ chéo để sử dụng với dịch vụ mở rộng

Triển khai các giao diện

  1. Xác định lớp Trình tạo cho phép biến đổi của bạn để triển khai giao diện

    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    5467 và ghi đè phương thức
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    5470 sẽ được sử dụng để xây dựng đối tượng biến đổi của bạn. Các giá trị cấu hình ban đầu cho biến đổi của bạn phải được xác định trong phương thức
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    5470. Trong hầu hết các trường hợp, thật tiện lợi khi làm cho lớp trình tạo biến đổi Java triển khai
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    5467

    Ghi chú.

    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    5467 yêu cầu bạn xác định một đối tượng cấu hình [một POJO đơn giản] để nắm bắt một tập hợp các tham số do SDK bên ngoài gửi để bắt đầu chuyển đổi Java. Thông thường, các tham số này ánh xạ trực tiếp tới các tham số hàm tạo của biến đổi Java

    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    35

    Để biết các ví dụ đầy đủ, hãy xem JavaCountBuilder và JavaPrefixBuilder

    Lưu ý rằng phương thức

    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    5470 có thể thực hiện các thao tác bổ sung trước khi đặt các thuộc tính nhận được từ SDK bên ngoài trong quá trình chuyển đổi. Ví dụ:
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    5470 có thể xác thực các thuộc tính có sẵn trong đối tượng cấu hình trước khi đặt chúng trong biến đổi

  2. Đăng ký biến đổi dưới dạng biến đổi ngôn ngữ chéo bên ngoài bằng cách xác định một lớp thực hiện

    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    5468. Bạn phải chú thích lớp của mình bằng chú thích
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    5477 để đảm bảo rằng biến đổi của bạn được đăng ký và khởi tạo đúng cách bởi dịch vụ mở rộng

  3. Trong lớp công ty đăng ký của bạn, hãy xác định Tên tài nguyên thống nhất [URN] cho biến đổi của bạn. URN phải là một chuỗi duy nhất xác định biến đổi của bạn với dịch vụ mở rộng

  4. Từ bên trong lớp công ty đăng ký của bạn, hãy xác định lớp cấu hình cho các tham số được sử dụng trong quá trình khởi tạo chuyển đổi của bạn bằng SDK bên ngoài

    Ví dụ sau đây từ phép biến đổi KafkaIO cho thấy cách thực hiện các bước từ hai đến bốn

    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    36

    Để biết thêm ví dụ, hãy xem JavaCountRegistrar và JavaPrefixRegistrar

Sau khi bạn đã triển khai các giao diện

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5467 và
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5468, biến đổi của bạn có thể được đăng ký và tạo thành công bởi dịch vụ mở rộng Java mặc định

Bắt đầu dịch vụ mở rộng

Bạn có thể sử dụng dịch vụ mở rộng với nhiều biến đổi trong cùng một quy trình. Beam Java SDK cung cấp dịch vụ mở rộng mặc định cho các biến đổi Java. Bạn cũng có thể viết dịch vụ mở rộng của riêng mình, nhưng điều đó thường không cần thiết, vì vậy nó không được đề cập trong phần này

Thực hiện các thao tác sau để khởi động trực tiếp dịch vụ mở rộng Java

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
37

Dịch vụ mở rộng hiện đã sẵn sàng để phục vụ các biến đổi trên cổng được chỉ định

Khi tạo trình bao bọc dành riêng cho SDK cho biến đổi của mình, bạn có thể sử dụng các tiện ích do SDK cung cấp để bắt đầu dịch vụ mở rộng. Ví dụ: SDK Python cung cấp các tiện ích

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5480 và
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5481 để khởi động dịch vụ mở rộng Java bằng tệp JAR

bao gồm các phụ thuộc

Nếu biến đổi của bạn yêu cầu các thư viện bên ngoài, bạn có thể đưa chúng vào bằng cách thêm chúng vào đường dẫn lớp của dịch vụ mở rộng. Sau khi chúng được đưa vào đường dẫn lớp, chúng sẽ được phân đoạn khi biến đổi của bạn được mở rộng bởi dịch vụ mở rộng

Viết trình bao bọc dành riêng cho SDK

Biến đổi Java đa ngôn ngữ của bạn có thể được gọi thông qua lớp

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5482 cấp thấp hơn trong một kênh dẫn đa ngôn ngữ [như được mô tả trong phần tiếp theo]; . Sự trừu tượng hóa cấp cao hơn này sẽ giúp các tác giả đường ống sử dụng biến đổi của bạn dễ dàng hơn

Để tạo trình bao bọc SDK để sử dụng trong đường dẫn Python, hãy làm như sau

  1. Tạo một mô-đun Python cho [các] biến đổi ngôn ngữ chéo của bạn

  2. Trong mô-đun, hãy sử dụng một trong các lớp

    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    5483 để xây dựng tải trọng cho yêu cầu mở rộng chuyển đổi ngôn ngữ chéo ban đầu

    Tên tham số và loại tải trọng phải ánh xạ tới tên tham số và loại cấu hình POJO được cung cấp cho Java

    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    5467. Các loại tham số được ánh xạ trên các SDK bằng lược đồ Beam. Tên tham số được ánh xạ bằng cách đơn giản chuyển đổi tên biến được phân tách bằng dấu gạch dưới Python thành trường hợp lạc đà [tiêu chuẩn Java]

    Trong ví dụ sau, kafka. py sử dụng

    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    5485 để xây dựng tải trọng. Các tham số ánh xạ tới Java KafkaIO. Bên ngoài. Đối tượng cấu hình cấu hình được xác định trong phần trước

    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    38

  3. Bắt đầu một dịch vụ mở rộng, trừ khi một dịch vụ được chỉ định bởi người tạo đường ống. Beam Python SDK cung cấp các tiện ích

    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    5480 và
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    5481 để bắt đầu dịch vụ mở rộng bằng tệp JAR.
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    5480 có thể được sử dụng để khởi động dịch vụ mở rộng bằng cách sử dụng đường dẫn [đường dẫn cục bộ hoặc URL] tới tệp JAR đã cho.
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    5481 có thể được sử dụng để bắt đầu dịch vụ mở rộng từ JAR được phát hành với Beam

    Đối với các biến đổi được phát hành bằng Beam, hãy làm như sau

    1. Thêm mục tiêu Gradle vào Beam có thể được sử dụng để xây dựng JAR dịch vụ mở rộng bóng mờ cho biến đổi Java mục tiêu. Mục tiêu này sẽ tạo ra một Beam JAR chứa tất cả các phụ thuộc cần thiết để mở rộng biến đổi Java và JAR sẽ được phát hành cùng với Beam. Bạn có thể sử dụng mục tiêu Gradle hiện có cung cấp phiên bản tổng hợp của dịch vụ mở rộng JAR [ví dụ: cho tất cả GCP IO]

    2. Trong mô-đun Python của bạn, hãy khởi tạo

      await beam.createRunner[].run[function pipeline[root] {
        // Use root to build a pipeline.
      }];
      
      5481 với mục tiêu Gradle

      await beam.createRunner[].run[function pipeline[root] {
        // Use root to build a pipeline.
      }];
      
      39

  4. Thêm lớp biến đổi trình bao bọc Python mở rộng

    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    5482. Truyền tải trọng và dịch vụ mở rộng được xác định ở trên dưới dạng tham số cho hàm tạo của lớp cha
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    5482

13. 1. 2. Tạo các biến đổi Python đa ngôn ngữ

Bất kỳ biến đổi Python nào được xác định trong phạm vi của dịch vụ mở rộng đều có thể truy cập được bằng cách chỉ định tên đủ điều kiện của chúng. Ví dụ: bạn có thể sử dụng biến đổi

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5493 của Python trong một quy trình Java với tên đủ điều kiện của nó là
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5494

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
40

Ghi chú.

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5495 có các phương pháp hữu ích khác, chẳng hạn như
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5496 để dàn dựng các phụ thuộc gói PyPI và
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5497 để đặt bộ mã hóa đầu ra

Ngoài ra, bạn có thể muốn tạo một mô-đun Python đăng ký một biến đổi Python hiện có dưới dạng một biến đổi ngôn ngữ chéo để sử dụng với dịch vụ mở rộng Python và gọi vào biến đổi hiện có đó để thực hiện thao tác dự định của nó. Một URN đã đăng ký có thể được sử dụng sau này trong yêu cầu mở rộng để chỉ ra mục tiêu mở rộng

Xác định mô-đun Python

  1. Xác định Tên tài nguyên thống nhất [URN] cho biến đổi của bạn. URN phải là một chuỗi duy nhất xác định biến đổi của bạn với dịch vụ mở rộng

    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    41

  2. Đối với một biến đổi Python hiện có, hãy tạo một lớp mới để đăng ký URN với dịch vụ mở rộng Python

    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    42

  3. Từ bên trong lớp, định nghĩa một phương thức mở rộng lấy PCollection đầu vào, chạy biến đổi Python, sau đó trả về PCollection đầu ra

    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    43

  4. Cũng như các biến đổi Python khác, hãy xác định phương thức

    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    5498 trả về URN

    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    44

  5. Xác định một phương thức tĩnh

    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    5499 trả về một khởi tạo của biến đổi Python đa ngôn ngữ

    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    45

Bắt đầu dịch vụ mở rộng

Một dịch vụ mở rộng có thể được sử dụng với nhiều biến đổi trong cùng một đường ống. Beam Python SDK cung cấp dịch vụ mở rộng mặc định để bạn sử dụng với các biến đổi Python của mình. Bạn có thể tự do viết dịch vụ mở rộng của riêng mình, nhưng điều đó thường không cần thiết, vì vậy nó không được đề cập trong phần này

Thực hiện các bước sau để khởi động trực tiếp dịch vụ mở rộng Python mặc định

  1. Tạo một môi trường ảo và cài đặt Apache Beam SDK

  2. Bắt đầu dịch vụ mở rộng của SDK Python với một cổng được chỉ định

    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    46

  3. Nhập bất kỳ mô-đun nào có chứa các biến đổi sẽ được cung cấp bằng dịch vụ mở rộng

    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    47

  4. Dịch vụ mở rộng này hiện đã sẵn sàng để phục vụ các biến đổi trên địa chỉ

    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    5500

bao gồm các phụ thuộc

Hiện tại, các phép biến đổi bên ngoài của Python bị giới hạn ở các phần phụ thuộc có sẵn trong bộ khai thác Beam SDK cốt lõi

13. 1. 3. Tạo biến đổi ngôn ngữ chéo

Go hiện không hỗ trợ tạo biến đổi ngôn ngữ chéo, chỉ sử dụng biến đổi ngôn ngữ chéo từ các ngôn ngữ khác;

13. 1. 4. Định nghĩa một URN

Phát triển chuyển đổi ngôn ngữ chéo liên quan đến việc xác định URN để đăng ký chuyển đổi với dịch vụ mở rộng. Trong phần này, chúng tôi cung cấp một quy ước để xác định các URN như vậy. Việc tuân theo quy ước này là tùy chọn nhưng nó sẽ đảm bảo rằng biến đổi của bạn sẽ không gặp xung đột khi đăng ký dịch vụ mở rộng cùng với các biến đổi do các nhà phát triển khác phát triển

13. 1. 4. 1. Lược đồ

Một URN nên bao gồm các thành phần sau

  • ns-id. Một định danh không gian tên. Khuyến nghị mặc định là
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    5501
  • định danh tổ chức. Xác định tổ chức nơi chuyển đổi được xác định. Các biến đổi được xác định trong Apache Beam sử dụng
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    5502 cho việc này
  • định danh chức năng. Xác định chức năng của chuyển đổi ngôn ngữ chéo
  • phiên bản. một số phiên bản cho chuyển đổi

Chúng tôi cung cấp lược đồ từ quy ước URN ở dạng Backus–Naur tăng cường. Từ khóa trong chữ hoa là từ thông số URN

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
48

13. 1. 4. 2. ví dụ

Dưới đây chúng tôi đã đưa ra một số ví dụ về các lớp biến đổi và các URN tương ứng sẽ được sử dụng

  • Một biến đổi được cung cấp với Apache Beam để ghi các tệp Parquet
    • await beam.createRunner[].run[function pipeline[root] {
        // Use root to build a pipeline.
      }];
      
      5503
  • Một biến đổi được cung cấp với Apache Beam đọc từ Kafka với siêu dữ liệu
    • await beam.createRunner[].run[function pipeline[root] {
        // Use root to build a pipeline.
      }];
      
      5504
  • Một chuyển đổi được phát triển bởi tổ chức abc. org đọc từ kho dữ liệu MyDatastore
    • await beam.createRunner[].run[function pipeline[root] {
        // Use root to build a pipeline.
      }];
      
      5505

13. 2. Sử dụng biến đổi ngôn ngữ chéo

Tùy thuộc vào ngôn ngữ SDK của quy trình, bạn có thể sử dụng lớp trình bao bọc SDK cấp cao hoặc lớp chuyển đổi cấp thấp để truy cập chuyển đổi ngôn ngữ chéo

13. 2. 1. Sử dụng các biến đổi ngôn ngữ chéo trong một đường dẫn Java

Người dùng có ba tùy chọn để sử dụng chuyển đổi ngôn ngữ chéo trong đường dẫn Java. Ở mức độ trừu tượng cao nhất, một số biến đổi Python phổ biến có thể truy cập được thông qua các biến đổi trình bao bọc Java chuyên dụng. Ví dụ: SDK Java có lớp

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5506, lớp này sử dụng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5506 của SDK Python và nó có lớp
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5508, lớp này sử dụng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5508 của SDK Python, v.v. Khi biến đổi trình bao bọc dành riêng cho SDK không có sẵn cho biến đổi Python đích, bạn có thể sử dụng lớp PythonExternalTransform cấp thấp hơn thay vào đó bằng cách chỉ định tên đủ điều kiện của biến đổi Python. Nếu bạn muốn thử chuyển đổi bên ngoài từ SDK khác ngoài Python [bao gồm cả SDK Java], bạn cũng có thể sử dụng lớp Bên ngoài cấp thấp nhất

Sử dụng trình bao bọc SDK

Để sử dụng chuyển đổi ngôn ngữ chéo thông qua trình bao bọc SDK, hãy nhập mô-đun cho trình bao bọc SDK và gọi nó từ quy trình của bạn, như minh họa trong ví dụ

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
49

Sử dụng lớp PythonExternalTransform

Khi không có trình bao bọc dành riêng cho SDK, bạn có thể truy cập biến đổi đa ngôn ngữ Python thông qua lớp

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5495 bằng cách chỉ định tên đủ điều kiện và đối số hàm tạo của biến đổi Python đích

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
50

Sử dụng lớp bên ngoài

  1. Đảm bảo rằng bạn đã cài đặt mọi phụ thuộc môi trường thời gian chạy [như JRE] trên máy cục bộ của mình [trực tiếp trên máy cục bộ hoặc có sẵn thông qua bộ chứa]. Xem phần dịch vụ mở rộng để biết thêm chi tiết

    Ghi chú. Khi bao gồm các biến đổi Python từ bên trong đường dẫn Java, tất cả các phần phụ thuộc Python phải được bao gồm trong bộ chứa khai thác SDK

  2. Bắt đầu dịch vụ mở rộng cho SDK bằng ngôn ngữ của biến đổi mà bạn đang cố gắng sử dụng, nếu không có sẵn

    Đảm bảo rằng biến đổi bạn đang cố sử dụng có sẵn và có thể được sử dụng bởi dịch vụ mở rộng

  3. Bao gồm bên ngoài. of[…] khi khởi tạo đường dẫn của bạn. Tham khảo dịch vụ URN, tải trọng và mở rộng. Ví dụ, xem bộ thử nghiệm chuyển đổi ngôn ngữ chéo

  4. Sau khi công việc đã được gửi tới trình chạy Beam, hãy tắt dịch vụ mở rộng bằng cách chấm dứt quy trình dịch vụ mở rộng

13. 2. 2. Sử dụng các biến đổi ngôn ngữ chéo trong một đường dẫn Python

Nếu có trình bao bọc dành riêng cho Python cho biến đổi ngôn ngữ chéo, hãy sử dụng trình bao bọc đó. Mặt khác, bạn phải sử dụng lớp

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5482 cấp thấp hơn để truy cập biến đổi

Sử dụng trình bao bọc SDK

Để sử dụng chuyển đổi ngôn ngữ chéo thông qua trình bao bọc SDK, hãy nhập mô-đun cho trình bao bọc SDK và gọi nó từ quy trình của bạn, như minh họa trong ví dụ

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
51

Sử dụng lớp ExternalTransform

Khi không có trình bao bọc dành riêng cho SDK, bạn sẽ phải truy cập vào chuyển đổi ngôn ngữ chéo thông qua lớp

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5482

  1. Đảm bảo rằng bạn đã cài đặt mọi phụ thuộc môi trường thời gian chạy [như JRE] trên máy cục bộ của mình. Xem phần dịch vụ mở rộng để biết thêm chi tiết

  2. Bắt đầu dịch vụ mở rộng cho SDK bằng ngôn ngữ của biến đổi mà bạn đang cố gắng sử dụng, nếu không có sẵn. Python cung cấp một số lớp để tự động bắt đầu các dịch vụ java mở rộng như JavaJarExpansionService và BeamJarExpansionService có thể được chuyển trực tiếp dưới dạng dịch vụ mở rộng tới

    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    5513. Đảm bảo rằng biến đổi bạn đang cố sử dụng có sẵn và có thể được sử dụng bởi dịch vụ mở rộng

    Đối với Java, đảm bảo rằng trình xây dựng và công ty đăng ký cho biến đổi có sẵn trong đường dẫn lớp của dịch vụ mở rộng

  3. Bao gồm

    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    5482 khi khởi tạo quy trình của bạn. Tham khảo dịch vụ URN, tải trọng và mở rộng. Bạn có thể sử dụng một trong các lớp
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    5483 có sẵn để xây dựng tải trọng cho
    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    5482

    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    52

    Để biết thêm ví dụ, hãy xem addprefix. py và javacount. py

  4. Sau khi công việc đã được gửi tới trình chạy Beam, hãy tắt mọi dịch vụ mở rộng được bắt đầu thủ công bằng cách chấm dứt quy trình dịch vụ mở rộng

Sử dụng lớp JavaExternalTransform

Python có khả năng gọi các phép biến đổi do Java định nghĩa thông qua các đối tượng proxy như thể chúng là các phép biến đổi Python. Chúng được gọi như sau

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
53

Phương thức

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5517 của Python có thể được sử dụng nếu tên phương thức trong java là các từ khóa Python dành riêng, chẳng hạn như
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5518

Cũng như các biến đổi bên ngoài khác, có thể cung cấp dịch vụ mở rộng bắt đầu trước hoặc các tệp jar bao gồm biến đổi, các phần phụ thuộc của nó và dịch vụ mở rộng của Beam, trong trường hợp đó, dịch vụ mở rộng sẽ tự động khởi động

13. 2. 3. Sử dụng chuyển đổi ngôn ngữ chéo trong đường dẫn Go

Nếu có trình bao bọc dành riêng cho Go cho một ngôn ngữ chéo, hãy sử dụng trình bao bọc đó. Mặt khác, bạn phải sử dụng chức năng CrossLanguage cấp thấp hơn để truy cập biến đổi

Dịch vụ mở rộng

Go SDK hỗ trợ tự động bắt đầu các dịch vụ mở rộng Java nếu địa chỉ mở rộng không được cung cấp, mặc dù điều này chậm hơn so với việc cung cấp dịch vụ mở rộng liên tục. Nhiều biến đổi Java được bao gói quản lý thực hiện việc này một cách tự động; . Để sử dụng chuyển đổi ngôn ngữ chéo Python, bạn phải bắt đầu thủ công bất kỳ dịch vụ mở rộng cần thiết nào trên máy cục bộ của mình và đảm bảo chúng có thể truy cập được vào mã của bạn trong quá trình xây dựng đường ống

Sử dụng trình bao bọc SDK

Để sử dụng chuyển đổi ngôn ngữ chéo thông qua trình bao bọc SDK, hãy nhập gói cho trình bao bọc SDK và gọi gói đó từ quy trình của bạn như minh họa trong ví dụ

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
54

Sử dụng chức năng CrossLanguage

Khi không có trình bao bọc dành riêng cho SDK, bạn sẽ phải truy cập vào chuyển đổi ngôn ngữ chéo thông qua chức năng

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5520

  1. Đảm bảo bạn có dịch vụ mở rộng phù hợp đang chạy. Xem phần dịch vụ mở rộng để biết chi tiết

  2. Đảm bảo rằng biến đổi bạn đang cố sử dụng có sẵn và có thể được sử dụng bởi dịch vụ mở rộng. Tham khảo Tạo biến đổi ngôn ngữ chéo để biết chi tiết

  3. Sử dụng chức năng

    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    5520 trong quy trình của bạn khi thích hợp. Tham khảo URN, tải trọng, địa chỉ dịch vụ mở rộng và xác định đầu vào và đầu ra. Bạn có thể sử dụng chùm tia. Chức năng CrossLanguagePayload như một trình trợ giúp để mã hóa tải trọng. Bạn có thể sử dụng chùm tia. UnnamedInput và tia. UnnamedOutput có chức năng như các phím tắt cho các đầu vào/đầu ra đơn lẻ, không tên hoặc xác định bản đồ cho các đầu vào/đầu ra được đặt tên

    await beam.createRunner[].run[function pipeline[root] {
      // Use root to build a pipeline.
    }];
    
    55

  4. Sau khi công việc đã được gửi tới trình chạy Beam, hãy tắt dịch vụ mở rộng bằng cách chấm dứt quy trình dịch vụ mở rộng

13. 2. 4. Sử dụng các biến đổi ngôn ngữ chéo trong một đường ống Bản mô tả

Việc sử dụng trình bao bọc Bản mô tả cho đường dẫn ngôn ngữ chéo cũng tương tự như sử dụng bất kỳ biến đổi nào khác, miễn là các phụ thuộc [e. g. một trình thông dịch Python gần đây hoặc Java JRE] có sẵn. Ví dụ: hầu hết các IO Bản mô tả chỉ đơn giản là các trình bao bọc xung quanh các biến đổi Beam từ các ngôn ngữ khác

Nếu trình bao bọc chưa có sẵn, người ta có thể sử dụng nó một cách rõ ràng bằng cách sử dụng apache_beam. biến đổi. bên ngoài. rawExternalTransform. lấy `urn` [chuỗi xác định biến đổi], `payload` [đối tượng nhị phân hoặc json tham số hóa biến đổi] và `expansionService` có thể là địa chỉ của dịch vụ bắt đầu trước hoặc trả về có thể gọi được

Ví dụ, người ta có thể viết

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
56

Lưu ý rằng

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5522 phải có bộ mã hóa tương thích đa ngôn ngữ, chẳng hạn như
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5523. Điều này có thể được đảm bảo với các biến đổi withCoderInternal hoặc withRowCoder, e. g

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
57

Coder cũng có thể được chỉ định trên đầu ra nếu nó không thể được suy ra, e. g

Ngoài ra, có một số tiện ích như pythonTransform giúp gọi các phép biến đổi từ các ngôn ngữ cụ thể dễ dàng hơn

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
58

Chuyển đổi ngôn ngữ chéo cũng có thể được xác định theo dòng, có thể hữu ích để truy cập các tính năng hoặc thư viện không có sẵn trong SDK gọi

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
59

13. 3. Hỗ trợ người chạy

Hiện tại, các trình chạy di động như Flink, Spark và trình chạy trực tiếp có thể được sử dụng với các đường dẫn đa ngôn ngữ

Dataflow hỗ trợ các đường ống đa ngôn ngữ thông qua kiến ​​trúc phụ trợ Dataflow Runner v2

13. 4 mẹo và khắc phục sự cố

Để biết thêm mẹo và thông tin khắc phục sự cố, hãy xem tại đây

14 DoFn theo đợt

Thích ứng cho
  • SDK Java
  • SDK Python
  • Truy cập SDK
  • SDK TypeScript

Batched DoFns hiện là một tính năng chỉ dành cho Python

Batched DoFns cho phép người dùng tạo các thành phần mô-đun, có thể kết hợp hoạt động theo lô gồm nhiều thành phần logic. Các DoFn này có thể tận dụng các thư viện Python được vector hóa, như numpy, scipy và pandas, hoạt động trên các lô dữ liệu để đạt hiệu quả

14. 1 Khái niệm cơ bản

Batched DoFns hiện là một tính năng chỉ dành cho Python

Một Batched DoFn tầm thường có thể trông như thế này

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
60

DoFn này có thể được sử dụng trong đường ống Beam hoạt động trên các phần tử riêng lẻ. Beam sẽ hoàn toàn đệm các phần tử và tạo các mảng có nhiều mảng ở phía đầu vào và ở phía đầu ra, nó sẽ phân tách các mảng có nhiều mảng thành các phần tử riêng lẻ

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
61

Lưu ý rằng chúng tôi sử dụng

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5524 để đặt kiểu chữ theo từng phần tử cho đầu ra của
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5525. Sau đó, khi áp dụng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5526 cho
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
73 này, Beam nhận ra rằng
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5528 là loại lô có thể chấp nhận được để sử dụng cùng với các phần tử
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5529. Chúng tôi sẽ sử dụng các gợi ý kiểu chữ gọn gàng như thế này trong suốt hướng dẫn này, nhưng Beam cũng hỗ trợ các gợi ý kiểu chữ từ các thư viện khác, hãy xem Các loại hàng loạt được hỗ trợ

Trong trường hợp trước, Beam sẽ ngầm tạo và phát nổ các lô ở ranh giới đầu vào và đầu ra. Tuy nhiên, nếu Batched DoFns với các loại tương đương được xâu chuỗi lại với nhau, việc tạo và phát nổ hàng loạt này sẽ bị loại bỏ. Các lô sẽ được chuyển thẳng qua. Điều này làm cho việc tổng hợp hiệu quả các biến đổi hoạt động theo lô trở nên đơn giản hơn nhiều

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
62

14. Dự phòng 2 phần tử

Batched DoFns hiện là một tính năng chỉ dành cho Python

Đối với một số DoFns, bạn có thể cung cấp cả triển khai theo đợt và theo từng phần tử theo logic mong muốn của mình. Bạn có thể làm điều này bằng cách xác định cả

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
630 và
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5531

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
63

Khi thực hiện DoFn này, Beam sẽ chọn cách triển khai tốt nhất để sử dụng trong bối cảnh nhất định. Nói chung, nếu các đầu vào cho DoFn đã được theo đợt thì Beam sẽ sử dụng triển khai theo đợt;

Lưu ý rằng, trong trường hợp này, không cần xác định

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5533. Điều này là do Beam có thể lấy loại đầu ra từ gợi ý đánh máy trên
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
630

14. 3 Sản xuất hàng loạt so với. tiêu thụ hàng loạt

Batched DoFns hiện là một tính năng chỉ dành cho Python

Theo quy ước, Beam giả định rằng phương pháp

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5531, sử dụng các đầu vào theo đợt, cũng sẽ tạo ra các đầu ra theo đợt. Tương tự, Beam giả sử phương pháp
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
630 sẽ tạo ra các phần tử riêng lẻ. Điều này có thể được ghi đè bằng các trình trang trí
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5537 và
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5538. Ví dụ

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
64

14. 4 loại lô được hỗ trợ

Batched DoFns hiện là một tính năng chỉ dành cho Python

Chúng tôi đã sử dụng các loại numpy trong triển khai Batched DoFn trong hướng dẫn này –

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5539 làm gợi ý kiểu phần tử và
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5528 làm gợi ý kiểu lô tương ứng – nhưng Beam cũng hỗ trợ các gợi ý kiểu chữ từ các thư viện khác

cục mịch

Loại phần tửgợi ýLoại hàng loạtgợi ýCác loại số [
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
601,
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5542,
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5543,…] np. ndarray [của Mảng Numpy]

gấu trúc

Loại phần tửgợi ý Loại hàng loạtgợi ýCác loại số [
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
601,
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5542,
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5543,…]
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5547
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5548
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5057Các loại giản đồ chùm
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5550

Các loại khác?

Nếu có các loại lô khác mà bạn muốn sử dụng với Batched DoFns, vui lòng gửi vấn đề

14. 5 loại đầu vào và đầu ra hàng loạt động

Batched DoFns hiện là một tính năng chỉ dành cho Python

Đối với một số DoFn theo lô, có thể không đủ để khai báo các loại lô một cách tĩnh, với các gợi ý về kiểu chữ trên

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
630 và/hoặc
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5531. Bạn có thể cần phải khai báo động các kiểu này. Bạn có thể thực hiện việc này bằng cách ghi đè các phương thức
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5553 và
await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5554 trên DoFn của mình

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
65

14. 6 lô và ngữ nghĩa thời gian sự kiện

Batched DoFns hiện là một tính năng chỉ dành cho Python

Hiện tại, các lô phải có một bộ thông tin thời gian duy nhất [thời gian sự kiện, cửa sổ, v.v.] áp dụng cho mọi thành phần logic trong lô. Hiện tại không có cơ chế để tạo các lô kéo dài nhiều dấu thời gian. Tuy nhiên, có thể truy xuất thông tin thời gian này trong triển khai Batched DoFn. Thông tin này có thể được truy cập bằng cách sử dụng các thuộc tính

await beam.createRunner[].run[function pipeline[root] {
  // Use root to build a pipeline.
}];
5555 thông thường

Chủ Đề