美文网首页
Clickhouse 实践之11亿出租车出行信息处理

Clickhouse 实践之11亿出租车出行信息处理

作者: c3729438b799 | 来源:发表于2017-12-31 21:44 被阅读1088次

    ClickHouse功能非常丰富。 它支持16个不同的表引擎,它包括动画进度指示器和语法高亮显示,并且它的性能在开源产品中出类拔萃。

    这就是说,这个软件并不是像PostgreSQL这样的替代品。 它缺少事务,完整的UPDATE和DELETE语句,像DROP TABLE这样的调用不能在超过54 GB的表上工作,而无需先改变服务器的配置。 尽管如此,它还是一个非常值得敬重的实时大数据分析处理平台。

    Yandex的高级软件工程师Alexey Milovidov和ClickHouse的核心贡献者之一,编写了一个基准指南,在基准测试中使用的11亿辆出租车数据集来对数据库进行基准测试。

    在这个博客文章中,我将使用我曾经用来对Amazon Athena,BigQuery,Elasticsearch,kdb + / q,MapD,PostgreSQL,Presto,Redshift,Spark和Vertica进行基准测试的完全相同的集合来运行ClickHouse的基准测试。 我编制了这些基准的单页总结。

    硬件

    在这个基准测试中,我将运行一个全新安装的Ubuntu 14.04.3 LTS,主频为3.4 GHz的Intel Core i5 4670K,16 GB DDR3 RAM和SanDisk SDSSDHII960G 960 GB SSD硬盘。

    ClickHouse 启动和运行

    我将首先运行一些命令,以便从预先制作的包中安装ClickHouse。

    $echo"deb http://repo.yandex.ru/clickhouse/trusty stable main"|\sudo tee -a /etc/apt/sources.list

    $ sudo apt-key adv\--keyserver keyserver.ubuntu.com\--recv E0C56BD4

    $ sudo apt-get update

    然后,我将安装客户端和服务器软件的版本1.1.54140。

    $ sudo apt-get install\clickhouse-client\clickhouse-server-common

    然后我将启动服务器。 我还没有设置任何定制的配置,所以所有的设置是你开箱即用的。

    $ sudo service clickhouse-server start

    加载 11亿的Trips数据进入ClickHouse

    我正在使用的数据集被分成56个gzip压缩的CSV文件。 我首先将它们导入由“Log”引擎支持的“Trips”表。

    $ clickhouse-client

    CREATE TABLE trips (

    trip_id UInt32,

    vendor_id String,

    pickup_datetime DateTime,

    dropoff_datetime Nullable(DateTime),

    store_and_fwd_flag Nullable(FixedString(1)),

    rate_code_id Nullable(UInt8),

    pickup_longitude Nullable(Float64),

    pickup_latitude Nullable(Float64),

    dropoff_longitude Nullable(Float64),

    dropoff_latitude Nullable(Float64),

    passenger_count Nullable(UInt8),

    trip_distance Nullable(Float64),

    fare_amount Nullable(Float32),

    extra Nullable(Float32),

    mta_tax Nullable(Float32),

    tip_amount Nullable(Float32),

    tolls_amount Nullable(Float32),

    ehail_fee Nullable(Float32),

    improvement_surcharge Nullable(Float32),

    total_amount Nullable(Float32),

    payment_type Nullable(String),

    trip_type Nullable(UInt8),

    pickup Nullable(String),

    dropoff Nullable(String),

    cab_type Nullable(String),

    precipitation Nullable(Int8),

    snow_depth Nullable(Int8),

    snowfall Nullable(Int8),

    max_temperature Nullable(Int8),

    min_temperature Nullable(Int8),

    average_wind_speed Nullable(Int8),

    pickup_nyct2010_gid Nullable(Int8),

    pickup_ctlabel Nullable(String),

    pickup_borocode Nullable(Int8),

    pickup_boroname Nullable(String),

    pickup_ct2010 Nullable(String),

    pickup_boroct2010 Nullable(String),

    pickup_cdeligibil Nullable(FixedString(1)),

    pickup_ntacode Nullable(String),

    pickup_ntaname Nullable(String),

    pickup_puma Nullable(String),

    dropoff_nyct2010_gid Nullable(UInt8),

    dropoff_ctlabel Nullable(String),

    dropoff_borocode Nullable(UInt8),

    dropoff_boroname Nullable(String),

    dropoff_ct2010 Nullable(String),

    dropoff_boroct2010 Nullable(String),

    dropoff_cdeligibil Nullable(String),

    dropoff_ntacode Nullable(String),

    dropoff_ntaname Nullable(String),

    dropoff_puma Nullable(String)

    ) ENGINE = Log;

    数据集本身使用逗号分隔字段。 数据的内容都不包含任何逗号,所以没有引用来帮助转义数据。 NULL值由逗号分隔符之间简单的没有任何内容来定义。 通常情况下这不是问题,但ClickHouse空字段不会被视为NULL,以避免空字符串的歧义。 出于这个原因,我需要通过一个转换脚本来管理数据,将用 \N替换所有的空值。

    以下是转换脚本。

    $ cat trans.py

    import sys

    for line in sys.stdin:

        print ','.join([item if len(item.strip())else '\N'

                        for item in line.strip().split(',')])

    这是我用来将11亿条记录导入Trips表的bash命令。

    $ time(for filename in /home/mark/trips/trips_x*.csv.gz;do

                gunzip -c $filename | \

                    python trans.py | \

                    clickhouse-client \

                        --query="INSERT INTO trips FORMAT CSV"

            done)

    执行上述脚本大约3小时27分35秒。 毫无疑问,如果我没有使用Python脚本来转换内容,那么这个时间就会大大减少。 以下显示了导入过程中的顶层命令,您可以看到Python脚本耗尽了大量资源。

    ... %CPU %MEM TIME+ COMMAND

    ... 99.2  0.1  0:32.76 python trans.py

    ... 45.3 12.3  0:17.14 clickhouse-client --query=INSERT INTO trips FORMAT CSV

    ... 28.3  0.0  0:09.89 gzip -d -c /home/mark/trips/trips_xac.csv.gz

    使用日志引擎支持的表,我将创建一个使用MergeTree引擎的新表。 这个表格将填充Trips表的内容。

    在Milovidov的指导中,这个表的一些字段从字符串转换成枚举列。 其中一些列不支持在我的数据集版本中看到的每个值,所以我需要删除这些字段的转换过程。 下面是我的版本的MergeTree支持表。

    下面39分57秒完成。

    CREATETABLEtrips_mergetree

    ENGINE = MergeTree(pickup_date, pickup_datetime, 8192)

    AS SELECT

    trip_id, CAST(vendor_id AS Enum8('1' = 1, '2' = 2, 'CMT' = 3, 'VTS' = 4, 'DDS' = 5, 'B02512' = 10, 'B02598' = 11, 'B02617' = 12, 'B02682' = 13, 'B02764' = 14)) AS vendor_id,

    toDate(pickup_datetime) AS pickup_date,

    ifNull(pickup_datetime, toDateTime(0)) AS pickup_datetime,

    toDate(dropoff_datetime) AS dropoff_date,

    ifNull(dropoff_datetime, toDateTime(0)) AS dropoff_datetime,

    assumeNotNull(store_and_fwd_flag) IN ('Y', '1', '2') AS store_and_fwd_flag,

    assumeNotNull(rate_code_id) AS rate_code_id,

    assumeNotNull(pickup_longitude) AS pickup_longitude,

    assumeNotNull(pickup_latitude) AS pickup_latitude,

    assumeNotNull(dropoff_longitude) AS dropoff_longitude,

    assumeNotNull(dropoff_latitude) AS dropoff_latitude,

    assumeNotNull(passenger_count) AS passenger_count,

    assumeNotNull(trip_distance) AS trip_distance,

    assumeNotNull(fare_amount) AS fare_amount,

    assumeNotNull(extra) AS extra,

    assumeNotNull(mta_tax) AS mta_tax,

    assumeNotNull(tip_amount) AS tip_amount,

    assumeNotNull(tolls_amount) AS tolls_amount,

    assumeNotNull(ehail_fee) AS ehail_fee,

    assumeNotNull(improvement_surcharge) AS improvement_surcharge,

    assumeNotNull(total_amount) AS total_amount,

    CAST((assumeNotNull(payment_type) AS pt) IN ('CSH', 'CASH', 'Cash', 'CAS', 'Cas', '1') ? 'CSH' : (pt IN ('CRD', 'Credit', 'Cre', 'CRE', 'CREDIT', '2') ? 'CRE' : (pt IN ('NOC', 'No Charge', 'No', '3') ? 'NOC' : (pt IN ('DIS', 'Dispute', 'Dis', '4') ? 'DIS' : 'UNK'))) AS Enum8('CSH' = 1, 'CRE' = 2, 'UNK' = 0, 'NOC' = 3, 'DIS' = 4)) AS payment_type_,

    assumeNotNull(trip_type) AS trip_type,

    ifNull(toFixedString(unhex(pickup), 25), toFixedString('', 25)) AS pickup,

    ifNull(toFixedString(unhex(dropoff), 25), toFixedString('', 25)) AS dropoff,

    CAST(assumeNotNull(cab_type) AS Enum8('yellow' = 1, 'green' = 2, 'uber' = 3)) AS cab_type,

    assumeNotNull(pickup_nyct2010_gid) AS pickup_nyct2010_gid,

    toFloat32(ifNull(pickup_ctlabel, '0')) AS pickup_ctlabel,

    assumeNotNull(pickup_borocode) AS pickup_borocode,

    assumeNotNull(pickup_boroname) AS pickup_ct2010,

    toFixedString(ifNull(pickup_boroct2010, '0000000'), 7) AS pickup_boroct2010,

    assumeNotNull(ifNull(pickup_cdeligibil, ' ')) AS pickup_cdeligibil,

    toFixedString(ifNull(pickup_ntacode, '0000'), 4) AS pickup_ntacode,

    assumeNotNull(pickup_ntaname) AS pickup_ntaname,

    toUInt16(ifNull(pickup_puma, '0')) AS pickup_puma,

    assumeNotNull(dropoff_nyct2010_gid) AS dropoff_nyct2010_gid,

    toFloat32(ifNull(dropoff_ctlabel, '0')) AS dropoff_ctlabel,

    assumeNotNull(dropoff_borocode) AS dropoff_borocode,

    assumeNotNull(dropoff_boroname) AS dropoff_ct2010,

    toFixedString(ifNull(dropoff_boroct2010, '0000000'), 7) AS dropoff_boroct2010,

    assumeNotNull(ifNull(dropoff_cdeligibil, ' ')) AS dropoff_cdeligibil,

    toFixedString(ifNull(dropoff_ntacode, '0000'), 4) AS dropoff_ntacode,

    assumeNotNull(dropoff_ntaname) AS dropoff_ntaname,

    toUInt16(ifNull(dropoff_puma, '0')) AS dropoff_puma

    FROM trips

    ClickHouse 基准测试

    对于这个基准测试,我将通过ClickHouse CLI运行SQL命令。 默认情况下,CLI在每个SELECT语句后以毫秒粒度打印计时遥测。

    下面引用的时间是一系列运行中查看的最低查询次数。 和我所有的基准一样,我使用最低的查询时间来表示“最高速度”。

    $ clickhouse-client

    以下在1.034秒内完成。

    SELECT cab_type,count(*) FROM trips_mergetree GROUP BY cab_type

    以下完成在3.058秒。

    SELECT passenger_count,avg(total_amount) FROM trips_mergetree GROUP BY passenger_count

    以下在5.354秒完成。

    SELECT passenger_count, toYear(pickup_date) AS year,count(*) FROM trips_mergetree GROUP BY passenger_count,year

    以下在12.748秒内完成。

    SELECT passenger_count, toYear(pickup_date) AS year,round(trip_distance) AS distance,count(*) FROM trips_mergetree GROUP BY passenger_count,year,distance ORDER BY year,count(*) DESC

    这些结果把我的基准测试#6位置ClickHouse。 所看到的性能,鉴于这个基准测试的硬件,是令人印象深刻的。

    欢迎大家在各种应用场景中尝试使用 ClickHouse,ClickHouse 确实是一个不可多得的开源实时大数据处理平台。

    相关文章

      网友评论

          本文标题:Clickhouse 实践之11亿出租车出行信息处理

          本文链接:https://www.haomeiwen.com/subject/rbiagxtx.html