aioch

repository·master·Indexed 41 days ago

https://github.com/mymarilyn/aioch

An asynchronous wrapper for the ClickHouse native interface that provides asyncio support for features found in the clickhouse-driver library. It includes support for standard query execution via Client.execute(), streaming large result sets with execute_iter(), and monitoring query progress using execute_with_progress().

Tokens
2.1K
Snippets
10
Records
11
Agent score
1%

What's inside aioch

  1. Install aioch via pip or source

    master

    You can install aioch using pip for a standard installation, or by cloning the repository and running the setup script for development/source installation.

    # Via pip
    pip install aioch
    
    # From source
    git clone https://github.com/mymarilyn/aioch
    cd aioch
    python setup.py install
  2. Execute queries with progress tracking

    master

    Use Client.execute_with_progress(query) to run a query while monitoring its progress. This method returns an asynchronous iterator that yields (num_rows, total_rows).

    To retrieve the actual result of the query after the iterator is exhausted, call await progress.get_result() within an else block of the async for loop to ensure the query completed successfully.

    from aioch import Client
    import asyncio
    
    async def exec_progress():
        client = Client('localhost')
        # Returns an async iterator yielding (num_rows, total_rows)
        progress = await client.execute_with_progress('SELECT * FROM my_table')
    
        async for num_rows, total_rows in progress:
            print(f"Progress: {num_rows}/{total_rows}")
        else:
            # Retrieve the result after completion
            rv = await progress.get_result()
            print(rv)
    
    asyncio.run(exec_progress())
  3. Cancel a running query

    master

    If a query is taking too long or meeting specific criteria (e.g., not reaching a certain percentage of completion within a timeout), you can stop the execution on the server by calling await client.cancel().

    from datetime import datetime
    import asyncio
    from aioch import Client
    
    async def exec_with_timeout_logic():
        client = Client('localhost')
        progress = await client.execute_with_progress('LONG AND COMPLICATED QUERY')
        timeout = 20
        started_at = datetime.now()
    
        async for num_rows, total_rows in progress:
            done = num_rows / total_rows if total_rows else 0
            now = datetime.now()
            
            # Cancel query if it takes more than 20 seconds to process 50% of rows.
            if (now - started_at).total_seconds() > timeout and done < 0.5:
                await client.cancel()
                break
        else:
            rv = await progress.get_result()
            print(rv)
    
    asyncio.run(exec_with_timeout_logic())
  4. Execute standard queries

    master

    For standard asynchronous query execution without progress monitoring, use Client.execute(query). This method wraps the underlying clickhouse-driver functionality.

    from aioch import Client
    import asyncio
    
    async def exec_no_progress():
        client = Client('localhost')
        rv = await client.execute('SELECT * FROM my_table')
        print(rv)
    
    asyncio.run(exec_no_progress())
  5. Configure the aioch Client

    master

    The Client constructor accepts the following parameters:

    • executor: An instance of a custom Executor. If not supplied, a default executor is used.
    • loop: An asyncio compatible event loop.

    Additionally, any parameters accepted by the underlying clickhouse-driver's Client can be passed to the aioch.Client constructor.

  6. Execute a query with iteration

    master

    Use execute_iter to execute a query and receive an IterQueryResult. This is useful for streaming large result sets row-by-row without loading everything into memory at once.

    Parameters:

    • query: The SQL query string.
    • params: Dictionary of parameters.
    • with_column_types: Boolean, if True, includes column types.
    • external_tables: Data for external tables.
    • query_id: Unique identifier for the query.
    • settings: ClickHouse query settings.
    • types_check: Boolean for type checking.
    async def stream_query(client):
        async for row in await client.execute_iter('SELECT * FROM large_table'):
            print(row)
  7. Execute a query with progress tracking

    master

    Use execute_with_progress to run a query and receive a ProgressQueryResult. This allows you to monitor the progress of the query execution.

    Parameters:

    • query: The SQL query string.
    • params: Dictionary of parameters for substitution.
    • with_column_types: Boolean, if True, includes column types in the result.
    • external_tables: Data for external tables.
    • query_id: Unique identifier for the query.
    • settings: ClickHouse query settings.
    • types_check: Boolean for type checking.
    • columnar: Boolean to return results in columnar format.
    async def run_query(client):
        result = await client.execute_with_progress(
            'SELECT * FROM my_table WHERE id = %(id)s',
            params={'id': 123},
            with_column_types=True
        )
        # result is a ProgressQueryResult
        async for row in result:
            print(row)
  8. Initialize the aioch Client

    master

    The Client class provides an asynchronous interface for ClickHouse queries. You can initialize it in two ways:

    1. Using from_url: The recommended way to connect via a connection string.
    2. Passing an existing _client: If you already have a clickhouse_driver.Client instance, you can wrap it.

    You can optionally provide an event_loop or an executor to manage how blocking calls are run in the background.

    from aioch import Client
    
    # Recommended: Connect via URL
    client = Client.from_url('clickhouse://user:password@host:port/database')
    
    # Optional: Provide custom loop or executor
    client = Client.from_url('clickhouse://...', loop=my_loop, executor=my_executor)
  9. Cancel a running query

    master

    You can cancel a query currently being processed by calling cancel().

    Note: After sending the cancel signal, the client must still read until the END_OF_STREAM packet is received to ensure the connection is left in a clean state. The method returns the result of the remaining stream (optionally with column types).

    # To cancel a query
    await client.cancel(with_column_types=True)