
2026/08/30 2:13
コード11行でより優れたSQLを
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
Prela は、UCLA RePL で開発された新しい問い合わせ言語であり、従来の SQL などの手法とは異なり、二元関係を変数として扱える構文可能な関数として捉えることで、極めて簡潔さを最優先しています。Python 風のシンタックスを採用し、
.where を用いたフィルタリングや & を用いた結合など直感的な演算子を活用することで、論理のシームレスな連鎖を可能にします。例えば、特定のキャラクターがタイトルに含まれるアメリカ映画を検索する問い合わせは、従来の SQL では 20 行以上必要でしたが、Prela では movie.where(company.s(country).eq("[us]") & keyword.eq("character-name-in-title")).select(title & cast.s(person).s(alias).s(text)) のように単一の簡潔な行で表現できます。Prela の設計は、広範なテーブルを二元関係に分解する点に基づいており、各関係は行番号と列値をマッピングし、入力(行番号)、出力(複数の値)を持つ関数のように振る舞い、関数の連鎖に似た合成が可能となります。.select, &, .eq(v), .where などの演算子は、フィルタリング、結合、ネストされた属性選択、連鎖的な条件設定(例:.where(american & year.eq(1942)))を実現します。サブ式には通常の Python 変数を用いて CTE がサポートされ、論理的な連合、グループ化、集計も利用可能です。現在では Python で実装された玩具システムとして実証されていますが、Prela は、馴染みのある構文可能な論理を通じてデータ取得を簡素化する方向への大きなパラダイムシフトを表しています。完全な仕様は、この技術が現在のプロトタイプ段階を超えて成熟した時点で、今後の学術論文で詳細に説明される予定です。本文
Prela: シンプルな二元関係によるクエリ言語入門
概要
Prela は UCLA の RePL プロジェクトで開発中の新しいクエリ言語です。この言語は SQL とは異なりますが、その核心となるアイデアはシンプルです。本チュートリアルでは Python を使用して Prela の簡易実装を構築し、以下のクエリの挙動を理解します:
movie.where(company.s(country).eq("[us]") & keyword.eq("character-name-in-title")).select(title & cast.s(person).s(alias).s(text))
このコードは、「米国で製作され、かつタイトルにキャラクター名が含まれる映画」を検出し、各映画のタイトルと出演俳優の**別名(alias)**を出力します。同様の処理を行う SQL クエリは通常 20 行以上必要ですが、Prela では一行で記述可能です。
二元関係(Binary Relations)とは?
Prela の最大の特殊性は、すべてのデータ構造が**二元の関係(relation)**である点です。表には常に Exactly 2 つの列しか存在しません。
多数の列を持つ表を「広い表」から「狭い表」(二元関係)に変換する方法を考えましょう。例えば以下の映画テーブル:
| ID | title | year |
|---|---|---|
| 646 | The Godfather | 1972 |
| 478 | Seven Samurai | 1954 |
| 583 | Casablanca | 1942 |
この 3 列の表は、行番号をキーとして各属性を別々の二元関係に分解できます:
movie = Rel([(646, 0), (478, 1), (583, 2)]) title = Rel([(0, "The Godfather"), (1, "Seven Samurai"), (2, "Casablanca")]) year = Rel([(0, 1972), (1, 1954), (2, 1942)])
: ID と行番号の対応関係movie
: 行番号とタイトル名title
: 行番号と年year
ヒント: このチュートリアルでは
snip を使用して、コードセルをノートブックのような環境に連結しています。あるセルで行った変更は、後のセルにも自動的に反映されます。
関係の組み合わせ(Composition)
二元関係を「非決定論的関数」と捉えると、関係の組み合わせという強力な演算子が得られます。
- 関数の組み合わせ: 入力 → 出力 A → 出力 B
- 関係の組み合わせ: ID → 行番号 → 値(別の属性)
Python では辞書として変換して実装できます:
def select(r, s): d = dict(s) return [ (x, d[y]) for x, y in r if y in d ]
例:タイトルを取得
print(movie.select(title)) # ID: 646 -> The Godfather
チェイン式記法(Chaining Syntax)
複数の
.select を連結すると、複雑な結合が可能になります。
映画会社テーブルの追加:
| ID | name | country |
|---|---|---|
| 0 | Paramount | [us] |
| 1 | Toho | [jp] |
| 2 | Warner Bros. | [us] |
これを分解し、以下の関係を得ます:
company = Rel([(0, 0), (1, 1), (2, 2)]) id2row = Rel([(0, 0), (1, 1), (2, 2)]) name = Rel([(0, "Paramount"), (1, "Toho"), (2, "Warner Bros.")]) country = Rel([(0, "[us]"), (1, "[jp]"), (2, "[us]")])
シンプルなチェーン(省略による簡略化)
外鍵結合で ID を解析する必要がある場合でも、Prela は自動的にステップを挿入します:
# 完全な呼び出し print(movie.s(company).s(id2row).s(country)) # チェーン記法(推奨) print(movie.s(company).s(country)) # 意味:「映画会社の国」を取得
これは冒頭で示された
cast.s(person).s(alias).s(text) と同様です。
多列の選択(& 演算子)
単一の列ではなく、複数の属性を選択するには
演算子を使用します。&
&
の動作
&- 関係
の第二列と関係r
の第一列を一致させる (s
). - 両者の第一列同士を連結し、第二列をペアリングする
def and_(r, s): d = dict(s) return [ (x, (y, d[x])) for x, y in r if x in d ]
print(movie.select(title & year)) # 結果: [(646, ("The Godfather", 1972)), ...]
注意: 結果は依然として二元関係であり、
は値をタプルにネストするだけです。これにより、他の関係と同様にさらに組み合わせて使用可能です。&
フィルタリング(.where と .eq)
特定の状態にある行のみを選択するには、述語(predicate)演算子が必要です。
等価性チェック .eq(v)
.eq(v)関係の第二列が値
v に等しいペアのみを残します:
def eq(r, v): return [ (x, y) for x, y in r if y == v ]
例:米国映画のみを抽出
# company.s(country).eq("[us]") # 意味:国が "[us]" の行のみを残す print(company.s(country).eq("[us]"))
組み合わせ演算子 .where
.where述語を受け取り、別の関係をフィルタリングします:
def where(r, s): d = dict(s) return [ (x, y) for x, y in r if y in d ]
使用例:米国映画のリストを取得
print(movie.where(company.s(country).eq("[us]")))
CTE 的な変数と複合条件
中間結果を保存(CTE)
Python の純粋な変数を使って、C テンポラリー エクプレッション (CTE) を作成できます:
american = company.s(country).eq("[us]") print(movie.where(american)) # 意味:「会社の国が [us] である映画」をフィルタリング
複数条件の論理積(AND)
& は where 節内部で論理的な AND として機能します:
# 1942 年生産かつ米国映画のみ print(movie.where(american & year.eq(1942))) # 結果: カサブランカ (Casablanca) のみ
クリーンな記法
フィルタリングと選択を明確に分けることも可能です:
# 条件の指定 -> 選択 print(movie.where(american).select(title & year.eq(1942)))
まとめ:Prela の本質
Prela のすべての言語機能は、**関係の組み合わせ(Composition)**という基本的な概念に基づいています。これにより以下のことが可能になります:
- 簡潔さ: 複雑な SQL クエリを数行にまとめる
- 可読性: チェーン式記法による直感的な表現
- 柔軟性: Python の変数や論理演算子を自由に組み合わせて使用
Prela はまた、グループ化や集計などの一般的な演算子もサポートしています。詳細については論文を参照してください。
最終的な練習コード
上記の知識を使って、以下のクエリを実行できる環境を構築してみてください:
# keyword = ... (必要に応じて定義) # cast = ... (必要に応じて定義) print( movie .where( company.s(country).eq("[us]") & keyword.eq("character-name-in-title") ) .select( title & cast.s(person).s(alias).s(text) ) )