<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def insert_fake_data(hosts=None, table=None, num_records=1e5, bulk_size=1000, concurrency=25, mapping_file=None):
 """Generate random data and insert it into a table. This will read the table schema and then find suitable random data providers. Which provider is choosen depends on the column name and data type. Example: A column named `name` will map to the `name` provider. A column named `x` of type int will map to `random_int` because there is no `x` provider. Available providers are listed here: https://faker.readthedocs.io/en/latest/providers.html Additional providers: - auto_inc: Returns unique incrementing numbers. Automatically used for columns named "id" of type int or long - geo_point Returns [<lon>, <lat>] Automatically used for columns of type geo_point Args: hosts: <host>:[<port>] of the Crate node table: The table name into which the data should be inserted. Either fully qualified: `<schema>.<table>` or just `<table>` num_records: Number of records to insert. Usually a number but expressions like `1e4` work as well. bulk_size: The bulk size of the insert statements. concurrency: How many operations to run concurrently. mapping_file: A JSON file that defines a mapping from column name to fake-factory provider. The format is as follows: { "column_name": ["provider_with_args", ["arg1", "arg"]], "x": ["provider_with_args", ["arg1"]], "y": "provider_without_args" } """

    with clients.client(hosts, concurrency=1) as client:
        schema, table_name = parse_table(table)
        columns = retrieve_columns(client, schema, table_name)
    if not columns:
        sys.exit('Could not find columns for table "{}"'.format(table))
    print('Found schema: ')
    print(json.dumps(columns, sort_keys=True, indent=4))
    mapping = None
    if mapping_file:
        mapping = json.load(mapping_file)

    bulk_size = min(num_records, bulk_size)
    num_inserts = int(math.ceil(num_records / bulk_size))

    gen_row = create_row_generator(columns, mapping)

    stmt = to_insert('"{schema}"."{table_name}"'.format(**locals()), columns)[0]
    print('Using insert statement: ')
    print(stmt)

    print('Will make {} requests with a bulk size of {}'.format(
        num_inserts, bulk_size))

    print('Generating fake data and executing inserts')
    q = asyncio.Queue(maxsize=concurrency)
    with clients.client(hosts, concurrency=concurrency) as client:
        active = [True]

        def stop():
            asyncio.ensure_future(q.put(None))
            active.clear()
            loop.remove_signal_handler(signal.SIGINT)
        if sys.platform != 'win32':
            loop.add_signal_handler(signal.SIGINT, stop)
        bulk_seq = _bulk_size_generator(num_records, bulk_size, active)
        with ThreadPoolExecutor() as e:
            tasks = asyncio.gather(
                _gen_data_and_insert(q, e, client, stmt, gen_row, bulk_seq),
                consume(q, total=num_inserts)
            )
            loop.run_until_complete(tasks)