Run SubgraphSampler on Dataproc 2.2 / Spark 3.5 before image 2.0 becomes uncreatable - #738
Run SubgraphSampler on Dataproc 2.2 / Spark 3.5 before image 2.0 becomes uncreatable#738kmontemayor2-sc wants to merge 5 commits into
Conversation
Google blocks Dataproc image 2.0 cluster creation on 2026-08-25, so the V1 SubgraphSampler must run on image 2.2 via the scala_spark35 jar. That jar's TaskRunner threw "PureSpark SGS not supported in spark35 yet." for the non-graphdb node-anchor-based link prediction path, which is exactly what the cora_nalp/cora_udl e2e tests use. - TaskRunner: replace the throw with the NALP/UDL dispatch ported from scala/subgraph_sampler TaskRunner (UDL detection via isPos/isNegUserDefinedForCondensedEdgeType). - SGSPureSparkV1Task: restore the sampleWithReplacement feature (UDF, default params on the three sampling methods, SQL branches) that the ported tests exercise. The spark35 comment fixes are kept; this is not a wholesale copy of the spark31 file. - Port the 4 pureSpark test suites (only import-path edits plus the SupervisedNodeClassificationTask ctor difference); test assets already existed in this tree. Deliberately unported: the sample_with_replacement experimental-flag reading in the NALP/UDL task classes (documented parity gap), and any heterogeneous-graph support. sbt "subgraph_sampler/test": 25 tests, 7 suites, 0 failures. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Google blocks Dataproc image 2.0 cluster creation on 2026-08-25; the use_spark35=False path creates 2.0.47 clusters. Flip the use_spark35_runner experimental-flag default to "True" so default-configured pipelines (including the cora e2e tests) move to Dataproc 2.2 now, while an explicit "False" remains a rollback escape hatch until the 2.0 branch is deleted after the cutoff. test_subgraph_sampler_for_spark now exercises the new default: the spark35 sidecar jar is uploaded and passed alongside the 3.5 tfrecord jar, and the cluster is created with use_spark35=True. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2.2.19 is over a year stale; 2.2.85 (2026-06-30, Spark 3.5.3) is the newest 2.2.x listed on the Dataproc release page. Separate commit because this line also moves SplitGenerator, which already runs on 2.2 unconditionally, so the bump can be reverted independently of the SubgraphSampler migration. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
/all_test |
GiGL Automation@ 17:12:42UTC : 🔄 @ 18:29:45UTC : ✅ Workflow completed successfully. |
GiGL Automation@ 17:12:42UTC : 🔄 |
GiGL Automation@ 17:12:42UTC : 🔄 @ 17:14:38UTC : ✅ Workflow completed successfully. |
GiGL Automation@ 17:12:43UTC : 🔄 @ 17:23:46UTC : ✅ Workflow completed successfully. |
GiGL Automation@ 17:12:44UTC : 🔄 @ 18:44:12UTC : ✅ Workflow completed successfully. |
GiGL Automation@ 17:12:44UTC : 🔄 @ 17:22:21UTC : ✅ Workflow completed successfully. |
This reverts commit f78347840e2c99b40a0b28cbc4b19b48eec9c1a6.
Image 2.2.85 breaks the SubgraphSampler Spark job. Every V1 e2e pipeline
failed within minutes of the cluster coming up, all with the same error:
Exception in thread "main" java.lang.NoClassDefFoundError: io/grpc/Context
dblp_nalp fails too, and it already ran the spark35 jar on 2.2.19 before this
branch, so the sub-minor is the variable, not the ported pureSpark code. 2.2.85
evidently ships a different gRPC classpath than 2.2.19.
2.2.19 stays on a supported minor, and escaping image 2.0 before it becomes
uncreatable on 2026-08-25 does not require the newest sub-minor. Bumping it is
worth doing separately, once the classpath change is understood.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The three pureSpark `castTo*ProtoSchema` functions renamed only top-level columns to their proto names. Array-of-struct columns were passed through carrying the sampling pipeline's internal `_`-prefixed element field names (`_node_id`, `_src_node`, ...). The always-empty `neg_edges` / `hard_neg_edges` were emitted as bare `ARRAY()` literals. Both were latent bugs that `sparksql31-scalapb0_11 1.0.0` hid. In 1.0.0, `FromCatalystHelpers.fieldFromCatalyst` wrapped repeated fields in `MapObjects(lambda, input, protoSql.singularDataType(fd))`. The lambda variable carried the proto's *declared* struct type, so the by-name field lookup inside the lambda resolved against the declared names and compiled down to ordinal access. At runtime the data was therefore read positionally and the wrong element names never mattered. Field order happens to match the proto at every creation site, so Spark 3.1 produced correct protos regardless. `sparksql35-scalapb0_11 1.0.4` builds the deserializer with `UnresolvedMapObjects` instead, deferring element typing to the analyzer. Spark's `ResolveDeserializer` binds the lambda variable to the *actual* element type and resolves fields by name, which fails at analysis time: [FIELD_NOT_FOUND] No such struct field `node_id` in `_node_id`, `_condensed_node_type`, `_feature_values` A bare `ARRAY()` is `ARRAY<VOID>`, and with no declared element type the analyzer has nothing to bind the lambda variable to there either: [INVALID_EXTRACT_BASE_FIELD_TYPE] Can't extract a value from "lambdavariable(MapObject, NullType, false, 347)" ... but got "VOID" This is why cora_nalp, cora_udl and cora_snc all die in SubgraphSampler on Dataproc 2.2 while dblp_nalp passes -- dblp takes the GraphDB path, whose SQL already aliases nested fields to the proto names. Downgrading is not an option: only 1.0.4 and 1.0.5 exist for the `sparksql35` artifact, and both postdate the change. Rewrite the element field names to the proto names at the cast boundary with `transform`, and give the empty edge arrays an explicit element type. The rewrite lives in three shared helpers on `SGSPureSparkV1Task` so the five call sites across the three cast functions cannot drift apart. `transform` is NULL-safe, so the UNION branches that emit `NULL` for their neighbor arrays still deserialize to empty sequences. Creation sites and intermediate joins keep their `_`-prefixed convention. The legacy `scala/` (Spark 3.1) tree is deliberately left alone: 1.0.0's positional semantics make the same code correct there, and it is being retired. No pureSpark test previously crossed the `castTo*` + `.as[proto]` boundary, which is why this reached production, so add two regression tests. The RootedNodeNeighborhood one uses the production loaders against the checked-in TFRecord assets rather than this suite's mock fixtures, since those mocks use scalar/double features that the proto encoder rejects for unrelated reasons. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
/all_test |
GiGL Automation@ 03:29:10UTC : 🔄 @ 04:33:21UTC : ✅ Workflow completed successfully. |
GiGL Automation@ 03:29:12UTC : 🔄 @ 03:41:00UTC : ✅ Workflow completed successfully. |
GiGL Automation@ 03:29:14UTC : 🔄 @ 03:31:19UTC : ✅ Workflow completed successfully. |
GiGL Automation@ 03:29:15UTC : 🔄 @ 05:04:55UTC : ✅ Workflow completed successfully. |
GiGL Automation@ 03:29:19UTC : 🔄 @ 03:38:23UTC : ✅ Workflow completed successfully. |
GiGL Automation@ 03:29:21UTC : 🔄 @ 04:44:37UTC : ❌ Workflow failed. |
yliu2-sc
left a comment
There was a problem hiding this comment.
Do we actually need all those tests? I think AI added a lot of tests which weren't there before.
I think AI added the tests s.t. it could do dev here. (e.g. test locally). I think they're probably useful as such |
Uh oh!
There was an error while loading. Please reload this page.