Package: simplech
Simple ClickHouse libVery simple ClickHouse client that simplify you interration with DBMS by using dicts as payload.
It contains two versions: synchronous for reguar usage and asynchronous for use withasyncio. Sync version internally uses low-level python http client. Both are use high-performance json serializer/parserujson.InstallationInstall usingpipfrom pypi repositorypipinstall-UsimplechOr latest version from gitpip install -U git+https://github.com/madiedinro/simple-clickhouse.gitConnection paramsComes with async versionAsyncClickHouseand syncClickHouse.При использовании в Rockstat, параметры указывать не требуется. Они подставляются автоматически из переменных окружения.fromsimplechimportAsyncClickHousech=AsyncClickHouse()host:[default:127.0.0.1] Хост с clickhouseport:[default:8123]  Порт подключенияdb:[default:default]  Название базы данныхscheme:[default:http]  Протокол http/httpsuser:[default:default]  Имя пользователяpassword:[default:""]  Парольsession:[default:False] Использовать сессию. Идентификатор сессии генерируется автоматическиsession_id:[default:""] Идентификатор сессии взамен автоматически сгенериованногоdsn:[default:""] Использовать DSN для подключения (пример:http://default@127.0.0.1:8123/stats)debug:[default:False] Включение логов в режим отладкиflush_every:[default:5] Every X seconds data will be flushed to dbbuffer_limit:[default:1000] Буффер записи на таблицу. При достижении будет произведена запись в БДloop:[default:None] При необходимости указать конкретный loop (для асинхронной версии)timeout:[default:10] Время ожидания запроса в секундахПеременные окруженияCH_DSN,CLICKHOUSE_DSN, при наличии которых, их значение будет использовано в качестве DSN.Приоритет DSN: 1. аргумент конструктораdsn, 2.CH_DSN3.CLICKHOUSE_DSNAsync versionSelecting without decodingfromsimplechimportAsyncClickHousech=AsyncClickHouse(host='localhost',user='default')print(awaitch.select('SHOW DATABASES'))[Out]:defaultsystemSelecting as dict's steamПолучить записи по отдельности, в видеdict.
К запросу автоматически будет добавленоFORMAT JSONEachRow.asyncforobjinch.objects_stream('SELECT * FROM events'):print(obj)[Out]:{'browser_if':[0,2],'browser_sr_asp':4000,'browser_sr_avail_h':740,'browser_sr_avail_w':360,'browser_sr_oAngle':0...}...Disabling decoding for streaming datafromsimplechimportbytes_decoderasyncforobjinch.objects_stream('SELECT * from events',decoder=none_decoder):print(obj)[Out]:b'{"browser_if": [0, 2],"browser_sr_asp": 4000,"browser_sr_avail_h": 740,"browser_sr_avail_w": 360,"browser_sr_oAngle": 0}'#...Чтобы получить результат в виде строки воспользуйтесьbytes_decoderExecuting sql statementsДля для записи данных, управления БД и других операция (не select) слудует использовать методrunawaitch.run('CREATE TABLE my_table (name String, num UInt64) ENGINE=Log ')Можно использовать для "ручной" записи данных>>>awaitch.run('INSERT INTO my_table (name, num) VALUES("myname", 7)')Microbatch writing using context managerВ simplech запись объекта производится при помощи методаpush, но непосредственно запись
будет произведена при достижении лимита буффера, устанавливаемого параметром конструктораbuffer_limit.newwithch.table('tablename')asw:forrecinrecs:w.push(rec)On exit context all data will be flushed.Old manual conrolled mechanic.foriinrange(1,1500):ch.push('my_table',{'name':'hux','num':i})ch.flush('my_table')awaitch.select('SELECT count() FROM my_table')[Out]:1499Доступен методflush_all(), он производит запись всех буфферов.ch.push('my_table',{'name':'hux','num':1})ch.push('other_table',my_other_obj)# orch.flush_all()Some Simpe MagickSchema detectionTo create instance of TableDiscovery callch.discover(table, records=None, columns=None)records is a list with recordscolumnts is a dict where key is table columnt name / field name; value is the field data type.One of records or columns should be filled.ch.discover('table_name', records=[...])-> TableDiscovery instansech.discover('table', columns={...})td_deals=ch.discover('deals',columns={'id':'Int64','uid':'Int64','cid':'String','sale':'Int64','date':'Date','date_time':'DateTime','account_id':'Int64'})Detect using present datach=ClickHouse()td=ch.discovery(deals,'deals')td.date('date').idx('account_id','date').metrics('sale')TableDiscovery.merge_tree()ch.merge_tree()resultCREATE TABLE IF NOT EXISTS `deals` (
  `id`  UInt64,
  `uid`  UInt64,
  `cid`  String,
  `sale`  UInt64,
  `date`  Date,
  `date_time`  DateTime,
  `account_id`  UInt64
) ENGINE MergeTree() PARTITION BY toYYYYMM(`date`) ORDER BY (`account_id`, `date`) SETTINGS index_granularity=8192Code generationmNext times after use table auto discovery you shoud use fixed layout. To to this easy tryTableDiscovery.pycode()code=td.pycode()print(code)will be returnedtd = ch.discover('deals', columns={
    'id': 'Int64', 
    'uid': 'Int64', 
    'cid': 'String', 
    'sale': 'Int64', 
    'date': 'Date', 
    'date_time': 'DateTime', 
    'account_id': 'Int64'
})\
.metrics('sale')\
.dimensions('date_time', 'account_id', 'cid', 'uid', 'id', 'date')\
.date('date')\
.idx('account_id', 'date')Correct detected / implicit set data-typesTableDiscovery.int(*args)set columnts to intreturns selfSet date columnsTableDiscovery.date(*args)Set date columnreturns selfSet str columnsTableDiscovery.str(*args)Set strinmg columnreturns selfColumns configurationSet primary key columns.idx(*args)returns selfSet metrics.metrics(*args)returns selfother marked as dimensionsSet dimensions.dimensions(*args)other marked as metricsPrint table create statement / execute querytd.merge_tree(Execute=True|False)Chainingtd.date('date').metrics('sale').idx('account_id', 'date')Discovery TODOSupport all ClickHouse types, especially ArraysDiscovery by DB Table structurewithtd.table('tablename')asw:forrecinrecs:w.push(rec)Difference handling. Be careful currently it Proof of conceptSync versionch=ClickHouse()upd=[{'name':'lalala','value':1},{'name':'bababa','value':2},{'name':'nanana','value':3}]td=ch.discover('test1',upd).metrics('value')d1='2019-01-10'd2='2019-01-13'new_recs=[]withtd.difference(d1,d2,upd)asd:forrowind:td.push(row)print(row)All records will be flushed to DB on context exitAsync versionch=AsyncClickHouse()# new dataupd=[{'name':'lalala','value':1},{'name':'bababa','value':2},{'name':'nanana','value':3}]td=ch.discover('test1',upd).metrics('value')d1='2019-01-10'd2='2019-01-13'asyncwithtd.difference(d1,d2,upd)asd:asyncforrowind:td.push(row)# Graceful unloadch.close()Difference TODOFocus on CollapsingMergeTreeСинхронная версияВыполнение запроса и чтение всего результата сразуfromsimplechimportClickHousech=ClickHouse(host='localhost',user='default')print(ch.select('SHOW DATABASES'))Получение записей потокомforobjinch.objects_stream('SELECT * from events'):print(obj)Выполнение SQL операцийch.run('CREATE TABLE my_table (name String, num UInt64) ENGINE=Log ')Запись данныхforiinrange(1,1500):ch.push('my_table',{'name':'hux','num':i})ch.flush('my_table')или>>>ch.flush_all()better approachmy_data=[{'name':'lalala','value':1},{'name':'bababa','value':2},{'name':'nanana'}]withch.table('mytbl')asc:forrecinmy_data:c.push(record)all data will be flushed on exit contextLicenseThe MIT License (MIT)Copyright (c) 2018-2019 Dmitry RodinPermission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.