熊猫:如何将数据框插入Clickhouse

时间:2019-10-16 21:49:09

标签: python pandas clickhouse

我正在尝试将熊猫数据框插入Clickhouse。

这是我的代码

import pandas
import sqlalchemy as sa

uri = 'clickhouse://default:@localhost/default'
ch_db = sa.create_engine(uri)

pdf = pandas.DataFrame.from_records([
    {'year': 1994, 'first_name': 'Vova'},
    {'year': 1995, 'first_name': 'Anja'},
    {'year': 1996, 'first_name': 'Vasja'},
    {'year': 1997, 'first_name': 'Petja'},
])

pdf.to_sql('test_humans', ch_db, if_exists='append', index=False)

这是我收到的错误。这是否与关于引擎的一些多余的额外争论有关?我该如何解决?

  

异常:代码:62,e.displayText()= DB :: Exception:语法错误:   在位置65(第7行,第2行)失败:FORMAT   TabSeparatedWithNamesAndTypes。预期之一:引擎,存储   定义(版本19.15.2.2(正式版本))

记录

  

INFO:sqlalchemy.engine.base.Engine:EXISTS表test_humans   INFO:sqlalchemy.engine.base.Engine:{}   INFO:sqlalchemy.engine.base.Engine:创建表test_humans(           first_name TEXT,           年BIGINT)

     

INFO:sqlalchemy.engine.base.Engine:{}   INFO:sqlalchemy.engine.base.Engine:ROLLBACK

4 个答案:

答案 0 :(得分:1)

您还可以使用https://github.com/kszucs/pandahouse插入数据框,而无需进行额外的转换。

pip安装pandahouse

import pandahouse as ph

pdf = pandas.DataFrame.from_records([
    {'year': 1994, 'first_name': 'Vova'},
    {'year': 1995, 'first_name': 'Anja'},
    {'year': 1996, 'first_name': 'Vasja'},
    {'year': 1997, 'first_name': 'Petja'},
])

connection = dict(database='default',
                  host='localhost',
                  user='default',
                  password='')

ph.to_clickhouse(pdf, 'test_humans', index=False, chunksize=100000, connection=connection)

答案 1 :(得分:0)

您可以在没有sqlalchemy的情况下进行操作。

pip安装clickhouse驱动程序

from clickhouse_driver import Client

client = Client('localhost')
df = pandas.DataFrame.from_records([
    {'year': 1994, 'first_name': 'Vova'},
    {'year': 1995, 'first_name': 'Anja'},
    {'year': 1996, 'first_name': 'Vasja'},
    {'year': 1997, 'first_name': 'Petja'},
])
# df processing blablabla...
client.execute("INSERT INTO your_table VALUES", df.to_dict('records'))

希望这会有所帮助。

答案 2 :(得分:0)

sqlalchemy-clickhouse无法自动创建表(至少直到版本 0.1.5.post0 包括在内),并将表创建的所有sql查询解释为 SELECT -总是以 FORMAT TabSeparatedWithNamesAndTypes 子句结尾的查询。

要解决此问题,需要使用infi.clickhouse_orm-api(此模块随 sqlalchemy-clickhouse 一起提供)手动创建表:

import pandas as pd
from infi.clickhouse_orm.engines import Memory
from infi.clickhouse_orm.fields import UInt16Field, StringField
from infi.clickhouse_orm.models import Model
from sqlalchemy import create_engine


# define the ClickHouse table schema
class Test_Humans(Model):
    year = UInt16Field()
    first_name = StringField()
    engine = Memory()


engine = create_engine('clickhouse://default:@localhost/test')

# create table manually
with engine.connect() as conn:
    conn.connection.create_table(Test_Humans) # https://github.com/Infinidat/infi.clickhouse_orm/blob/master/src/infi/clickhouse_orm/database.py#L142

pdf = pd.DataFrame.from_records([
    {'year': 1994, 'first_name': 'Vova'},
    {'year': 1995, 'first_name': 'Anja'},
    {'year': 1996, 'first_name': 'Vasja'},
    {'year': 1997, 'first_name': 'Petja'},
    # ! sqlalchemy-clickhouse ignores the last item so add fake one
    {}
])

pdf.to_sql('test_humans', engine, if_exists='append', index=False)

请考虑到 sqlalchemy-clickhouse 会忽略最后一项,因此添加伪造的项(请参阅source code和相关的issue 10)。

让我们检查数据库中的此表:

SELECT *
FROM test.test_humans

┌─year─┬─first_name─┐
│ 1994 │ Vova       │
│ 1995 │ Anja       │
│ 1996 │ Vasja      │
│ 1997 │ Petja      │
└──────┴────────────┘

4 rows in set. Elapsed: 0.003 sec.
*/

答案 3 :(得分:0)

从 0.2.0 版开始,clickhouse_driver 实现方法 insert_dataframe。请参阅:https://clickhouse-driver.readthedocs.io/en/latest/api.html#clickhouse_driver.Client.insert_dataframe