PythonのHamiltonでデータ処理のDAGを組み立て、実行・テスト・デバッグするためのスキルです。関数やデコレーターで処理の依存関係を表し、既存コードの分割や可視化も進められます。
- データ加工処理をDAGに整理したいとき
- 既存スクリプトを関数に分割したいとき
- Hamiltonの関数をテストしたいとき
Hamiltonの処理を規模や負荷に応じて高速化するため、非同期I/Oやマルチスレッド、Spark・Ray・Daskによる並列化とキャッシュの使い分けを学べます。
Performance and parallelization patterns for Hamilton including async I/O, Spark, Ray, Dask, caching, and multithreading. Use for scaling Hamilton workflows.
実行スコア 未検証
インストール方法を見るHamiltonのワークフローを、処理内容やデータ規模に合わせて並列化・高速化する方法を扱います。APIやデータベースなど待ち時間の多い処理には非同期実行、非同期に対応していない同期I/Oにはマルチスレッドを使う例を紹介します。単一マシンのメモリを超える大規模データにはSpark、分散Python計算にはRayやDaskを使うパターンも取り上げます。また、時間や費用のかかる処理を再利用するキャッシュの設定、対象ノードごとの動作制御、キャッシュ状況の確認方法も説明します。負荷に応じた方式の選び方や、最適化の前にボトルネックを測る考え方も含まれます。
複数のAPI呼び出しやデータベース処理を効率よく進めたいときに向いています。データが増えて単一マシンでの処理が難しくなった場合や、繰り返し実行する計算の時間を抑えたい場合にも役立ちます。
Spark、Ray、Daskを使う例では、それぞれのライブラリや実行環境が必要です。Sparkの分散処理にはクラスターが必要となる場合があります。
この紹介文は、公開されている SKILL.md をもとに AI(OpenAI Codex)が作成しました。正確な仕様は下の原文を確認してください。
インストールする前に、エージェントに与えられる指示の中身を確認できます。
This skill covers parallelization strategies and performance optimization for Apache Hamilton workflows.
Choose your scaling strategy based on workload:
When to Use:
Key Benefits:
Basic Async Pattern:
from hamilton import async_driver
import aiohttp
from typing import List
# Mix async and sync functions
async def api_data(user_id: str) -> dict:
"""Fetch from API (async I/O)."""
async with aiohttp.ClientSession() as session:
async with session.get(f"https://api.example.com/users/{user_id}") as resp:
return await resp.json()
def transform_data(api_data: dict) -> dict:
"""Transform data (sync CPU)."""
return {k: v.upper() if isinstance(v, str) else v for k, v in api_data.items()}
async def save_data(transform_data: dict) -> str:
"""Save to database (async I/O)."""
async with db_pool.acquire() as conn:
await conn.execute("INSERT INTO data VALUES ($1)", transform_data)
return "success"
# Use AsyncDriver
import my_async_module
dr = await async_driver.Builder().with_modules(my_async_module).build()
result = await dr.execute(["save_data"], inputs={"user_id": "123"})
Parallel I/O Operations:
# These three operations execute in parallel automatically!
async def user_data(user_id: str) -> dict:
"""Fetch user data."""
async with aiohttp.ClientSession() as session:
async with session.get(f"https://api.example.com/users/{user_id}") as resp:
return await resp.json()
async def user_orders(user_id: str) -> List[dict]:
"""Fetch user orders (parallel with user_data)."""
async with aiohttp.ClientSession() as session:
async with session.get(f"https://api.example.com/orders?user={user_id}") as resp:
return await resp.json()
async def user_preferences(user_id: str) -> dict:
"""Fetch preferences (parallel with both above)."""
async with db_pool.acquire() as conn:
return await conn.fetchrow("SELECT * FROM preferences WHERE user_id=$1", user_id)
def user_profile(user_data: dict, user_orders: List[dict], user_preferences: dict) -> dict:
"""Combine all data (waits for all three to complete)."""
return {"data": user_data, "orders": user_orders, "preferences": user_preferences}
For synchronous I/O-bound code (legacy APIs, blocking libraries):
from hamilton import driver
from hamilton.execution import executors
# Use multithreading for sync I/O operations
dr = (
driver.Builder()
.with_modules(my_functions)
.with_local_executor(executors.MultiThreadingExecutor(max_tasks=10))
.build()
)
# Sync functions that do I/O will run concurrently
results = dr.execute(["final_output"], inputs={...})
When to Use:
When to Use Spark:
Basic PySpark Pattern:
from pyspark.sql import DataFrame as SparkDataFrame, SparkSession
from hamilton.plugins import h_spark
def raw_data(spark_session: SparkSession) -> SparkDataFrame:
"""Load data into Spark."""
return spark_session.read.csv("data.csv", header=True)
def filtered_data(raw_data: SparkDataFrame) -> SparkDataFrame:
"""Filter using Spark operations."""
return raw_data.filter(raw_data.age > 18)
def aggregated_stats(filtered_data: SparkDataFrame) -> SparkDataFrame:
"""Aggregate using Spark."""
return filtered_data.groupBy("country").count()
# Driver Setup
dr = (
driver.Builder()
.with_modules(my_spark_functions)
.with_adapters(h_spark.SPARK_INPUT_CHECK)
.build()
)
result = dr.execute(["aggregated_stats"], inputs={"spark_session": spark})
Column-Level Transformations with @with_columns:
from hamilton.plugins.h_spark import with_columns
import pandas as pd
# File: map_transforms.py
def normalized_amount(amount: pd.Series) -> pd.Series:
"""Pandas UDF for normalization."""
return (amount - amount.mean()) / amount.std()
def amount_category(normalized_amount: pd.Series) -> pd.Series:
"""Categorize based on normalized amount."""
return pd.cut(
normalized_amount,
bins=[-float("inf"), -1, 1, float("inf")],
labels=["low", "medium", "high"],
)
# Main dataflow
@with_columns(map_transforms, columns_to_pass=["amount"])
def enriched_data(raw_data: SparkDataFrame) -> SparkDataFrame:
"""Apply pandas UDFs to Spark DataFrame."""
return raw_data
Spark Best Practices:
.collect() until final nodes@with_columns for map operations.limit(1000))When to Use Ray:
from hamilton.plugins import h_ray
import ray
ray.init()
ray_executor = h_ray.RayGraphAdapter(result_builder={"base": dict})
dr = driver.Driver({}, my_functions, adapter=ray_executor)
results = dr.execute(["large_computation"], inputs={...})
When to Use Dask:
from hamilton.plugins import h_dask
from dask import distributed
cluster = distributed.LocalCluster()
client = distributed.Client(cluster)
dask_executor = h_dask.DaskExecutor(client=client)
dr = driver.Builder().with_remote_executor(dask_executor).with_modules(my_functions).build()
When to Use Caching:
Basic Caching Setup:
from hamilton import driver
# Enable caching
dr = driver.Builder().with_modules(my_functions).with_cache().build()
# First execution: computes and caches
result1 = dr.execute(["final_output"], inputs={"data_path": "data.csv"})
# Second execution: retrieves from cache (instant!)
result2 = dr.execute(["final_output"], inputs={"data_path": "data.csv"})
Controlling Cache Behavior:
from hamilton.function_modifiers import cache
# Always recompute (for data loaders)
@cache(behavior="recompute")
def live_api_data(api_key: str) -> dict:
"""Always fetch fresh data."""
import requests
response = requests.get("https://api.example.com/data", headers={"Authorization": api_key})
return response.json()
# Never cache (for non-deterministic operations)
@cache(behavior="disable")
def random_sample(data: pd.DataFrame) -> pd.DataFrame:
"""Random sampling should not be cached."""
return data.sample(frac=0.1)
# Custom format for efficiency
@cache(format="parquet")
def large_dataframe(processed_data: pd.DataFrame) -> pd.DataFrame:
"""Store as parquet for efficiency."""
return processed_data
Driver-Level Cache Control:
dr = (
driver.Builder()
.with_modules(my_functions)
.with_cache(
recompute=["raw_data"], # Always recompute these
disable=["random_sample"], # Never cache these
path="./my_cache", # Custom location
)
.build()
)
# Force complete refresh
dr = driver.Builder().with_modules(my_functions).with_cache(recompute=True).build()
Cache Inspection:
# Visualize what was cached vs executed
dr.cache.view_run() # Green = cache hit, Orange = executed
# Access cached results
run_id = dr.cache.last_run_id
data_version = dr.cache.data_versions[run_id]["my_node"]
cached_result = dr.cache.result_store.get(data_version)
Decision Matrix:
| Workload Type | Strategy | Use When |
|---|---|---|
| I/O-bound (async-capable) | AsyncDriver | Multiple API calls, async libraries available |
| I/O-bound (sync only) | MultiThreading | Legacy APIs, blocking I/O |
| Large datasets | Spark | Multi-GB/TB data, cluster available |
| Python computation | Ray/Dask | Custom parallel logic, ML workloads |
| Expensive operations | Caching | Repeated computations, LLM calls |
Combining Strategies:
/hamilton-core/hamilton-llmまだレビューはありません。使ってみた感想をお寄せください。
ログインなしで書き込めます。使ってみた感想、質問、動かなかった環境などを気軽にどうぞ。
まだコメントはありません。最初のコメントを書いてみませんか。
PythonのHamiltonでデータ処理のDAGを組み立て、実行・テスト・デバッグするためのスキルです。関数やデコレーターで処理の依存関係を表し、既存コードの分割や可視化も進められます。
Hamiltonの新しいデータフローを、DOT図の設計から構造検証、ノード単位のテスト駆動実装まで順序立てて作る手順を案内します。
Hamiltonのデータ処理フローをAirflowやFastAPIなどに組み込み、定期実行、予測API、ダッシュボード、ノートブックで活用する方法を扱います。
HamiltonでRAGや埋め込み、ベクトルデータベース、プロンプトを組み合わせたLLMワークフローを設計し、並列実行やキャッシュ、構造化出力を使う実装パターンを学べます。
HamiltonのMCPツールを使い、データ処理のひな形作成からDAGの検証・可視化・実行までを会話の中で進め、構造上の誤りを直しながらパイプラインを組み立てます。
Hamiltonのデータフロー実行をUIとSDKで記録し、処理履歴や依存関係、失敗箇所、実行時間を確認して、開発時のデバッグや本番監視に役立てます。