TSV with CSV in your format arguments.
While working through this guide you will:
- Investigate: Query the structure and content of the TSV file.
- Determine the target ClickHouse schema: Choose proper data types and map the existing data to those types.
- Create a ClickHouse table.
- Preprocess and stream the data to ClickHouse.
- Run some queries against ClickHouse.
Prerequisites
- Download the dataset by visiting the NYPD Complaint Data Current (Year To Date) page, clicking the Export button, and choosing TSV for Excel.
- Install ClickHouse server and client
A note about the commands described in this guide
There are two types of commands in this guide:- Some of the commands are querying the TSV files, these are run at the command prompt.
- The rest of the commands are querying ClickHouse, and these are run in the
clickhouse-clientor Play UI.
The examples in this guide assume that you have saved the TSV file to
${HOME}/NYPD_Complaint_Data_Current__Year_To_Date_.tsv, please adjust the commands if needed.Familiarize yourself with the TSV file
Before starting to work with the ClickHouse database familiarize yourself with the data.Look at the fields in the source TSV file
This is an example of a command to query a TSV file, but don’t run it yet.Query
clickhouse-local to query the data in the TSV file you downloaded.
Query
Response
Nullable(Float64), and all other fields are Nullable(String). When you create a ClickHouse table to store the data you can specify more appropriate and performant types.
Determine the proper schema
In order to figure out what types should be used for the fields it is necessary to know what the data looks like. For example, the fieldJURISDICTION_CODE is a numeric: should it be a UInt8, or an Enum, or is Float64 appropriate?
Query
Response
JURISDICTION_CODE fits well in a UInt8.
Similarly, look at some of the String fields and see if they’re well suited to being DateTime or LowCardinality(String) fields.
For example, the field PARKS_NM is described as “Name of NYC park, playground or greenspace of occurrence, if applicable (state parks aren’t included)”. The names of parks in New York City may be a good candidate for a LowCardinality(String):
Query
Response
Query
Response
PARK_NM column. This is a small number based on the LowCardinality recommendation to stay below 10,000 distinct strings in a LowCardinality(String) field.
DateTime fields
Based on the Columns in this Dataset section of the dataset web page there are date and time fields for the start and end of the reported event. Looking at the min and max of theCMPLNT_FR_DT and CMPLT_TO_DT gives an idea of whether or not the fields are always populated:
Query
Response
Query
Response
Query
Response
Query
Response
Make a plan
Based on the above investigation:JURISDICTION_CODEshould be cast asUInt8.PARKS_NMshould be cast toLowCardinality(String)CMPLNT_FR_DTandCMPLNT_FR_TMare always populated (possibly with a default time of00:00:00)CMPLNT_TO_DTandCMPLNT_TO_TMmay be empty- Dates and times are stored in separate fields in the source
- Dates are
mm/dd/yyyyformat - Times are
hh:mm:ssformat - Dates and times can be concatenated into DateTime types
- There are some dates before January 1st 1970, which means we need a 64 bit DateTime
There are many more changes to be made to the types, they all can be determined by following the same investigation steps. Look at the number of distinct strings in a field, the min and max of the numerics, and make your decisions. The table schema that is given later in the guide has many low cardinality strings and unsigned integer fields and very few floating point numerics.
Concatenate the date and time fields
To concatenate the date and time fieldsCMPLNT_FR_DT and CMPLNT_FR_TM into a single String that can be cast to a DateTime, select the two fields joined by the concatenation operator: CMPLNT_FR_DT || ' ' || CMPLNT_FR_TM. The CMPLNT_TO_DT and CMPLNT_TO_TM fields are handled similarly.
Query
Response
Convert the date and time String to a DateTime64 type
Earlier in the guide we discovered that there are dates in the TSV file before January 1st 1970, which means that we need a 64 bit DateTime type for the dates. The dates also need to be converted fromMM/DD/YYYY to YYYY/MM/DD format. Both of these can be done with parseDateTime64BestEffort().
Query
DateTime64. As the complaint end time isn’t guaranteed to exist parseDateTime64BestEffortOrNull is used.
Response
The dates shown as
1925 above are from errors in the data. There are several records in the original data with dates in the years 1019 - 1022 that should be 2019 - 2022. They’re being stored as Jan 1st 1925 as that is the earliest date with a 64 bit DateTime.Create a table
The decisions made above on the data types used for the columns are reflected in the table schema below. We also need to decide on theORDER BY and PRIMARY KEY used for the table. At least one
of ORDER BY or PRIMARY KEY must be specified. Here are some guidelines on deciding on the
columns to includes in ORDER BY, and more information is in the Next Steps section at the end
of this document.
ORDER BY and PRIMARY KEY clauses
- The
ORDER BYtuple should include fields that are used in query filters - To maximize compression on disk the
ORDER BYtuple should be ordered by ascending cardinality - If it exists, the
PRIMARY KEYtuple must be a subset of theORDER BYtuple - If only
ORDER BYis specified, then the same tuple will be used asPRIMARY KEY - The primary key index is created using the
PRIMARY KEYtuple if specified, otherwise theORDER BYtuple - The
PRIMARY KEYindex is kept in main memory
ORDER BY:
| Column | Description (from the data dictionary) |
|---|---|
| OFNS_DESC | Description of offense corresponding with key code |
| RPT_DT | Date event was reported to police |
| BORO_NM | The name of the borough in which the incident occurred |
Query
Response
ORDER BY becomes:
The table below will use more easily read column names, the above names will be mapped to
ORDER BY tuple gives this table structure:
Finding the primary key of a table
The ClickHousesystem database, specifically system.table has all of the information about the table you
just created. This query shows the ORDER BY (sorting key), and the PRIMARY KEY:
Preprocess and import data
We will useclickhouse-local tool for data preprocessing and clickhouse-client to upload it.
clickhouse-local arguments used
Validate the data
The dataset changes once or more per year, your counts may not match what is in this document.
Query
Response
Query
Response
Run some queries
Query 1. Compare the number of complaints by month
Query
Response
Query 2. Compare total number of complaints by borough
Query
Response