メインコンテンツへスキップ
タブ区切り値 (TSV) ファイルは一般的な形式で、ファイルの1行目にフィールド見出しが含まれていることがあります。ClickHouse は TSV を取り込むことができ、ファイルを取り込まずに TSV をクエリすることもできます。このガイドでは、その両方のケースを扱います。CSV file をクエリまたは取り込む必要がある場合も、同じ手法が使えます。フォーマット引数内の TSVCSV に置き換えるだけです。 このガイドでは、次のことを行います。
  • 調査する: TSV ファイルの構造と内容をクエリします。
  • 対象の ClickHouse スキーマを決定する: 適切なデータ型を選び、既存のデータをそれらの型に対応付けます。
  • ClickHouse テーブルを作成する
  • データを前処理してストリーミングする: ClickHouse にデータを取り込みます。
  • いくつかのクエリを実行する: ClickHouse に対してクエリを実行します。
このガイドで使用するデータセット は NYC Open Data チームによるもので、「New York City Police Department (NYPD) に報告された、すべての有効な重罪、軽罪、および違反行為」に関するデータを含んでいます。本稿執筆時点ではデータファイルは 166MB ですが、定期的に更新されています。 ソース: data.cityofnewyork.us 利用規約: https://www1.nyc.gov/home/terms-of-use.page

前提条件

このガイドで説明するコマンドについて

このガイドには、2種類のコマンドがあります。
  • 一部のコマンドは TSV ファイルに対してクエリを実行するもので、コマンドプロンプトで実行します。
  • 残りのコマンドは ClickHouse に対してクエリを実行するもので、clickhouse-client または Play UI で実行します。
このガイドの例では、TSV ファイルを ${HOME}/NYPD_Complaint_Data_Current__Year_To_Date_.tsv に保存していることを前提としています。必要に応じてコマンドを調整してください。

TSVファイルの内容を把握する

ClickHouseデータベースでの作業を始める前に、データの内容を把握しておきましょう。

ソースTSVファイルのフィールドを確認する

以下はTSVファイルにクエリを実行するコマンドの例ですが、まだ実行しないでください。
Query
応答例
ほとんどの場合、上記のコマンドを実行すると、入力データ内のどのフィールドが数値で、どれが String で、どれが Tuple かを確認できます。ただし、常にそうとは限りません。ClickHouse は数十億件のレコードを含むデータセットでも日常的に使われるため、スキーマを推論する際に数十億行をパースしなくて済むよう、確認する行数のデフォルト値は 100 行に設定されています。データセットは毎年数回更新されるため、以下の応答は実際の表示結果と一致しない場合があります。Data Dictionary を見ると、CMPLNT_NUM は数値ではなくテキストとして定義されていることがわかります。推論に使用するデフォルトの 100 行を、設定 SETTINGS input_format_max_rows_to_read_for_schema_inference=2000 で上書きすると、 内容をより正確に把握できます。注: バージョン 22.5 以降では、スキーマ推論のデフォルトは 25,000 行になっています。そのため、この設定を変更するのは、古いバージョンを使用している場合か、25,000 行を超えてサンプルする必要がある場合だけにしてください。
このコマンドをコマンドラインで実行してください。ダウンロードした TSV ファイル内のデータをクエリするために clickhouse-local を使用します。
Query
Response
この時点で、TSV file のカラムが、dataset web pageこのデータセットのカラム セクションで指定されている名前と型に一致していることを確認してください。データ型はそれほど厳密ではなく、すべての数値フィールドは Nullable(Float64) に設定され、その他のフィールドはすべて Nullable(String) になっています。データを保存するための ClickHouse テーブル を作成する際は、より適切でパフォーマンスの高い型を指定できます。

適切なスキーマを決める

フィールドにどの型を使うべきかを判断するには、まずデータがどのようなものかを把握する必要があります。たとえば、フィールド JURISDICTION_CODE は数値です。UInt8 にすべきか、Enum にすべきか、あるいは Float64 が適切なのかを検討する必要があります。
Query
Response
クエリの応答から、JURISDICTION_CODEUInt8 にうまく収まることがわかります。 同様に、いくつかの String フィールドについても、それらが DateTime フィールドや LowCardinality(String) フィールドに適しているか確認します。 たとえば、フィールド PARKS_NM には “該当する場合、発生場所となった NYC の公園、遊び場、または緑地の名称 (州立公園は含まれません) ” とあります。ニューヨーク市内の公園名は、LowCardinality(String) の有力な候補といえるでしょう。
Query
Response
いくつかの公園名を見てみましょう。
Query
Response
執筆時点で使用しているデータセットでは、PARK_NMカラムに含まれる公園や遊び場の異なる値は数百件しかありません。これは、LowCardinality(String)フィールドでは異なる文字列を 10,000 未満に抑えるというLowCardinalityの推奨に照らすと、少ない数です。

DateTime フィールド

データセットの Web ページこのデータセットのカラム セクションによると、報告されたイベントの開始時刻と終了時刻に対応する日付・時刻フィールドがあります。CMPLNT_FR_DTCMPLT_TO_DT の最小値および最大値を確認すると、これらのフィールドが常に入力されているかどうかの見当をつけられます。
Query
Response
Query
Response
Query
Response
Query
Response

方針を立てる

上記の調査に基づくと、次のように判断できます。
  • JURISDICTION_CODEUInt8 に CAST する必要があります。
  • PARKS_NMLowCardinality(String) に CAST する必要があります
  • CMPLNT_FR_DTCMPLNT_FR_TM には常に値が入っています (デフォルト時刻の 00:00:00 が入っている可能性があります)
  • CMPLNT_TO_DTCMPLNT_TO_TM は空の場合があります
  • ソースでは、日付と時刻は別々のフィールドに格納されています
  • 日付は mm/dd/yyyy フォーマットです
  • 時刻は hh:mm:ss フォーマットです
  • 日付と時刻は連結して DateTime 型にできます
  • 1970年1月1日より前の日付がいくつかあるため、64ビットの DateTime が必要です
型については、さらに多くの変更が必要ですが、いずれも同じ調査手順で判断できます。フィールド内の異なる文字列の数、数値の最小値と最大値を確認して、判断してください。ガイドの後半で示すテーブルスキーマには、低カーディナリティの文字列と符号なし整数フィールドが多く、浮動小数点の数値はごくわずかしかありません。

日付フィールドと時刻フィールドを連結する

日付フィールド CMPLNT_FR_DT と時刻フィールド CMPLNT_FR_TM を連結して、DateTime にキャスト可能な 1 つの String にするには、連結演算子でつないだ 2 つのフィールド CMPLNT_FR_DT || ' ' || CMPLNT_FR_TM を選択します。CMPLNT_TO_DT フィールドと CMPLNT_TO_TM フィールドについても同様です。
Query
Response

日付と時刻の String を DateTime64 型に変換する

このガイドの前半で、TSVファイルには 1970 年 1 月 1 日より前の日付が含まれていることがわかりました。つまり、これらの日付には 64 ビットの DateTime64 型が必要です。さらに、日付は MM/DD/YYYY から YYYY/MM/DD フォーマットに変換する必要があります。これらはどちらも parseDateTime64BestEffort() で行えます。
Query
上の2行目と3行目には前のステップで連結した結果が含まれており、上の4行目と5行目ではその文字列を DateTime64 にパースしています。苦情の終了時刻が必ず存在するとは限らないため、parseDateTime64BestEffortOrNull を使用します。
Response
上に 1925 と表示されている日付は、データ内の誤りに起因するものです。元のデータには、本来 2019 - 2022 であるべき年が 1019 - 1022 になっているレコードがいくつかあります。64 ビットの DateTime で扱える最も古い日付が 1925 年 1 月 1 日であるため、それらは 1925 年 1 月 1 日として保存されています。

テーブルを作成

上で行った、各カラムに使用するデータ型の判断は、以下のテーブルスキーマに反映されています。また、このテーブルで使用する ORDER BYPRIMARY KEY も決める必要があります。ORDER BY または PRIMARY KEY の少なくとも一方を指定しなければなりません。以下に、ORDER BY に含めるカラムを決める際の指針をいくつか示します。詳細については、このドキュメントの末尾にある 次のステップ セクションを参照してください。

ORDER BY 句と PRIMARY KEY

  • ORDER BY タプルには、クエリのフィルタで使用されるフィールドを含めるべきです
  • ディスク上での圧縮を最大化するには、ORDER BY タプルをカーディナリティの昇順に並べるべきです
  • PRIMARY KEY タプルが存在する場合は、ORDER BY タプルの部分集合でなければなりません
  • ORDER BY のみが指定されている場合は、同じタプルが PRIMARY KEY として使用されます
  • 主キーの索引は、指定されていれば PRIMARY KEY タプルを使用して作成され、そうでない場合は ORDER BY タプルを使用して作成されます
  • PRIMARY KEY 索引は主記憶に保持されます
データセットと、それに対するクエリで答えたい問いを考えると、 ニューヨーク市の5つの行政区で、時間の経過に伴って報告された犯罪の種類を 見たいと判断するかもしれません。その場合、これらのフィールドを ORDER BY に 含めることになります。 3 つの候補カラムのカーディナリティを調べるために、TSVファイルに対してクエリを実行します。
Query
Response
カーディナリティ順に並べると、ORDER BY は次のようになります:
以下のテーブルでは、より読みやすいカラム名を使用します。上記の名前は次のようにマッピングされます。
データ型の変更と ORDER BY のタプルを合わせると、テーブル構造は次のようになります:

テーブルの主キーを確認する

ClickHouse の system データベース、特に system.table には、先ほど作成したテーブルに関する情報がすべて含まれています。このクエリを実行すると、ORDER BY (ソートキー) と PRIMARY KEY が表示されます。
レスポンス

データの前処理とインポート

データの前処理には clickhouse-local ツールを使用し、アップロードには clickhouse-client を使用します。

使用している clickhouse-local の引数

table='input' は、以下の clickhouse-local の引数に含まれています。clickhouse-local は、指定された入力 (cat ${HOME}/NYPD_Complaint_Data_Current__Year_To_Date_.tsv) を受け取り、その内容をテーブルに insert します。デフォルトのテーブル名は table です。このガイドでは、データの流れをわかりやすくするため、テーブル名を input に設定しています。clickhouse-local の最後の引数は、そのテーブルから選択するクエリ (FROM input) です。この結果が clickhouse-client にパイプされ、テーブル NYPD_Complaint にデータが取り込まれます。

データを確認する

このデータセットは年に1回以上更新されるため、件数がこのドキュメントに記載されている内容と一致しない場合があります。
Query
Response
ClickHouse内のデータセットのサイズは、元のTSVファイルのわずか12%です。元のTSVファイルのサイズとテーブルのサイズを比較してみましょう。
Query
Response

クエリをいくつか実行する

クエリ1. 月ごとの苦情件数を比較する

Query
Response

クエリ 2. 行政区ごとの苦情総数を比較する

Query
Response

次のステップ

ClickHouseにおけるスパースプライマリインデックスの実践的入門では、従来のリレーショナルデータベースと比較した場合のClickHouseの索引の違い、ClickHouseがスパースプライマリインデックスをどのように構築・利用するか、そして索引に関するベストプラクティスについて解説しています。
最終更新日 2026年7月3日