You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by gi...@apache.org on 2026/08/14 00:09:56 UTC
(groovy-dev-site) branch asf-site updated: 2026/08/14 00:09:50: Generated dev website from groovy-website@6f09268
This is an automated email from the ASF dual-hosted git repository.
asf-gitbox-commits pushed a commit to branch asf-site
in repository https://gitbox.apache.org/repos/asf/groovy-dev-site.git
The following commit(s) were added to refs/heads/asf-site by this push:
new a349648c 2026/08/14 00:09:50: Generated dev website from groovy-website@6f09268
a349648c is described below
commit a349648c3847c4290f07f1a0c64113eb80b6caee
Author: jenkins <bu...@apache.org>
AuthorDate: Fri Aug 14 00:09:50 2026 +0000
2026/08/14 00:09:50: Generated dev website from groovy-website@6f09268
---
blog/groovy-geaflow.html | 133 +++++++++++++--------------------------
blog/img/geaflow_influencers.png | Bin 0 -> 273809 bytes
search/search-index.json | 2 +-
3 files changed, 43 insertions(+), 92 deletions(-)
diff --git a/blog/groovy-geaflow.html b/blog/groovy-geaflow.html
index 50f09040..d4562123 100644
--- a/blog/groovy-geaflow.html
+++ b/blog/groovy-geaflow.html
@@ -63,7 +63,7 @@
</ul>
</div>
</div>
- </div><div id='content' class='page-1'><div class='row'><div class='row-fluid'><div class='col-lg-3'><ul class='nav-sidebar'><li><a href='./'>Blog index</a></li><li class='active'><a href='#doc'>Graph Computing with Groovy™ and Apache GeaFlow (Incubating)</a></li><li><a href='#_apache_geaflow' class='anchor-link'>Apache GeaFlow</a></li><li><a href='#_setting_up' class='anchor-link'>Setting up</a></li><li><a href='#_a_social_network_case_study' class='anchor- [...]
+ </div><div id='content' class='page-1'><div class='row'><div class='row-fluid'><div class='col-lg-3'><ul class='nav-sidebar'><li><a href='./'>Blog index</a></li><li class='active'><a href='#doc'>Graph Computing with Groovy™ and Apache GeaFlow (Incubating)</a></li><li><a href='#_apache_geaflow' class='anchor-link'>Apache GeaFlow</a></li><li><a href='#_setting_up' class='anchor-link'>Setting up</a></li><li><a href='#_a_social_network_case_study' class='anchor- [...]
<a href="https://github.com/paulk-asert/" target="_blank" rel="noopener noreferrer"><img style="border-radius:50%;height:48px;width:auto" src="img/paulk-asert.png" alt="Paul King"></a>
<div style="display:grid;align-items:center;margin:0.1ex;padding:0ex">
<div><a href="https://github.com/paulk-asert/" target="_blank" rel="noopener noreferrer"><span>Paul King</span></a></div>
@@ -141,7 +141,7 @@ are on Maven Central. For Gradle, the relevant part of the build file is:</p>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="groovy">dependencies {
- implementation "org.apache.groovy:groovy:5.0.8"
+ implementation "org.apache.groovy:groovy:6.0.0-beta-2"
implementation "org.apache.geaflow:geaflow-api:$geaflowVersion"
implementation "org.apache.geaflow:geaflow-pdata:$geaflowVersion"
implementation "org.apache.geaflow:geaflow-cluster:$geaflowVersion"
@@ -192,7 +192,7 @@ as captured in this map:</p>
</div>
<div class="listingblock">
<div class="content">
-<pre class="prettyprint highlight"><code data-lang="groovy">var follows = [
+<pre class="prettyprint highlight"><code data-lang="groovy">val follows = [
'Emily Seebohm' : ['Kaylee McKeown', 'Regan Smith'],
'Kylie Masse' : ['Kaylee McKeown', 'Regan Smith', 'Ingrid Wilm'],
'Regan Smith' : ['Kaylee McKeown', 'Katharine Berkoff'],
@@ -204,7 +204,9 @@ as captured in this map:</p>
</div>
<div class="paragraph">
<p>The keys of the map are the followers, and the values are the lists of
-swimmers they follow. Who are the influencers in this network?
+swimmers they follow. (If you haven’t seen <code>val</code> before, it arrived in
+Groovy 6: like <code>var</code>, it declares a type-inferred local variable, but
+a final one.) Who are the influencers in this network?
The classic algorithm for answering that question is
<a href="https://en.wikipedia.org/wiki/PageRank">PageRank</a>, originally used
to rank web pages, but equally applicable to any directed graph.</p>
@@ -231,11 +233,11 @@ value which we won’t use:</p>
</div>
<div class="listingblock">
<div class="content">
-<pre class="prettyprint highlight"><code data-lang="groovy">List<IVertex<String, Double>> vertices = follows.keySet().collect {
- (IVertex<String, Double>) new ValueVertex<>(it, 1d)
+<pre class="prettyprint highlight"><code data-lang="groovy">val vertices = follows.keySet().collect {
+ new ValueVertex<>(it, 1d)
}
-List<IEdge<String, Integer>> edges = follows.collectMany { follower, followed ->
- followed.collect { (IEdge<String, Integer>) new ValueEdge<>(follower, it, 1) }
+val edges = follows.collectMany { follower, followed ->
+ followed.collect { new ValueEdge<>(follower, it, 1) }
}</code></pre>
</div>
</div>
@@ -258,20 +260,19 @@ and then compute over it:</p>
void execute(IPipelineTaskContext ctx) {
// ... follows, vertices, edges as above ...
- PWindowStream<IVertex<String, Double>> vertexSource =
+ val vertexSource =
ctx.buildSource(new CollectionSource<IVertex<String, Double>>(vertices),
- AllWindow.<IVertex<String, Double>> getInstance())
- PWindowStream<IEdge<String, Integer>> edgeSource =
+ AllWindow.getInstance())
+ val edgeSource =
ctx.buildSource(new CollectionSource<IEdge<String, Integer>>(edges),
- AllWindow.<IEdge<String, Integer>> getInstance())
+ AllWindow.getInstance())
- def graphViewDesc = GraphViewBuilder.createGraphView(GraphViewBuilder.DEFAULT_GRAPH)
+ val graphViewDesc = GraphViewBuilder.createGraphView(GraphViewBuilder.DEFAULT_GRAPH)
.withShardNum(1)
.withBackend(IViewDesc.BackendType.Memory)
.build()
- PGraphWindow<String, Double, Integer> graph =
- ctx.buildWindowStreamGraph(vertexSource, edgeSource, graphViewDesc)
+ val graph = ctx.buildWindowStreamGraph(vertexSource, edgeSource, graphViewDesc)
graph.compute(new PRAlgorithm(10, 0.85d))
.compute(1)
@@ -287,6 +288,12 @@ and then compute over it:</p>
<div class="ulist">
<ul>
<li>
+<p>We’re writing idiomatic dynamic Groovy here — no explicit types are
+needed for the sources or the graph. If you prefer compile-time type
+checking, adding <code>@CompileStatic</code> works too, at the cost of a few
+explicit generic types to help inference along.</p>
+</li>
+<li>
<p><code>AllWindow</code> tells GeaFlow to read all of the data as one batch,
giving <em>static</em> graph computation. Size-based tumbling windows are
used instead when processing <em>streaming</em> data incrementally.</p>
@@ -337,18 +344,18 @@ static class PRComputeFunction implements VertexCentricComputeFunction<String
@Override
void compute(String vertexId, Iterator<Double> messages) {
- def vertex = context.vertex().get()
- def outEdges = context.edges().outEdges
+ val vertex = context.vertex().get()
+ val outEdges = context.edges().outEdges
if (context.iterationId == 1L) {
if (outEdges) {
context.sendMessageToNeighbors(vertex.value / outEdges.size() as double)
}
} else {
- double sum = messages.sum(0d) as double
+ double sum = messages.sum(0d)
double pr = sum * alpha + (1 - alpha)
context.setNewVertexValue(pr)
if (outEdges) {
- context.sendMessageToNeighbors(pr / outEdges.size() as double)
+ context.sendMessageToNeighbors(pr / outEdges.size())
}
}
}
@@ -387,10 +394,10 @@ and runs it:</p>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="groovy">static void main(String[] args) {
- def environment = EnvironmentFactory.onLocalEnvironment()
- def pipeline = PipelineFactory.buildPipeline(environment)
+ val environment = EnvironmentFactory.onLocalEnvironment()
+ val pipeline = PipelineFactory.buildPipeline(environment)
pipeline.submit(new PRTask())
- def result = pipeline.execute()
+ val result = pipeline.execute()
result.get()
environment.shutdown()
System.exit(0)
@@ -416,81 +423,25 @@ Kaylee McKeown has influence 1.85</pre>
Kaylee McKeown and Regan Smith, come out on top — as our hypothetical
follower graph intended. Phew!</p>
</div>
+<div class="paragraph">
+<p><span class="image"><img src="./img/geaflow_influencers.png" alt="From follows map to influence ranking with Groovy and GeaFlow" width="800"></span></p>
+</div>
</div>
</div>
<div class="sect1">
-<h2 id="_a_note_on_lambdas_closures_and_serialization">A note on lambdas, closures and serialization</h2>
+<h2 id="_a_note_on_serialization">A note on serialization</h2>
<div class="sectionbody">
<div class="paragraph">
<p>GeaFlow is a distributed system. Tasks and functions are serialized
-(using <a href="https://github.com/EsotericSoftware/kryo">kryo</a>) and shipped
-across process boundaries — even in local mode, where the in-process
-components talk to each other over the same RPC protocol they’d use on
-a cluster. That has consequences for how we write our Groovy code.
-GeaFlow’s functional interfaces like <code>PipelineTask</code> and <code>SinkFunction</code>
-all extend <code>Serializable</code>, and we found the following
-(with static compilation enabled via <code>@CompileStatic</code>):</p>
-</div>
-<table class="tableblock frame-all grid-all stretch">
-<colgroup>
-<col style="width: 33.3333%;">
-<col style="width: 33.3333%;">
-<col style="width: 33.3334%;">
-</colgroup>
-<thead>
-<tr>
-<th class="tableblock halign-left valign-top">Style</th>
-<th class="tableblock halign-left valign-top">Example</th>
-<th class="tableblock halign-left valign-top">Works?</th>
-</tr>
-</thead>
-<tbody>
-<tr>
-<td class="tableblock halign-left valign-top"><p class="tableblock">Class implementing the interface</p></td>
-<td class="tableblock halign-left valign-top"><p class="tableblock"><code>pipeline.submit(new PRTask())</code></p></td>
-<td class="tableblock halign-left valign-top"><p class="tableblock">✅</p></td>
-</tr>
-<tr>
-<td class="tableblock halign-left valign-top"><p class="tableblock">Native lambda expression</p></td>
-<td class="tableblock halign-left valign-top"><p class="tableblock"><code>pipeline.submitIPipelineTaskContext ctx) → runJob(ctx</code></p></td>
-<td class="tableblock halign-left valign-top"><p class="tableblock">✅</p></td>
-</tr>
-<tr>
-<td class="tableblock halign-left valign-top"><p class="tableblock">Method reference</p></td>
-<td class="tableblock halign-left valign-top"><p class="tableblock"><code>pipeline.submit(SubmitVariants::runJob)</code></p></td>
-<td class="tableblock halign-left valign-top"><p class="tableblock">❌ (fixed in Groovy 6)</p></td>
-</tr>
-<tr>
-<td class="tableblock halign-left valign-top"><p class="tableblock">Closure</p></td>
-<td class="tableblock halign-left valign-top"><p class="tableblock"><code>pipeline.submit { IPipelineTaskContext ctx → runJob(ctx) }</code></p></td>
-<td class="tableblock halign-left valign-top"><p class="tableblock">❌</p></td>
-</tr>
-</tbody>
-</table>
-<div class="paragraph">
-<p>Classes and lambda expressions work: Groovy compiles a lambda targeting
-a <code>Serializable</code> functional interface into a serializable lambda, just
-like Java does, and GeaFlow’s kryo configuration knows how to transport
-those. A nice pattern is to hoist the body of your job into a static
-method and submit it with a one-line lambda.</p>
-</div>
-<div class="paragraph">
-<p>Method references surprised us: Groovy currently misses marking them
-as serializable, even when the target interface extends <code>Serializable</code>
-(where Java would). Investigating this while writing this post
-led us to <a href="https://issues.apache.org/jira/browse/GROOVY-11993">GROOVY-11993</a>,
-which has already fixed this for the upcoming Groovy 6 —
-we verified that method references work fine with GeaFlow using a
-recent Groovy 6 pre-release.</p>
-</div>
-<div class="paragraph">
-<p>Closures (whether coerced explicitly with <code>as PipelineTask</code> or
-implicitly) are converted to JDK dynamic proxies, which kryo doesn’t
-currently transport, so avoid them for functions that cross the RPC
-boundary — which includes tasks, sources, sinks, and compute functions.
-Interestingly, the closure proxies <em>are</em> serializable with plain Java
-serialization, so teaching GeaFlow’s kryo setup about them would be a
-nice little contribution for a Groovy-friendly volunteer.</p>
+and shipped across process boundaries — even in local mode. So, write
+your tasks, sources, sinks, and compute functions as classes (as we did
+above), or, with static compilation, as lambda expressions or method
+references — all of these serialize cleanly. Avoid closures for these
+particular functions: they are converted to dynamic proxies which
+GeaFlow won’t currently transport. More details, including a related
+method reference issue affecting earlier Groovy versions
+(<a href="https://issues.apache.org/jira/browse/GROOVY-11993">GROOVY-11993</a>,
+fixed in Groovy 6), can be found in the accompanying repo.</p>
</div>
</div>
</div>
diff --git a/blog/img/geaflow_influencers.png b/blog/img/geaflow_influencers.png
new file mode 100644
index 00000000..bfe012f8
Binary files /dev/null and b/blog/img/geaflow_influencers.png differ
diff --git a/search/search-index.json b/search/search-index.json
index cd7a7f51..73633faf 100644
--- a/search/search-index.json
+++ b/search/search-index.json
@@ -324,7 +324,7 @@
{
"id": "blog/groovy-geaflow.html",
"title": "The Apache Groovy programming language - Blogs - Graph Computing with Groovy™ and Apache GeaFlow (Incubating)",
- "content": "The Apache Groovy programming language - Blogs - Graph Computing with Groovy™ and Apache GeaFlow (Incubating) Socialize Discuss on the mailing list Groovy on X Groovy on Bluesky Groovy on Mastodon Groovy on LinkedIn Events and conferences Source code on GitHub Report issues in Jira Stack Overflow questions Slack Community You are using an outdated browser. Please upgrade your browser to improve your experience. Apache Groovy™ Learn Documentation Download S [...]
+ "content": "The Apache Groovy programming language - Blogs - Graph Computing with Groovy™ and Apache GeaFlow (Incubating) Socialize Discuss on the mailing list Groovy on X Groovy on Bluesky Groovy on Mastodon Groovy on LinkedIn Events and conferences Source code on GitHub Report issues in Jira Stack Overflow questions Slack Community You are using an outdated browser. Please upgrade your browser to improve your experience. Apache Groovy™ Learn Documentation Download S [...]
"url": "blog/groovy-geaflow.html",
"site": "dev"
},