我正在尝试将熊猫数据框插入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
答案 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