Skip to content

はじめに

Polars は SQL との連携をサポートしていますが、より読みやすく表現力のあるコードを書くためには、 エクスプレッション構文 に慣れることをお勧めします。 DataFrame インターフェースが Polars の主要機能であるため、新機能は通常まずエクスプレッション API に追加されます。 しかし、既存の SQL コードベースを持っているユーザーや SQL の使用を好むユーザー向けに、Polars は SQL をサポートしています。

Note

Polars には固有の SQL エンジンはありません。なぜなら Polars は SQL クエリを エクスプレッション に変換し、独自のエンジンを使って実行するためです。このアプローチにより、純粋な DataFrame ライブラリとしての Polars のパフォーマンスとスケーラビリティの利点を維持しつつ、SQL を使用する機能を提供しています。

コンテキスト

Polars は SQL クエリを管理するために SQLContext オブジェクトを使用します。このコンテキストには、DataFrameLazyFrame の識別子名とそれに対応するデータセット 1 のマッピングが含まれます。以下の例では SQLContext を開始しています:

SQLContext

ctx = pl.SQLContext()

DataFrameの登録

SQLContext の初期化時に DataFrame を登録する方法はいくつかあります。

  • グローバル名前空間内のすべての LazyFrame および DataFrame オブジェクトを登録する方法
  • 辞書マッピングまたは kwargs を使って明示的に登録する方法

SQLContext

df = pl.DataFrame({"a": [1, 2, 3]})
lf = pl.LazyFrame({"b": [4, 5, 6]})

# Register all dataframes in the global namespace: registers both "df" and "lf"
ctx = pl.SQLContext(register_globals=True)

# Register an explicit mapping of identifier name to frame
ctx = pl.SQLContext(frames={"table_one": df, "table_two": lf})

# Register frames using kwargs; dataframe df as "df" and lazyframe lf as "lf"
ctx = pl.SQLContext(df=df, lf=lf)

Pandas DataFrame も、Polars に変換することで登録できます。

SQLContext

import pandas as pd

df_pandas = pd.DataFrame({"c": [7, 8, 9]})
ctx = pl.SQLContext(df_pandas=pl.from_pandas(df_pandas))

Note

Numpy をバックエンドとして使用している Pandas DataFrame を変換すると、変換のコストが高くなる可能性があります。しかし、Arrow をバックエンドとして使用している場合、変換のコストを大幅に抑えることができます (場合によってはほぼゼロに近くなります)。

SQLContext が初期化されたら、以下の方法で追加の DataFrame を登録したり、既存の DataFrame を登録解除できます:

  • register
  • register_globals
  • register_many
  • unregister

クエリの実行と結果の収集

SQL クエリは、クエリ計画の最適化を最大限に活用するために、常に遅延モードで実行されます。 そのため、結果を収集するには2つの方法があります:

  • SQLContexteager_execution パラメーターを True に設定してください。これにより Polars は execute 呼び出しから LazyFrame の結果を自動的に収集するようになります。
  • execute でクエリを実行する際に eager パラメーターを True に設定するか、collect を使用して明示的に結果を収集してください。

SQL クエリは SQLContextexecute を呼び出して実行します。

register · execute

# For local files use scan_csv instead
pokemon = pl.read_csv(
    "https://gist.githubusercontent.com/ritchie46/cac6b337ea52281aa23c049250a4ff03/raw/89a957ff3919d90e6ef2d34235e6bf22304f3366/pokemon.csv"
)
with pl.SQLContext(register_globals=True, eager_execution=True) as ctx:
    df_small = ctx.execute("SELECT * from pokemon LIMIT 5")
    print(df_small)

shape: (5, 13)
┌─────┬───────────────────────┬────────┬────────┬───┬─────────┬───────┬────────────┬───────────┐
│ #   ┆ Name                  ┆ Type 1 ┆ Type 2 ┆ … ┆ Sp. Def ┆ Speed ┆ Generation ┆ Legendary │
│ --- ┆ ---                   ┆ ---    ┆ ---    ┆   ┆ ---     ┆ ---   ┆ ---        ┆ ---       │
│ i64 ┆ str                   ┆ str    ┆ str    ┆   ┆ i64     ┆ i64   ┆ i64        ┆ bool      │
╞═════╪═══════════════════════╪════════╪════════╪═══╪═════════╪═══════╪════════════╪═══════════╡
│ 1   ┆ Bulbasaur             ┆ Grass  ┆ Poison ┆ … ┆ 65      ┆ 45    ┆ 1          ┆ false     │
│ 2   ┆ Ivysaur               ┆ Grass  ┆ Poison ┆ … ┆ 80      ┆ 60    ┆ 1          ┆ false     │
│ 3   ┆ Venusaur              ┆ Grass  ┆ Poison ┆ … ┆ 100     ┆ 80    ┆ 1          ┆ false     │
│ 3   ┆ VenusaurMega Venusaur ┆ Grass  ┆ Poison ┆ … ┆ 120     ┆ 80    ┆ 1          ┆ false     │
│ 4   ┆ Charmander            ┆ Fire   ┆ null   ┆ … ┆ 50      ┆ 65    ┆ 1          ┆ false     │
└─────┴───────────────────────┴────────┴────────┴───┴─────────┴───────┴────────────┴───────────┘

複数のソースからのクエリ実行

同様に、複数のソースから SQL クエリを実行することも簡単にできます。 以下の例では、次のものを登録しています:

  • CSV ファイル (遅延読み込み)
  • NDJSON ファイル (遅延読み込み)
  • Pandas DataFrame

そして SQL を使って、これらを結合します。 遅延読み込みを使用すると、ファイルから必要な行と列のみを読み込むことができます。

同様に、クラウドのデータレイク(S3, Azure Data Lake)を登録することもできます。 PyArrow データセットがデータレイクを指すようにし、scan_pyarrow_dataset を使って Polars で読み込むことができます。

register · execute

# Input data:
# products_masterdata.csv with schema {'product_id': Int64, 'product_name': String}
# products_categories.json with schema {'product_id': Int64, 'category': String}
# sales_data is a Pandas DataFrame with schema {'product_id': Int64, 'sales': Int64}

with pl.SQLContext(
    products_masterdata=pl.scan_csv("docs/data/products_masterdata.csv"),
    products_categories=pl.scan_ndjson("docs/data/products_categories.json"),
    sales_data=pl.from_pandas(sales_data),
    eager_execution=True,
) as ctx:
    query = """
    SELECT
        product_id,
        product_name,
        category,
        sales
    FROM
        products_masterdata
    LEFT JOIN products_categories USING (product_id)
    LEFT JOIN sales_data USING (product_id)
    """
    print(ctx.execute(query))

shape: (5, 4)
┌────────────┬──────────────┬────────────┬───────┐
│ product_id ┆ product_name ┆ category   ┆ sales │
│ ---        ┆ ---          ┆ ---        ┆ ---   │
│ i64        ┆ str          ┆ str        ┆ i64   │
╞════════════╪══════════════╪════════════╪═══════╡
│ 1          ┆ Product A    ┆ Category 1 ┆ 100   │
│ 2          ┆ Product B    ┆ Category 1 ┆ 200   │
│ 3          ┆ Product C    ┆ Category 2 ┆ 150   │
│ 4          ┆ Product D    ┆ Category 2 ┆ 250   │
│ 5          ┆ Product E    ┆ Category 3 ┆ 300   │
└────────────┴──────────────┴────────────┴───────┘

互換性

Polars は SQL 仕様全体をサポートしているわけではありませんが、最も一般的なステートメントタイプのサブセットをサポートしています。

Note

可能な限り、Polars は PostgreSQL の構文定義と関数の動作に従うことを目指しています。

例えば、サポートされている機能の一部は以下の通りです:

  • CREATE ステートメント: CREATE TABLE xxx AS ...
  • SELECT ステートメント: WHEREORDERLIMITGROUP BYUNIONJOIN 句など
  • 共通テーブル式 (CTE) : WITH tablename AS など
  • クエリを説明する: EXPLAIN SELECT ...
  • 登録済みのテーブルを一覧表示する: SHOW TABLES
  • テーブルを削除する: DROP TABLE tablename
  • テーブルを空にする: TRUNCATE TABLE tablename

以下は、まだサポートされていない機能の一部です:

  • INSERTUPDATEDELETE ステートメント
  • ANALYZE などのメタクエリ

今後のセクションでは、各ステートメントについてより詳しく説明します。


  1. 加えて、共通テーブルエクスプレッション も管理します。