chdb-io / chdb

chDB is an in-process OLAP SQL Engine ๐Ÿš€ powered by ClickHouse
https://doc.chdb.io
Apache License 2.0
1.85k stars 71 forks source link
chdb clickhouse clickhouse-database clickhouse-server data-science database embedded-database olap python sql
๐Ÿ“ข chDB joins the ClickHouse family ๐Ÿ+๐Ÿš€
[![Build X86](https://github.com/chdb-io/chdb/actions/workflows/build_linux_x86_wheels.yml/badge.svg?event=release)](https://github.com/chdb-io/chdb/actions/workflows/build_linux_x86_wheels.yml) [![PyPI](https://img.shields.io/pypi/v/chdb.svg)](https://pypi.org/project/chdb/) [![Downloads](https://static.pepy.tech/badge/chdb)](https://pepy.tech/project/chdb) [![Discord](https://img.shields.io/discord/1098133460310294528?logo=Discord)](https://discord.gg/D2Daa2fM5K) [![Twitter](https://img.shields.io/twitter/url/http/shields.io.svg?style=social&label=Twitter)](https://twitter.com/chdb_io)

chDB

chDB is an in-process SQL OLAP Engine powered by ClickHouse [^1] For more details: The birth of chDB

Features

Arch

Get Started

Get started with chdb using our Installation and Usage Examples


Installation

Currently, chDB supports Python 3.8+ on macOS and Linux (x86_64 and ARM64).

pip install chdb

Usage

Run in command line

python3 -m chdb SQL [OutputFormat]

python3 -m chdb "SELECT 1,'abc'" Pretty


Data Input

The following methods are available to access on-disk and in-memory data formats:

๐Ÿ—‚๏ธ Query On File

(Parquet, CSV, JSON, Arrow, ORC and 60+)
You can execute SQL and return desired format data. ```python import chdb res = chdb.query('select version()', 'Pretty'); print(res) ``` ### Work with Parquet or CSV ```python # See more data type format in tests/format_output.py res = chdb.query('select * from file("data.parquet", Parquet)', 'JSON'); print(res) res = chdb.query('select * from file("data.csv", CSV)', 'CSV'); print(res) print(f"SQL read {res.rows_read()} rows, {res.bytes_read()} bytes, elapsed {res.elapsed()} seconds") ``` ### Pandas dataframe output ```python # See more in https://clickhouse.com/docs/en/interfaces/formats chdb.query('select * from file("data.parquet", Parquet)', 'Dataframe') ```

๐Ÿ—‚๏ธ Query On Table

(Pandas DataFrame, Parquet file/bytes, Arrow bytes)
### Query On Pandas DataFrame ```python import chdb.dataframe as cdf import pandas as pd # Join 2 DataFrames df1 = pd.DataFrame({'a': [1, 2, 3], 'b': ["one", "two", "three"]}) df2 = pd.DataFrame({'c': [1, 2, 3], 'd': ["โ‘ ", "โ‘ก", "โ‘ข"]}) ret_tbl = cdf.query(sql="select * from __tbl1__ t1 join __tbl2__ t2 on t1.a = t2.c", tbl1=df1, tbl2=df2) print(ret_tbl) # Query on the DataFrame Table print(ret_tbl.query('select b, sum(a) from __table__ group by b')) ```

๐Ÿ—‚๏ธ Query with Stateful Session

```python from chdb import session as chs ## Create DB, Table, View in temp session, auto cleanup when session is deleted. sess = chs.Session() sess.query("CREATE DATABASE IF NOT EXISTS db_xxx ENGINE = Atomic") sess.query("CREATE TABLE IF NOT EXISTS db_xxx.log_table_xxx (x String, y Int) ENGINE = Log;") sess.query("INSERT INTO db_xxx.log_table_xxx VALUES ('a', 1), ('b', 3), ('c', 2), ('d', 5);") sess.query( "CREATE VIEW db_xxx.view_xxx AS SELECT * FROM db_xxx.log_table_xxx LIMIT 4;" ) print("Select from view:\n") print(sess.query("SELECT * FROM db_xxx.view_xxx", "Pretty")) ``` see also: [test_stateful.py](tests/test_stateful.py).

๐Ÿ—‚๏ธ Query with Python DB-API 2.0

```python import chdb.dbapi as dbapi print("chdb driver version: {0}".format(dbapi.get_client_info())) conn1 = dbapi.connect() cur1 = conn1.cursor() cur1.execute('select version()') print("description: ", cur1.description) print("data: ", cur1.fetchone()) cur1.close() conn1.close() ```

๐Ÿ—‚๏ธ Query with UDF (User Defined Functions)

```python from chdb.udf import chdb_udf from chdb import query @chdb_udf() def sum_udf(lhs, rhs): return int(lhs) + int(rhs) print(query("select sum_udf(12,22)")) ``` Some notes on chDB Python UDF(User Defined Function) decorator. 1. The function should be stateless. So, only UDFs are supported, not UDAFs(User Defined Aggregation Function). 2. Default return type is String. If you want to change the return type, you can pass in the return type as an argument. The return type should be one of the following: https://clickhouse.com/docs/en/sql-reference/data-types 3. The function should take in arguments of type String. As the input is TabSeparated, all arguments are strings. 4. The function will be called for each line of input. Something like this: ``` def sum_udf(lhs, rhs): return int(lhs) + int(rhs) for line in sys.stdin: args = line.strip().split('\t') lhs = args[0] rhs = args[1] print(sum_udf(lhs, rhs)) sys.stdout.flush() ``` 5. The function should be pure python function. You SHOULD import all python modules used IN THE FUNCTION. ``` def func_use_json(arg): import json ... ``` 6. Python interpertor used is the same as the one used to run the script. Get from `sys.executable` see also: [test_udf.py](tests/test_udf.py).

๐Ÿ—‚๏ธ Python Table Engine

### Query on Pandas DataFrame ```python import chdb import pandas as pd df = pd.DataFrame( { "a": [1, 2, 3, 4, 5, 6], "b": ["tom", "jerry", "auxten", "tom", "jerry", "auxten"], } ) chdb.query("SELECT b, sum(a) FROM Python(df) GROUP BY b ORDER BY b").show() ``` ### Query on Arrow Table ```python import chdb import pyarrow as pa arrow_table = pa.table( { "a": [1, 2, 3, 4, 5, 6], "b": ["tom", "jerry", "auxten", "tom", "jerry", "auxten"], } ) chdb.query( "SELECT b, sum(a) FROM Python(arrow_table) GROUP BY b ORDER BY b", "debug" ).show() ``` ### Query on chdb.PyReader class instance 1. You must inherit from chdb.PyReader class and implement the `read` method. 2. The `read` method should: 1. return a list of lists, the first demension is the column, the second dimension is the row, the columns order should be the same as the first arg `col_names` of `read`. 1. return an empty list when there is no more data to read. 1. be stateful, the cursor should be updated in the `read` method. 3. An optional `get_schema` method can be implemented to return the schema of the table. The prototype is `def get_schema(self) -> List[Tuple[str, str]]:`, the return value is a list of tuples, each tuple contains the column name and the column type. The column type should be one of the following: https://clickhouse.com/docs/en/sql-reference/data-types ```python import chdb class myReader(chdb.PyReader): def __init__(self, data): self.data = data self.cursor = 0 super().__init__(data) def read(self, col_names, count): print("Python func read", col_names, count, self.cursor) if self.cursor >= len(self.data["a"]): return [] block = [self.data[col] for col in col_names] self.cursor += len(block[0]) return block reader = myReader( { "a": [1, 2, 3, 4, 5, 6], "b": ["tom", "jerry", "auxten", "tom", "jerry", "auxten"], } ) chdb.query( "SELECT b, sum(a) FROM Python(reader) GROUP BY b ORDER BY b" ).show() ``` see also: [test_query_py.py](tests/test_query_py.py). ### Limitations 1. Column types supported: pandas.Series, pyarrow.array, chdb.PyReader 1. Data types supported: Int, UInt, Float, String, Date, DateTime, Decimal 1. Python Object type will be converted to String 1. Pandas DataFrame performance is all of the best, Arrow Table is better than PyReader

For more examples, see examples and tests.


Demos and Examples

Benchmark

Documentation

Events

Contributing

Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are greatly appreciated. There are something you can help:

Bindings

We welcome bindings for other languages, please refer to bindings for more details.

License

Apache 2.0, see LICENSE for more information.

Acknowledgments

chDB is mainly based on ClickHouse [^1] for trade mark and other reasons, I named it chDB.

Contact


[^1]: ClickHouseยฎ is a trademark of ClickHouse Inc. All trademarks, service marks, and logos mentioned or depicted are the property of their respective owners. The use of any third-party trademarks, brand names, product names, and company names does not imply endorsement, affiliation, or association with the respective owners.