tableRows =
80 | MusicBrainzTransforms.transformToTableRows(artistsWithRecordings, bqTableSchema);
81 | /*
82 | * write the tablerows to Big Query
83 | */
84 | try {
85 | tableRows.apply(
86 | "Write to BigQuery",
87 | BigQueryIO.writeTableRows()
88 | .to(options.getBigQueryTablename())
89 | .withSchema(bqTableSchema)
90 | .withWriteDisposition(BigQueryIO.Write.WriteDisposition.WRITE_TRUNCATE)
91 | .withCreateDisposition(BigQueryIO.Write.CreateDisposition.CREATE_IF_NEEDED));
92 | } catch (Exception e) {
93 | logger.error("error writing to BQ: ", e);
94 | }
95 | p.run().waitUntilFinish();
96 | }
97 |
98 | private static TableSchema bqSchema() {
99 | return FieldSchemaListBuilder.create()
100 | .intField("artist_id")
101 | .stringField("artist_gid")
102 | .stringField("artist_name")
103 | .stringField("artist_sort_name")
104 | .intField("artist_begin_date_year")
105 | .intField("artist_begin_date_month")
106 | .intField("artist_begin_date_day")
107 | .intField("artist_end_date_year")
108 | .intField("artist_end_date_month")
109 | .intField("artist_end_date_day")
110 | .intField("artist_type")
111 | .stringField("artist_area")
112 | .stringField("artist_gender")
113 | .intField("artist_edits_pending")
114 | .timestampField("artist_last_updated")
115 | .stringField("artist_comment")
116 | .boolField("artist_ended")
117 | .stringField("artist_begin_area")
118 | .field(
119 | FieldSchemaListBuilder.create()
120 | .intField("artist_credit_name_artist_credit")
121 | .intField("artist_credit_name_position")
122 | .intField("artist_credit_name_artist")
123 | .stringField("artist_credit_name_name")
124 | .stringField("artist_credit_name_join_phrase")
125 | .intField("recording_id")
126 | .stringField("recording_gid")
127 | .stringField("recording_name")
128 | .intField("recording_length")
129 | .stringField("recording_comment")
130 | .intField("recording_edits_pending")
131 | .timestampField("recording_last_updated")
132 | .boolField("recording_video")
133 | .repeatedRecord("artist_recordings"))
134 | .schema();
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/src/main/java/com/google/cloud/bqetl/BQETLSimple.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022 Google LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.google.cloud.bqetl;
18 |
19 | import com.google.api.services.bigquery.model.TableRow;
20 | import com.google.api.services.bigquery.model.TableSchema;
21 | import com.google.cloud.bqetl.mbdata.MusicBrainzDataObject;
22 | import com.google.cloud.bqetl.mbdata.MusicBrainzTransforms;
23 | import com.google.cloud.bqetl.mbschema.FieldSchemaListBuilder;
24 | import com.google.cloud.bqetl.options.BQETLOptions;
25 | import org.apache.beam.sdk.Pipeline;
26 | import org.apache.beam.sdk.io.gcp.bigquery.BigQueryIO;
27 | import org.apache.beam.sdk.options.PipelineOptionsFactory;
28 | import org.apache.beam.sdk.options.ValueProvider.StaticValueProvider;
29 | import org.apache.beam.sdk.values.KV;
30 | import org.apache.beam.sdk.values.PCollection;
31 |
32 | /**
33 | * This is a pipeline that denormalizes exported data from the musicbrainz dataset to create a
34 | * flattened, denormalized Big Query table of artists' recordings that repeats artist information
35 | * for each of their credited recordings.
36 | *
37 | * In addition to standard Pipeline parameters, this main program takes the following additional
38 | * parameters: --bigQueryTablename= :.
39 | * --loadingBucketURL=gs://
40 | *
41 | * An example of how to run this pipeline: mvn compile exec:java \ -Dexec.mainClass=BQETLSimple \
42 | * -Dexec.args="--project=jlb-onboarding \ --loadingBucketURL=gs://mb-data \
43 | * --stagingLocation=gs://mb-data \ --runner=BlockingDataflowPipelineRunner \ --numWorkers=185 \
44 | * --maxNumWorkers=500 \ --bigQueryTablename=example_project:example_dataset.example_table \
45 | * --diskSizeGb=1000 \ --workerMachineType=n1-standard-1"
46 | */
47 | public class BQETLSimple {
48 |
49 | public static void main(String[] args) {
50 | PipelineOptionsFactory.register(BQETLOptions.class);
51 |
52 | /*
53 | * get the custom options
54 | */
55 | BQETLOptions options =
56 | PipelineOptionsFactory.fromArgs(args).withValidation().as(BQETLOptions.class);
57 | Pipeline p = Pipeline.create(options);
58 |
59 | /*
60 | * load the line delimited JSON files into keyed PCollections
61 | */
62 | PCollection> artists;
63 | if (options.getPerformLookups()) {
64 | // [START loadArtistsWithLookups]
65 | artists =
66 | MusicBrainzTransforms.loadTable(
67 | p,
68 | "artist",
69 | "id",
70 | MusicBrainzTransforms.lookup("area", "id", "name", "area", "begin_area"),
71 | MusicBrainzTransforms.lookup("gender", "id", "name", "gender"));
72 | // [END loadArtistsWithLookups]
73 | } else {
74 | artists = MusicBrainzTransforms.loadTable(p, "artist", "id");
75 | }
76 | PCollection> artistCreditName =
77 | MusicBrainzTransforms.loadTable(p, "artist_credit_name", "artist");
78 | PCollection> recordingsByArtistCredit =
79 | MusicBrainzTransforms.loadTable(p, "recording", "artist_credit");
80 |
81 | /*
82 | * perform inner joins
83 | */
84 | // [START artist_artist_credit_join]
85 | PCollection artistCredits =
86 | MusicBrainzTransforms.innerJoin("artists with artist credits", artists, artistCreditName);
87 | // [END artist_artist_credit_join]
88 | // [START byCall]
89 | PCollection> artistCreditNamesByArtistCredit =
90 | MusicBrainzTransforms.by("artist_credit_name_artist_credit", artistCredits);
91 | // [END byCall]
92 | // [START joinCall]
93 | PCollection artistRecordings =
94 | MusicBrainzTransforms.innerJoin(
95 | "joined recordings", artistCreditNamesByArtistCredit, recordingsByArtistCredit);
96 | // [END joinCall]
97 |
98 | /*
99 | * create the table schema for Big Query
100 | */
101 | TableSchema bqTableSchema = bqSchema(options.getPerformLookups());
102 | /*
103 | * transform the joined MusicBrainzDataObject results into BQ Table rows
104 | */
105 | // [START transformToTableRowCall]
106 | PCollection tableRows =
107 | MusicBrainzTransforms.transformToTableRows(artistRecordings, bqTableSchema);
108 | // [END transformToTableRowCall]
109 | /*
110 | * write the tablerows to Big Query
111 | */
112 | // [START bigQueryWrite]
113 | tableRows.apply(
114 | "Write to BigQuery",
115 | BigQueryIO.writeTableRows()
116 | .to(options.getBigQueryTablename())
117 | .withSchema(bqTableSchema)
118 | .withCustomGcsTempLocation(StaticValueProvider.of(options.getTempLocation()))
119 | .withWriteDisposition(BigQueryIO.Write.WriteDisposition.WRITE_TRUNCATE)
120 | .withCreateDisposition(BigQueryIO.Write.CreateDisposition.CREATE_IF_NEEDED));
121 | // [END bigQueryWrite]
122 |
123 | p.run().waitUntilFinish();
124 | }
125 |
126 | private static TableSchema bqSchema(boolean usingAreaGenderLookups) {
127 | FieldSchemaListBuilder fieldSchemaListBuilder = new FieldSchemaListBuilder();
128 |
129 | fieldSchemaListBuilder
130 | .intField("artist_id")
131 | .stringField("artist_gid")
132 | .stringField("artist_name")
133 | .stringField("artist_sort_name")
134 | .intField("artist_begin_date_year")
135 | .intField("artist_begin_date_month")
136 | .intField("artist_begin_date_day")
137 | .intField("artist_end_date_year")
138 | .intField("artist_end_date_month")
139 | .intField("artist_end_date_day")
140 | .intField("artist_type")
141 | .intField("artist_edits_pending")
142 | .timestampField("artist_last_updated")
143 | .stringField("artist_comment")
144 | .boolField("artist_ended")
145 | .intField("artist_credit_name_artist_credit")
146 | .intField("artist_credit_name_position")
147 | .intField("artist_credit_name_artist")
148 | .stringField("artist_credit_name_name")
149 | .stringField("artist_credit_name_join_phrase")
150 | .intField("recording_id")
151 | .stringField("recording_gid")
152 | .stringField("recording_name")
153 | .intField("recording_artist_credit")
154 | .intField("recording_length")
155 | .stringField("recording_comment")
156 | .intField("recording_edits_pending")
157 | .timestampField("recording_last_updated")
158 | .boolField("recording_video");
159 |
160 | if (usingAreaGenderLookups) {
161 | fieldSchemaListBuilder
162 | .stringField("artist_area")
163 | .stringField("artist_gender")
164 | .stringField("artist_begin_area");
165 | } else {
166 | fieldSchemaListBuilder
167 | .intField("artist_area")
168 | .intField("artist_gender")
169 | .intField("artist_begin_area");
170 | }
171 |
172 | return fieldSchemaListBuilder.schema();
173 | }
174 | }
175 |
--------------------------------------------------------------------------------
/src/test/resources/artist_credit_name.json:
--------------------------------------------------------------------------------
1 | {"artist_credit":634509,"position":0,"artist":634509,"name":"Justin Bieber","join_phrase":""}
2 | {"artist_credit":820684,"position":1,"artist":634509,"name":"Justin Bieber","join_phrase":""}
3 | {"artist_credit":835671,"position":1,"artist":634509,"name":"Justin Bieber","join_phrase":""}
4 | {"artist_credit":846330,"position":0,"artist":634509,"name":"Justin Bieber","join_phrase":" feat. "}
5 | {"artist_credit":846331,"position":0,"artist":634509,"name":"Justin Bieber","join_phrase":" feat. "}
6 | {"artist_credit":846332,"position":0,"artist":634509,"name":"Justin Bieber","join_phrase":" feat. "}
7 | {"artist_credit":857848,"position":0,"artist":634509,"name":"Justin Bieber","join_phrase":" feat. "}
8 | {"artist_credit":857849,"position":0,"artist":634509,"name":"Justin Bieber","join_phrase":" & "}
9 | {"artist_credit":871457,"position":1,"artist":634509,"name":"Justin Bieber","join_phrase":""}
10 | {"artist_credit":999502,"position":0,"artist":634509,"name":"Justin Bieber","join_phrase":" feat. "}
11 | {"artist_credit":999503,"position":0,"artist":634509,"name":"Justin Bieber","join_phrase":" feat. "}
12 | {"artist_credit":904694,"position":0,"artist":634509,"name":"Justin Bieber","join_phrase":" with "}
13 | {"artist_credit":904702,"position":0,"artist":634509,"name":"Justin Bieber","join_phrase":" feat. "}
14 | {"artist_credit":904703,"position":0,"artist":634509,"name":"Justin Bieber","join_phrase":" feat. "}
15 | {"artist_credit":904704,"position":0,"artist":634509,"name":"Justin Bieber","join_phrase":" feat. "}
16 | {"artist_credit":904705,"position":0,"artist":634509,"name":"Justin Bieber","join_phrase":" feat. "}
17 | {"artist_credit":890575,"position":0,"artist":634509,"name":"Justin Bieber","join_phrase":" feat. "}
18 | {"artist_credit":890576,"position":0,"artist":634509,"name":"Justin Bieber","join_phrase":" feat. "}
19 | {"artist_credit":890577,"position":0,"artist":634509,"name":"Justin Bieber","join_phrase":" feat. "}
20 | {"artist_credit":897870,"position":1,"artist":634509,"name":"Justin Bieber","join_phrase":" & "}
21 | {"artist_credit":999754,"position":1,"artist":634509,"name":"Justin Bieber","join_phrase":" & "}
22 | {"artist_credit":917362,"position":0,"artist":634509,"name":"Justin Bieber","join_phrase":" feat. "}
23 | {"artist_credit":999099,"position":0,"artist":634509,"name":"Justin Bieber","join_phrase":" feat. "}
24 | {"artist_credit":1007132,"position":1,"artist":634509,"name":"Justin Bieber","join_phrase":""}
25 | {"artist_credit":919196,"position":1,"artist":634509,"name":"Justin Bieber","join_phrase":""}
26 | {"artist_credit":964779,"position":1,"artist":634509,"name":"Justin Bieber","join_phrase":""}
27 | {"artist_credit":1027242,"position":0,"artist":634509,"name":"Justin Bieber","join_phrase":" feat. "}
28 | {"artist_credit":1052228,"position":1,"artist":634509,"name":"Justin Bieber","join_phrase":""}
29 | {"artist_credit":1067702,"position":0,"artist":634509,"name":"Justin Bieber","join_phrase":" & "}
30 | {"artist_credit":1093597,"position":0,"artist":634509,"name":"Justin Bieber","join_phrase":" & "}
31 | {"artist_credit":1170806,"position":0,"artist":634509,"name":"Justin Bieber","join_phrase":", "}
32 | {"artist_credit":1122987,"position":1,"artist":634509,"name":"Justin Bieber","join_phrase":""}
33 | {"artist_credit":1141329,"position":1,"artist":634509,"name":"Justin Bieber","join_phrase":""}
34 | {"artist_credit":1182229,"position":2,"artist":634509,"name":"Justin Bieber","join_phrase":""}
35 | {"artist_credit":1183195,"position":2,"artist":634509,"name":"Justin Bieber","join_phrase":" & "}
36 | {"artist_credit":1482172,"position":2,"artist":634509,"name":"Justin Bieber","join_phrase":""}
37 | {"artist_credit":1208426,"position":0,"artist":634509,"name":"Justin Bieber","join_phrase":" & "}
38 | {"artist_credit":1218129,"position":2,"artist":634509,"name":"Justin Bieber","join_phrase":""}
39 | {"artist_credit":1234197,"position":1,"artist":634509,"name":"Justin Bieber","join_phrase":""}
40 | {"artist_credit":1239695,"position":0,"artist":634509,"name":"Justin Bieber","join_phrase":" feat. "}
41 | {"artist_credit":1247041,"position":0,"artist":634509,"name":"Justin Bieber","join_phrase":" feat. "}
42 | {"artist_credit":1249078,"position":0,"artist":634509,"name":"Justin Bieber","join_phrase":" feat. "}
43 | {"artist_credit":1249079,"position":0,"artist":634509,"name":"Justin Bieber","join_phrase":" feat. "}
44 | {"artist_credit":1286965,"position":2,"artist":634509,"name":"Justin Bieber","join_phrase":""}
45 | {"artist_credit":1293773,"position":5,"artist":634509,"name":"Justin Bieber","join_phrase":", "}
46 | {"artist_credit":1294704,"position":1,"artist":634509,"name":"Justin Bieber","join_phrase":" & "}
47 | {"artist_credit":1331108,"position":1,"artist":634509,"name":"Justin Bieber","join_phrase":""}
48 | {"artist_credit":1345536,"position":0,"artist":634509,"name":"Justin Bieber","join_phrase":" feat. "}
49 | {"artist_credit":1355031,"position":2,"artist":634509,"name":"Justin Bieber","join_phrase":""}
50 | {"artist_credit":1356581,"position":1,"artist":634509,"name":"Justin Bieber","join_phrase":""}
51 | {"artist_credit":1420071,"position":1,"artist":634509,"name":"Justin Bieber","join_phrase":""}
52 | {"artist_credit":1436473,"position":0,"artist":634509,"name":"Justin Bieber","join_phrase":" & "}
53 | {"artist_credit":1493844,"position":1,"artist":634509,"name":"Justin Bieber","join_phrase":""}
54 | {"artist_credit":1529552,"position":1,"artist":634509,"name":"Justin Bieber","join_phrase":" & "}
55 | {"artist_credit":1534055,"position":1,"artist":634509,"name":"Justin Bieber","join_phrase":""}
56 | {"artist_credit":1561294,"position":1,"artist":634509,"name":"Justin Bieber","join_phrase":""}
57 | {"artist_credit":1564254,"position":0,"artist":634509,"name":"Justin Bieber","join_phrase":" feat. "}
58 | {"artist_credit":1564256,"position":0,"artist":634509,"name":"Justin Bieber","join_phrase":" feat. "}
59 | {"artist_credit":1564257,"position":0,"artist":634509,"name":"Justin Bieber","join_phrase":" feat. "}
60 | {"artist_credit":1564258,"position":0,"artist":634509,"name":"Justin Bieber","join_phrase":" feat. "}
61 | {"artist_credit":1564259,"position":0,"artist":634509,"name":"Justin Bieber","join_phrase":" & "}
62 | {"artist_credit":1564540,"position":2,"artist":634509,"name":"Justin Bieber","join_phrase":""}
63 | {"artist_credit":1568753,"position":1,"artist":634509,"name":"Justin Bieber","join_phrase":" & "}
64 | {"artist_credit":1586223,"position":0,"artist":634509,"name":"Justin Bieber","join_phrase":" feat. "}
65 | {"artist_credit":1588820,"position":0,"artist":634509,"name":"Justin Bieber feat. Usher","join_phrase":""}
66 | {"artist_credit":1588821,"position":0,"artist":634509,"name":"Justin Bieber feat. Ludacris","join_phrase":""}
67 | {"artist_credit":1588822,"position":0,"artist":634509,"name":"Justin Bieber feat. Jessica Jarrell","join_phrase":""}
68 | {"artist_credit":1588823,"position":0,"artist":634509,"name":"Justin Bieber with Sean Kingston","join_phrase":""}
69 | {"artist_credit":1596359,"position":2,"artist":634509,"name":"Justin Bieber","join_phrase":""}
70 | {"artist_credit":1602071,"position":2,"artist":634509,"name":"Justin Bieber","join_phrase":""}
71 | {"artist_credit":1602072,"position":0,"artist":634509,"name":"Justin Bieber","join_phrase":" feat. "}
72 | {"artist_credit":1620423,"position":0,"artist":634509,"name":"Justin Bieber","join_phrase":" duet with "}
73 | {"artist_credit":1625803,"position":1,"artist":634509,"name":"Justin Bieber","join_phrase":""}
74 | {"artist_credit":1630569,"position":3,"artist":634509,"name":"Justin Bieber","join_phrase":""}
75 | {"artist_credit":1656741,"position":1,"artist":634509,"name":"Justin Bieber","join_phrase":" & "}
76 | {"artist_credit":1674737,"position":1,"artist":634509,"name":"Justin Bieber","join_phrase":""}
77 | {"artist_credit":1689843,"position":1,"artist":634509,"name":"Justin Bieber","join_phrase":""}
78 | {"artist_credit":1690683,"position":1,"artist":634509,"name":"Justin Bieber","join_phrase":""}
79 | {"artist_credit":1690777,"position":1,"artist":634509,"name":"Justin Bieber","join_phrase":" & "}
80 |
--------------------------------------------------------------------------------
/src/test/java/com/google/cloud/bqetl/mbdata/MusicBrainzTransformsTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022 Google LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.google.cloud.bqetl.mbdata;
18 |
19 | import static java.util.stream.Collectors.toList;
20 |
21 | import java.io.BufferedReader;
22 | import java.io.InputStream;
23 | import java.io.InputStreamReader;
24 | import java.util.AbstractMap.SimpleEntry;
25 | import java.util.ArrayList;
26 | import java.util.Collections;
27 | import java.util.List;
28 | import java.util.Map;
29 | import org.apache.beam.sdk.coders.StringUtf8Coder;
30 | import org.apache.beam.sdk.testing.PAssert;
31 | import org.apache.beam.sdk.testing.TestPipeline;
32 | import org.apache.beam.sdk.transforms.Count;
33 | import org.apache.beam.sdk.transforms.Create;
34 | import org.apache.beam.sdk.transforms.Keys;
35 | import org.apache.beam.sdk.transforms.MapElements;
36 | import org.apache.beam.sdk.values.KV;
37 | import org.apache.beam.sdk.values.PCollection;
38 | import org.apache.beam.sdk.values.PCollectionView;
39 | import org.apache.beam.sdk.values.TypeDescriptor;
40 | import org.junit.runner.RunWith;
41 | import org.junit.runners.JUnit4;
42 | import org.slf4j.Logger;
43 | import org.slf4j.LoggerFactory;
44 |
45 | @RunWith(JUnit4.class)
46 | public class MusicBrainzTransformsTest {
47 |
48 | private List artistCreditLinesOfJson;
49 | private List recordingLinesOfJson;
50 | private List artistLinesOfJson;
51 | private List areaLinesOfJson;
52 |
53 | static final Logger LOG = LoggerFactory.getLogger(MusicBrainzTransformsTest.class);
54 |
55 | @org.junit.Test
56 | public void loadArtistCreditsByKey() {
57 |
58 | TestPipeline p = TestPipeline.create().enableAbandonedNodeEnforcement(false);
59 |
60 | Long[] artistCreditIds = {634509L, 846332L};
61 | PCollection text =
62 | p.apply(Create.of(artistCreditLinesOfJson)).setCoder(StringUtf8Coder.of());
63 | PCollection> artistCredits =
64 | MusicBrainzTransforms.loadTableFromText(text, "artist_credit_name", "artist_credit");
65 |
66 | PCollection artistCreditIdPCollection = artistCredits.apply(Keys.create());
67 | PAssert.that(artistCreditIdPCollection).containsInAnyOrder(634509L, 846332L);
68 | }
69 |
70 | @org.junit.Test
71 | public void joinArtistCreditsWithRecordings() {
72 |
73 | TestPipeline p = TestPipeline.create().enableAbandonedNodeEnforcement(false);
74 |
75 | PCollection artistCreditText =
76 | p.apply("artistCredits", Create.of(artistCreditLinesOfJson)).setCoder(StringUtf8Coder.of());
77 |
78 | PCollection> artistCredits =
79 | MusicBrainzTransforms.loadTableFromText(
80 | artistCreditText, "artist_credit_name", "artist_credit");
81 |
82 | PCollection recordingText =
83 | p.apply("recordings", Create.of(recordingLinesOfJson)).setCoder(StringUtf8Coder.of());
84 |
85 | PCollection> recordings =
86 | MusicBrainzTransforms.loadTableFromText(recordingText, "recording", "artist_credit");
87 |
88 | PCollection joinedRecordings =
89 | MusicBrainzTransforms.innerJoin(
90 | "artist credits with recordings", artistCredits, recordings);
91 |
92 | PCollection recordingIds =
93 | joinedRecordings.apply(
94 | MapElements.into(new TypeDescriptor() {})
95 | .via((MusicBrainzDataObject mbo) -> (Long) mbo.getColumnValue("recording_id")));
96 |
97 | Long bieberRecording = 17069165L;
98 | Long bieberRecording2 = 15508507L;
99 |
100 | PAssert.that(recordingIds)
101 | .satisfies(
102 | (longs) -> {
103 | List theList = new ArrayList<>();
104 | longs.forEach(theList::add);
105 | assert (theList.contains(bieberRecording));
106 | assert (theList.contains(bieberRecording2));
107 | return null;
108 | });
109 |
110 | PCollection numberJoined =
111 | joinedRecordings.apply("count joined recordings", Count.globally());
112 | PCollection numberOfArtistCredits =
113 | artistCredits.apply("count artist credits", Count.globally());
114 |
115 | PAssert.thatSingleton(numberJoined).isEqualTo(448L);
116 |
117 | p.run();
118 | }
119 |
120 | @org.junit.Test
121 | public void loadArtistsWithMapping() {
122 |
123 | TestPipeline p = TestPipeline.create().enableAbandonedNodeEnforcement(false);
124 |
125 | PCollection artistText =
126 | p.apply("artist", Create.of(artistLinesOfJson)).setCoder(StringUtf8Coder.of());
127 |
128 | List, PCollectionView