Skip to content

Commit 6ea9f72

Browse files
author
Yihao Sun
committed
try fix ci
remove Gemfile remove Gemfile Create jekyll-docker.yml fix CI
1 parent 0344168 commit 6ea9f72

File tree

6 files changed

+36
-138
lines changed

6 files changed

+36
-138
lines changed

.github/workflows/jekyll-docker.yml

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
name: Jekyll site CI
2+
3+
on:
4+
push:
5+
branches: [ "main" ]
6+
pull_request:
7+
branches: [ "main" ]
8+
9+
jobs:
10+
build:
11+
12+
runs-on: ubuntu-latest
13+
14+
steps:
15+
- uses: actions/checkout@v4
16+
- name: Build the site in the jekyll/builder container
17+
run: |
18+
docker run \
19+
-v ${{ github.workspace }}:/srv/jekyll -v ${{ github.workspace }}/_site:/srv/jekyll/_site \
20+
jekyll/builder:latest /bin/bash -c "chmod -R 777 /srv/jekyll && jekyll build --future"

.gitignore

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
_site/
22
_site/assets
3-
.DS_Store
3+
.DS_Store
4+
Gemfile.lock
5+
# Gemfile

Gemfile

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,6 @@ source "https://rubygems.org"
22

33
gem "jekyll"
44

5-
gem 'jekyll-scholar', group: :jekyll_plugins
5+
group :jekyll_plugins do
6+
gem "jekyll-scholar"
7+
end

Gemfile.lock

-127
This file was deleted.

_posts/2025-04-12-wcoj.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ where each of $R_i(x_i), R_j(x_j), R_k(x_k),...$ is a subatom over a the schema
328328

329329
To interpret a free join plan, simply treat each bracketed group [] as a loop level. Within each level, iterate over the first subatom of the group, and use the scanned value to ground (or filter) and look up the remaining subatoms. For example, the triangle query with WCOJ optimizations can be represented in pseudocode as follows:
330330

331-
![Free Join](/assets/blog/wcoj/free.png)
331+
![Free Join](/assets/blog/wcoj/free.png){:width="100%"}
332332

333333
One bonus contribution of the original Free Join paper is that it also presents an algorithm for implementing the join plan using a novel data structure called the Lazy Generalized Hash Trie (LGHT). Similar to how the sorted trie enables the pipelining of worst-case optimal joins in LFTJ, LGHT makes it possible to fully pipeline hash-based WCOJ.
334334

docs/2025/04/12/wcoj.html

+9-8
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ <h3 id="data-skew">Data Skew</h3>
135135

136136
<p>While the pipelining model is parallelizable, it can failed scale when <em>data skew</em> occurs. For instance, in a large social media graph, some influential nodes may have hundreds of times more followers than other nodes. When such a graph serves as the outer relation in a multi-input relation CQ, the thread processing the influential node will have to handle significantly more work compared to threads processing less-connected nodes. This imbalance can lead to thread idle.</p>
137137

138-
<p><img src="/assets/blog/wcoj/idle.png" alt="Thread idle" /></p>
138+
<p><img src="/assets/blog/wcoj/idle.png" alt="Thread idle" width="70%" /></p>
139139

140140
<p>This imbalance in k-way joins makes it difficult to scale pipelined join operations on massively parallel hardware and hinders adaptation to SIMD-based architectures, such as GPUs and AVX-supported CPUs.</p>
141141

@@ -204,7 +204,7 @@ <h2 id="4-query-size-estimation-bound-of-cqs">4. Query Size Estimation: Bound of
204204

205205
<p>A natural way to reason about how each relation and column contributes to the CQ is by constructing a <em>query graph</em>: nodes represent logical variables (i.e., column names), and edges represent the relations. In this model, worst-case join planning can be seen as an <em>edge cover</em> problem, where the goal is to identify a minimal set of vertices that touches every edge. For example, for two foobar query graphs we show earlier in this section, the first one might use the vertex set ${A, D, C}$ to represent the worst case for the first query, while the vertex set ${A, B}$ will be sufficient for the second query, indicating that the worst-case output size is dominated by fewer variables.</p>
206206

207-
<p><img src="/assets/blog/wcoj/graph.png" alt="Query Graph" /></p>
207+
<p><img src="/assets/blog/wcoj/graph.png" alt="Query Graph" width="70%" /></p>
208208

209209
<ul>
210210
<li>
@@ -278,7 +278,7 @@ <h2 id="5-worst-case-optimal-join">5. Worst Case Optimal Join</h2>
278278

279279
<p>Inspired by AGM bound, Hung Q. Ngo, Christopher Re and Atri Rudra purpose a generic framework (missing reference) for designing worst case optimal join. Their algorithm can be described using the following pseudocode:</p>
280280

281-
<p><img src="/assets/blog/wcoj/generic_join.png" alt="Generic Join" /></p>
281+
<p><img src="/assets/blog/wcoj/generic_join.png" alt="Generic Join" width="70%" /></p>
282282

283283
<p>At each recursion level, the algorithm selects a join variable—typically chosen based on heuristics such as frequency of occurrence across relations. It then <strong>projects</strong> the selected variable from all participating relations and computes the intersection of these value sets to determine all possible assignments to that logical variable. For each intersected value, the algorithm grounds the query accordingly and recursively applies the same process to the partially grounded query. This recursion continues until all variables in the query are bound, yielding a complete join result. This project-intersect-join pattern, this match the suggestion of original AGM paper.</p>
284284

@@ -296,7 +296,7 @@ <h3 id="delayed-materialization">Delayed Materialization</h3>
296296

297297
<p>One notable thing of the generic WCOJ algorithm is that it requires allocating temporary buffers at each level of the recursion (or nested for-loop) to store intermediate results, the partially grounded tuples. This introduces more memory overhead, when compared to traditional left-deep binary joins, where intermediate results are often pipelined or materialized in global buffer. If we use the same data structures for both storage and join processing (as is common in left-deep plans), this memory pressure can severely impact performance. A common solution is using prefix trie as relation data structure.</p>
298298

299-
<p><img src="/assets/blog/wcoj/trie.png" alt="Trie" /></p>
299+
<p><img src="/assets/blog/wcoj/trie.png" alt="Trie" width="80%" /></p>
300300

301301
<p>For example in above relation A stored in trie, operation <code class="language-plaintext highlighter-rouge">A[1]</code> can now be implemented as finding the pointer of sub-tree rooted at value one and instead of temporary buffer we only need store a single pointer.</p>
302302

@@ -316,10 +316,10 @@ <h3 id="leapfrog-triejoin">Leapfrog triejoin</h3>
316316

317317
<p>An implementation of this idea is <em>Leapfrog Triejoin (LFTJ)</em> <a class="citation" href="#veldhuizen2014leapfrog">(Veldhuizen)</a>, introduced by Todd L. Veldhuizen and used in the commercial system LogicBlox. LFTJ is specifically designed for scenarios where all column values are integers and each relation is indexed using a sorted trie. In such tries, each level corresponds to a join variable, and the children (subtries) of every node are kept in sorted order. Below pseudo code describe the LFTJ using iterator-model style:</p>
318318

319-
<p><img src="/assets/blog/wcoj/lftj_alg.png" alt="LFTJ pseudo code" />
319+
<p><img src="/assets/blog/wcoj/lftj_alg.png" alt="LFTJ pseudo code" width="100%" />
320320
Below is a concrete example illustrating the algorithm’s operation. Initially, the algorithm initializes an iterator over each input relation’s join column. In this example, the iterators for relations A, B, and C are positioned at 0, 0, and 2, respectively. The algorithm then determines the candidate join value by computing the maximum of these initial values as possible lower-bound of next joined value, which is 2—this value is currently held by relation C. Next, the algorithm uses the linear probing function (leapfrog-seek) to search for the candidate value 2 in another relation—in this case, relation A is arbitrarily chosen. During the search in relation A, it is found that 2 is not present; instead, the iterator advances to the smallest value greater than 2, which is 3. With 3 as the new possible lower-bound of next joined value, the algorithm then repeats the search in relation B.This process of advancing the iterators continues until a candidate join value (in the example, 8) is present in all relations. When such a value is found, it confirms that the value lies in the intersection of all join columns, allowing the algorithm to proceed with the inner loop of the generic join operation.</p>
321321

322-
<p><img src="/assets/blog/wcoj/lftj.png" alt="LFTJ example" /></p>
322+
<p><img src="/assets/blog/wcoj/lftj.png" alt="LFTJ example" width="100%" /></p>
323323

324324
<p>Although LFTJ is a compelling algorithm for pipelining worst-case optimal joins, its reliance on sorted tries for relation storage can be limiting. While sorted tries support efficient sequential iteration, they impose an ordering constraint that can result in non-constant factor access during lookups. For systems that require truly constant-factor indexed value access, a hash-trie based algorithm is more appealing.</p>
325325

@@ -347,7 +347,7 @@ <h3 id="free-join">Free Join</h3>
347347

348348
<p>To interpret a free join plan, simply treat each bracketed group [] as a loop level. Within each level, iterate over the first subatom of the group, and use the scanned value to ground (or filter) and look up the remaining subatoms. For example, the triangle query with WCOJ optimizations can be represented in pseudocode as follows:</p>
349349

350-
<p><img src="/assets/blog/wcoj/free.png" alt="Free Join" /></p>
350+
<p><img src="/assets/blog/wcoj/free.png" alt="Free Join" width="100%" /></p>
351351

352352
<p>One bonus contribution of the original Free Join paper is that it also presents an algorithm for implementing the join plan using a novel data structure called the Lazy Generalized Hash Trie (LGHT). Similar to how the sorted trie enables the pipelining of worst-case optimal joins in LFTJ, LGHT makes it possible to fully pipeline hash-based WCOJ.</p>
353353

@@ -356,7 +356,8 @@ <h2 id="whats-next-">What’s Next ?</h2>
356356
<p>In this article, we have explored a wide range of processing algorithms for conjunctive queries, but most of them only run on single CPU system—especially worst-case optimal join techniques. However, scaling these methods to parallel processing environments remains a complex and open research question. Recent work on adapting worst-case optimal joins to parallel hardware (see <a class="citation" href="#wu2025honeycomb">(Wu and Suciu)</a> <a class="citation" href="#lai2022accelerating">(Lai et al.)</a>) shows promising directions, though none of these approaches have matured for use in real-world databases. I look forward to discussing these developments and sharing my thoughts on parallelizing conjunctive query processing in future blog articles.</p>
357357

358358
<h2 id="reference">Reference</h2>
359-
<ol class="bibliography"><li><span id="graefe1993volcano">Graefe, Goetz, and William J. McKenna. “The Volcano Optimizer Generator: Extensibility and Efficient Search.” <i>Proceedings of IEEE 9th International Conference on Data Engineering</i>, IEEE, 1993, pp. 209–18.</span></li>
359+
<ol class="bibliography"><li><span id="cqwiki">Wikipedia. <i>Conjunctive Query</i>. 2024, https://en.wikipedia.org/wiki/Conjunctive_query.</span></li>
360+
<li><span id="graefe1993volcano">Graefe, Goetz, and William J. McKenna. “The Volcano Optimizer Generator: Extensibility and Efficient Search.” <i>Proceedings of IEEE 9th International Conference on Data Engineering</i>, IEEE, 1993, pp. 209–18.</span></li>
360361
<li><span id="palvo2024multiway">Palvo, Andy. <i>Lecture Note of Andy Palvo on Multi-Way Join Algorithm</i>. 2024, https://15721.courses.cs.cmu.edu/spring2024/notes/10-multiwayjoins.pdf.</span></li>
361362
<li><span id="lai2022accelerating">Lai, Zhuohang, et al. “Accelerating Multi-Way Joins on the GPU.” <i>The VLDB Journal</i>, 2022, pp. 1–25.</span></li>
362363
<li><span id="atserias2013size">Atserias, Albert, et al. “Size Bounds and Query Plans for Relational Joins.” <i>SIAM Journal on Computing</i>, vol. 42, no. 4, 2013, pp. 1737–67.</span></li>

0 commit comments

Comments
 (0)