Jupyter 노트북에서 DuckDB 사용하기
Jupyter 노트북에서 DuckDB 사용하기 (Jupyter Notebooks)
DuckDB의 Python 클라이언트는 원한다면 추가 설정 없이 Jupyter 노트북에서 바로 쓸 수 있어요. 하지만 추가 라이브러리를 쓰면 SQL 쿼리 개발이 훨씬 간편해지기도 해요. 이 가이드에서는 그런 추가 라이브러리를 활용하는 방법을 설명할게요. DuckDB와 Python을 함께 쓰는 방법은 Python 섹션의 다른 가이드들도 참고하면 좋아요.
출처: 공식문서
이 예시에서는 JupySQL 패키지를 사용해요. 이 워크플로우는 Google Colab 노트북으로도 제공되고 있어요.
필요한 라이브러리
Jupyter 노트북에서 DuckDB 경험을 개선해 주는 추가 라이브러리는 네 가지가 있어요.
- jupysql: Jupyter 코드 셀을 SQL 셀로 바꿔줘요
- Pandas: 깔끔한 테이블 시각화와 다른 분석과의 호환성
- matplotlib: Python으로 플로팅하기
- duckdb-engine (DuckDB SQLAlchemy 드라이버): SQLAlchemy가 DuckDB에 연결할 때 사용 (선택 사항)
설치
Jupyter Notebook이 아직 설치되어 있지 않다면 커맨드라인에서 아래 pip install 명령들을 실행해요. 그렇지 않다면 위의 Google Colab 링크에서 노트북 내 예시를 참고해도 돼요.
pip install duckdb
Jupyter Notebook 설치:
pip install notebook
또는 JupyterLab:
pip install jupyterlab
지원 라이브러리 설치:
pip install jupysql pandas matplotlib duckdb-engine
jupysql 설정
Jupyter Notebook을 열고 관련 라이브러리를 임포트해요.
jupysql에 설정을 적용해서 데이터를 Pandas로 바로 출력하고, 노트북에 출력되는 내용을 간단하게 만들 수 있어요.
%config SqlMagic.autopandas = True
%config SqlMagic.feedback = False
%config SqlMagic.displaycon = False
DuckDB에 연결하려면:
import duckdb
import pandas as pd
%load_ext sql
conn = duckdb.connect()
%sql conn --alias duckdb
⚠️ 변수(Variables)는 네이티브 DuckDB 연결에서는 인식되지 않아요.
대신 duckdb_engine을 통해 DuckDB에 SQLAlchemy로 연결할 수도 있어요. 성능 및 기능 차이는 이 문서를 참고하세요.
import duckdb
import pandas as pd
# duckdb_engine을 임포트할 필요는 없음
# jupysql이 connection string을 보고 드라이버를 자동으로 감지해요!
# SQL 셀을 만들기 위해 jupysql Jupyter 확장을 로드
%load_ext sql
새 인메모리 DuckDB, 기본 연결(default connection), 또는 파일 기반 데이터베이스 중 하나에 연결하면 돼요:
%sql duckdb:///:memory:
%sql duckdb:///:default:
%sql duckdb:///path/to/file.db
SQLAlchemy connection string으로 duckdb:///:default:를 제공하면 %sql 명령과 duckdb.sql이 같은 기본 연결을 공유해요.
SQL 셀 실행
라인 시작에 %sql을 붙이면 한 줄짜리 SQL 쿼리를 실행할 수 있어요. 쿼리 결과는 Pandas DataFrame으로 표시돼요.
%sql SELECT 'Off and flying!' AS a_duckdb_column;
셀 시작에 %%sql을 붙이면 Jupyter 셀 전체를 SQL 셀로 쓸 수 있어요. 쿼리 결과는 Pandas DataFrame으로 표시돼요.
%%sql
SELECT
schema_name,
function_name
FROM duckdb_functions()
ORDER BY ALL DESC
LIMIT 5;
쿼리 결과를 Python 변수에 저장하려면 <<를 할당 연산자로 사용해요.
%sql과 %%sql 두 Jupyter magic 모두에서 쓸 수 있어요.
%sql res << SELECT 'Off and flying!' AS a_duckdb_column;
%config SqlMagic.autopandas = True 옵션이 설정돼 있으면 변수는 Pandas dataframe이 되고, 그렇지 않으면 DataFrame() 함수로 Pandas로 변환할 수 있는 ResultSet이 돼요.
데이터프레임 쿼리하기
DuckDB는 Jupyter 노트북에 변수로 저장된 모든 dataframe을 찾아서 쿼리할 수 있어요.
input_df = pd.DataFrame.from_dict({"i": [1, 2, 3],
"j": ["one", "two", "three"]})
쿼리할 dataframe은 FROM 절에서 다른 테이블처럼 지정하면 돼요.
%sql output_df << SELECT sum(i) AS total_i FROM input_df;
⚠️ SQLAlchemy 연결을 사용할 때는 Pandas dataframe을 쿼리 가능하게 만들기 위해
%sql SET python_scan_all_frames=true를 실행해 주세요.
JupySQL로 플로팅하기
Python에서 데이터셋을 플로팅하는 가장 흔한 방법은 Pandas로 로드한 다음 matplotlib이나 seaborn으로 그리는 거예요. 이 방식은 모든 데이터를 메모리에 로드해야 해서 매우 비효율적이에요. JupySQL의 플로팅 모듈은 계산을 SQL 엔진에서 수행해요. 이것이 메모리 관리를 엔진에 위임해서, 중간 계산이 메모리를 계속 잡아먹지 않게 하면서 방대한 데이터셋을 효율적으로 그리게 해줘요.
박스플롯(boxplot)을 만들려면 %sqlplot boxplot을 호출하고 테이블 이름과 플로팅할 컬럼을 넘겨줘요.
이 경우 테이블 이름은 로컬에 저장된 Parquet 파일의 경로예요.
from urllib.request import urlretrieve
_ = urlretrieve(
"https://d37ci6vzurychx.cloudfront.net/trip-data/yellow_tripdata_2021-01.parquet",
"yellow_tripdata_2021-01.parquet",
)
%sqlplot boxplot --table yellow_tripdata_2021-01.parquet --column trip_distance
DuckDB의 httpfs 확장은 Parquet과 CSV 파일을 http로 원격 쿼리할 수 있게 해줘요. 이 예시들은 NYC의 과거 택시 데이터를 담은 Parquet 파일을 쿼리해요. Parquet 형식을 사용하면 DuckDB가 전체 파일을 다운로드하는 대신 필요한 행과 컬럼만 메모리로 가져와요. DuckDB는 로컬 Parquet 파일도 처리할 수 있어요. 전체 Parquet 파일을 쿼리하거나 파일의 큰 부분이 필요한 여러 쿼리를 실행하는 경우라면 로컬 처리가 더 나을 수 있어요.
%%sql
INSTALL httpfs;
LOAD httpfs;
이제 90번째 백분위수로 필터링하는 쿼리를 만들어볼게요.
--save와 --no-execute 함수를 사용한 점에 주목하세요.
이것은 JupySQL에게 쿼리를 저장하되 실행은 건너뛰라고 알려줘요. 다음 플로팅 호출에서 참조되게 됩니다.
%%sql --save short_trips --no-execute
SELECT *
FROM 'https://d37ci6vzurychx.cloudfront.net/trip-data/yellow_tripdata_2021-01.parquet'
WHERE trip_distance < 6.3
히스토그램을 만들려면 %sqlplot histogram을 호출하고 테이블 이름, 컬럼, bin 개수를 넘겨줘요.
--with short-trips를 사용해서 JupySQL이 앞서 정의한 쿼리를 사용하도록 하고, 따라서 데이터의 일부만 플로팅하게 해요.
%sqlplot histogram --table short_trips --column trip_distance --bins 10 --with short_trips
이제 SQL과 Pandas를 간단하면서도 고성능으로 오가며 쓸 수 있어요! 방대한 데이터셋을 엔진을 통해 직접 플로팅할 수 있고 (전체 파일 다운로드와 전부 메모리에 로드하는 것을 모두 피하면서) dataframe은 SQL에서 테이블처럼 읽히고, SQL 결과는 dataframe으로 출력될 수 있어요. 즐거운 분석 되세요!
jupysql의 대안으로는 magic_duckdb가 있어요.