TSV 替换为 CSV 即可。
按照本指南操作时,你将:
- 探查:查询 TSV 文件的结构和内容。
- 确定目标 ClickHouse schema:选择合适的数据类型,并将现有数据映射到这些类型。
- 创建 ClickHouse 表。
- 预处理并将数据流式传输到 ClickHouse。
- 运行一些查询。
前置条件
- 访问 NYPD Complaint Data Current (Year To Date) 页面,点击 Export 按钮,然后选择 TSV for Excel 下载数据集。
- 安装 ClickHouse server 和客户端
关于本指南中所述命令的说明
- 一部分命令用于查询 TSV 文件,需要在命令行提示符下运行。
- 其余命令用于查询 ClickHouse,需要在
clickhouse-client或 Play UI 中运行。
本指南中的示例默认你已将 TSV 文件保存到
${HOME}/NYPD_Complaint_Data_Current__Year_To_Date_.tsv;如有需要,请相应调整命令。了解 TSV 文件
查看 TSV 源文件中的字段
Query
clickhouse-local 查询已下载的 TSV 文件中的数据。
Query
Response
Nullable(Float64),其余字段则都为 Nullable(String)。创建用于存储这些数据的 ClickHouse 表时,你可以指定更合适、性能更优的类型。
确定合适的 schema
JURISDICTION_CODE 是数值型:它应该使用 UInt8、Enum,还是 Float64 更合适?
Query
Response
JURISDICTION_CODE 很适合使用 UInt8。
同样,也可以查看一些 String 字段,看看它们是否更适合使用 DateTime 或 LowCardinality(String) 类型。
例如,字段 PARKS_NM 的描述是 “事发地点对应的纽约市公园、游乐场或绿地名称 (如适用;不包括州立公园) “。纽约市公园名称很可能适合使用 LowCardinality(String):
Query
Response
Query
Response
PARK_NM 列里只有几百个不同的公园和游乐场。根据 LowCardinality 的建议,LowCardinality(String) 字段中的不同字符串数量最好保持在 10,000 以下,因此这已经算是很小的数量了。
DateTime 字段
CMPLNT_FR_DT 和 CMPLT_TO_DT 的最小值和最大值,可以大致判断这些字段是否始终有值:
Query
Response
Query
Response
Query
Response
Query
Response
制定计划
JURISDICTION_CODE应转换为UInt8。PARKS_NM应转换为LowCardinality(String)CMPLNT_FR_DT和CMPLNT_FR_TM始终有值 (时间可能为默认值00:00:00)CMPLNT_TO_DT和CMPLNT_TO_TM可能为空- 在源数据中,日期和时间分别存储在不同的字段中
- 日期采用
mm/dd/yyyy格式 - 时间采用
hh:mm:ss格式 - 日期和时间可以拼接为 DateTime 类型
- 有些日期早于 1970 年 1 月 1 日,这意味着我们需要 64 位 DateTime
还有很多类型需要调整,这些都可以通过遵循相同的调查步骤来确定。查看某个字段中不同字符串的数量、数值的最小值和最大值,然后据此做出判断。指南后面给出的表 schema 中包含许多低基数 String 和无符号整数字段,而浮点数值字段很少。
拼接日期和时间字段
CMPLNT_FR_DT 和 CMPLNT_FR_TM 拼接成一个可转换为 DateTime 的 String,请选择用拼接运算符连接这两个字段:CMPLNT_FR_DT || ' ' || CMPLNT_FR_TM。CMPLNT_TO_DT 和 CMPLNT_TO_TM 字段的处理方式也相同。
Query
Response
将日期和时间 String 转换为 DateTime64 类型
MM/DD/YYYY 格式转换为 YYYY/MM/DD 格式。这两项操作都可以通过 parseDateTime64BestEffort() 完成。
Query
DateTime64。由于投诉结束时间不一定存在,因此使用 parseDateTime64BestEffortOrNull。
Response
上面显示为
1925 的日期是由数据错误造成的。原始数据中有几条记录的年份写成了 1019 - 1022,实际应为 2019 - 2022。由于 1925 年 1 月 1 日是 64 位 DateTime 可表示的最早日期,这些记录都会被存储为这一天。创建表
ORDER BY 和 PRIMARY 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索引会保存在主内存中
ORDER BY 中:
查询 TSV 文件以获取这三个候选列的基数:
Query
Response
ORDER BY 为:
下表将使用更便于阅读的列名,上述名称将映射为
ORDER BY 元组后,可得到如下表结构:
查找表的主键
system 数据库中,具体来说是 system.table,包含了你刚创建的这个表的全部信息。下面这个查询会显示 ORDER BY (排序键) 和 PRIMARY KEY:
预处理并导入数据
clickhouse-local 工具对数据进行预处理,并使用 clickhouse-client 将其上传。
使用的 clickhouse-local 参数
验证数据
该数据集每年会更新一次或多次,因此你的计数结果可能与本文档中的内容不一致。
Query
Response
Query
Response
执行一些查询
查询 1:按月比较投诉数量
Query
Response
查询 2. 比较各区的投诉总数
Query
Response