lab6
.pdf
САНКТ-ПЕТЕРБУРГСКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ АЭРОКОСМИЧЕСКОГО ПРИБОРОСТРОЕНИЯ
КАФЕДРА ПРИКЛАДНОЙ ИНФОРМАТИКИ
ОТЧЕТ ЗАЩИЩЕН С ОЦЕНКОЙ
ПРЕПОДАВАТЕЛЬ
Канд. техн. наук |
|
Турнецкая Е. Л. |
должность, уч. степень, звание |
подпись, дата |
инициалы, фамилия |
ОТЧЕТ О ЛАБОРАТОРНОЙ РАБОТЕ №6
Взаимодействие с ClickHouse с помощью Python
по курсу: Программная инженерия
РАБОТУ ВЫПОЛНИЛ
СТУДЕНТ гр. № |
4111з |
|
Тюттерин Я. Н. |
||
|
|
|
|
|
|
|
|
|
подпись, дата |
|
инициалы, фамилия |
Санкт-Петербург 2026
Цель работы: получение практических навыков взаимодействия с ClickHouse с помощью
Python
Выполнение:
Подключение к ClickHouse с помощью Python осуществляется через библиотеку clickhouse-connect, которая является официальным драйвером для взаимодействия с
ClickHouse. На рисунке 1 c помощью pip install clickhouse-connect успешно установлен драйвер для подключения к ClickHouse.
Вариант 10. Автосалон
Существует фирма, торгующая автомобилями. Автомобиль выступает в качестве товара, и, как товар имеет определенные характеристики: код товара, страна-изготовитель,
марка автомобиля, модель, наличие на складе (да, нет, когда будет), цена. Кроме того, на каждый автомобиль имеются технические данные: фирма-производитель, тип кузова,
количество дверей, количество мест, тип двигателя, расположение двигателя, рабочий объем двигателя, мощность двигателя, наличие опций, количество ведущих колес, расход топлива,
время разгона до 100км\ч. Фирма имеет своих клиентов — покупателей автомобилей,
сведения о которых хранят в течение определенного времени. Информация о клиенте: код клиента, паспортные данные (серия, номер), домашний адрес, номер телефона. В заказе указывается информация об автомобиле, клиенте, продавце, способе оплаты, дате продажи.
Информация о продавце-консультанте: паспортные данные, номер телефона, заработная плата.
Листинг 1. Код на Python с программой для взаимодействия с БД ClickHouse
import os
import clickhouse_connect import pandas as pd
from dotenv import load_dotenv
# Загрузка переменных окружения load_dotenv()
#Получение учетных данных Neo4j из переменных окружения
CLICK_HOUSE_URI = os.getenv("CLICK_HOUSE_URI") CLICK_HOUSE_PORT = os.getenv("CLICK_HOUSE_PORT") CLICK_HOUSE_USERNAME = os.getenv("CLICK_HOUSE_USERNAME") CLICK_HOUSE_PASSWORD = os.getenv("CLICK_HOUSE_PASSWORD")
#Функция для очистки базы данных
def clear_db(client):
try:
# Получаем список таблиц в базе данных tables_query = f"SHOW TABLES FROM sales"
tables = client.query(tables_query).result_rows
# Итерируемся по списку таблиц и удаляем их
for table in tables:
table_name = table[0] # Предполагаем, что имя таблицы - первый элемент
drop_table_query = f"DROP TABLE sales.{table_name}" try:
client.command(drop_table_query)
print(f"Таблица sales.{table_name} успешно удалена.")
except Exception as e:
print(f"Ошибка при удалении таблицы sales.{table_name}:
{e}")
print(f"Все таблицы в базе данных sales удалены (или предпринята попытка удаления).")
except Exception as e:
print(f"Ошибка при получении списка таблиц или подключении к
ClickHouse: {e}")
# Функция для подключения в базе данных
def connect_to_db(host_name, port_number, user_name, password): client = clickhouse_connect.get_client(host=host_name,
port=port_number, username=user_name, password=password)
return client
def create_database(client): try:
client.query("""
CREATE DATABASE IF NOT EXISTS sales;
""")
client.query("""
CREATE TABLE sales.cars ( product_code String, country_of_origin String, brand String,
model String, stock_status String, price Float64, manufacturer String, body_type String, door_count Int32, seat_count Int32, engine_type String, engine_position String,
engine_displacement Float64, engine_power Int32,
options String, driven_wheels Int32, fuel_consumption Float64, acceleration_0_100 Float64
) ENGINE = MergeTree() ORDER BY product_code;
""")
client.query("""
INSERT INTO sales.cars VALUES
('P001', 'Germany', 'Audi', 'A4', 'In stock', 35000, 'Volkswagen Group', 'Sedan', 4, 5, 'Petrol', 'Front', 2.0, 150, 'ABS,Airbags', 4, 6.5, 8.5),
('P002', 'Japan', 'Toyota', 'Camry', 'Expected', 24000, 'Toyota Motor Corporation', 'Sedan', 4, 5, 'Hybrid', 'Front', 2.5, 200, 'ABS,Airbags,Navigation', 4, 4.8, 7.0),
('P003', 'USA', 'Ford', 'Mustang', 'In stock', 27000, 'Ford Motor Company', 'Coupe', 2, 4, 'Petrol', 'Rear', 5.0, 450, 'Leather,Navigation', 4, 8.0, 5.5),
('P004', 'Germany', 'BMW', 'X3', 'No', 41000, 'BMW AG', 'SUV', 4, 5, 'Diesel', 'Front', 3.0, 250, 'Sunroof,Leather', 4, 7.2, 6.4),
('P005', 'South Korea', 'Kia', 'Sorento', 'In stock', 29000, 'Hyundai', 'SUV', 4, 5, 'Petrol', 'Front', 2.2, 180, 'Airbags,Rearview Camera', 4, 8.0, 9.0),
('P006', 'France', 'Peugeot', '308', 'Expected', 20000, 'PSA Peugeot Citroën', 'Hatchback', 5, 5, 'Petrol', 'Front', 1.6, 120, 'Airbags', 4, 5.8, 10.0),
('P007', 'Japan', 'Honda', 'Civic', 'In stock', 22000, 'Honda Motor Co.', 'Sedan', 4, 5, 'Petrol', 'Front', 1.8, 140, 'Airbags,Navigation', 4, 6.0, 8.8),
('P008', 'Germany', 'Mercedes-Benz', 'C-Class', 'In stock', 42000, 'Daimler AG', 'Sedan', 4, 5, 'Diesel', 'Front', 2.0, 190, 'Leather,Sunroof', 4, 6.7, 7.5),
('P009', 'Italy', 'Fiat', '500', 'No', 15000, 'Fiat Chrysler', 'Hatchback', 3, 4, 'Petrol', 'Front', 1.2, 85, 'Airbags', 4, 5.0, 12.0),
('P010', 'USA', 'Chevrolet', 'Malibu', 'Expected', 23000, 'General Motors', 'Sedan', 4, 5, 'Petrol', 'Front', 1.8, 140, 'Airbags,Navigation', 4, 6.3, 8.9);
""")
client.query("""
CREATE TABLE sales.clients ( client_code String, passport_series String, passport_number String, address String,
phone String)
ENGINE = MergeTree() ORDER BY client_code;
""")
client.query("""
INSERT INTO sales.clients VALUES
('C001', 'Иванов Иван Иванович', '1234567890', 'ivanov@example.com', 'Москва, ул. Ленина, д.1'),
('C002', 'Петров Петр Петрович', '0987654321', 'petrov@example.com', 'Санкт-Петербург, наб. реки Мойки, д.5'),
('C003', 'Сидорова Мария Ивановна', '5551234567', 'sidorova@example.com', 'Новосибирск, ул. Октябрьская, д.10'),
('C004', 'Кузнецов Алексей Викторович', '4449876543', 'kuznecov@example.com', 'Екатеринбург, ул. Карла Маркса, д.3'),
('C005', 'Лебедева Ольга Сергеевна', '3334567890', 'lebedeva@example.com', 'Казань, ул. Баумана, д.12'),
('C006', 'Морозов Дмитрий Алексеевич', '2229876543', 'morozov@example.com', 'Ростов-на-Дону, пр. Чехова, д.8'),
('C007', 'Федорова Елена Ивановна', '1116549870', 'fedorova@example.com', 'Самара, ул. Гагарина, д.7'),
('C008', 'Николаев Владимир Петрович', '6661234567',
'nikolaev@example.com', 'Уфа, ул. Ленина, д.15'),
('C009', 'Григорьева Анастасия Викторовна',
'7776543210', 'grigorieva@example.com', 'Краснодар, ул. Красная, д.20'), ('C010', 'Баранов Михаил Сергеевич', '8889876543',
'baranov@example.com', 'Воронеж, ул. Советская, д.25');
""")
client.query("""
CREATE TABLE sales.sales ( sale_id String, product_code String, client_code String, seller_id String, payment_method String,
sale_date Date) ENGINE = MergeTree() ORDER BY sale_id;
""")
client.query("""
INSERT INTO sales.sales (sale_id, product_code, client_code, seller_id, payment_method, sale_date) VALUES
('S001', 'P001', 'C001', 'SP001', 'Credit Card',
'2023-07-15'),
('S002', 'P002', 'C002', 'SP002', 'Cash', '2023-07-16'), ('S003', 'P003', 'C003', 'SP003', 'Bank Transfer',
'2023-07-17'),
('S004', 'P004', 'C004', 'SP004', 'Credit Card',
'2023-07-18'),
('S005', 'P005', 'C005', 'SP005', 'Cash', '2023-07-19'), ('S006', 'P006', 'C006', 'SP006', 'Bank Transfer',
'2023-07-20'),
('S007', 'P007', 'C007', 'SP007', 'Credit Card',
'2023-07-21'),
('S008', 'P008', 'C008', 'SP008', 'Cash', '2023-07-22'), ('S009', 'P009', 'C009', 'SP009', 'Bank Transfer',
'2023-07-23'),
('S010', 'P010', 'C010', 'SP010', 'Credit Card',
'2023-07-24');
""")
client.query("""
CREATE TABLE sales.salespersons ( seller_id String, passport_series String, passport_number String, phone String,
salary Float64) ENGINE = MergeTree() ORDER BY
seller_id;
""")
client.query("""
INSERT INTO sales.salespersons VALUES
('SP001', '77', '123456', '111-222-33-44', 50000.0), ('SP002', '78', '654321', '222-333-44-55', 55000.0), ('SP003', '79', '789012', '333-444-55-66', 52000.0), ('SP004', '80', '210987', '444-555-66-77', 48000.0), ('SP005', '81', '345678', '555-666-77-88', 51000.0), ('SP006', '82', '987654', '666-777-88-99', 53000.0), ('SP007', '83', '456789', '777-888-99-00', 49000.0), ('SP008', '84', '654987', '888-999-00-11', 56000.0), ('SP009', '85', '123789', '999-000-11-22', 47000.0), ('SP010', '86', '987321', '000-111-22-33', 52000.0);
""")
print("Все таблицы были успешно созданы и заполнены.")
except Exception as e: print(f"Возникла ошибка: {e}")
#Выбрать все автомобили из Германии def func1(client):
query = """
SELECT brand, model FROM sales.cars WHERE country_of_origin = 'Germany'
"""
cars = client.query(query).result_rows
print("\nВсе авто из Германии:\n", pd.DataFrame(cars, columns=['brand', 'model']))
#Найти автомобили с ценой выше 30,000 и в наличии
def func2(client): query = """
SELECT brand, model, price FROM sales.cars WHERE price > 30000 AND stock_status = 'In stock'
"""
cars = client.query(query).result_rows
print("\nВсе автомобили с ценой выше 30,000 и в наличии:\n", pd.DataFrame(cars, columns=['brand', 'model', 'price']))
# Количество автомобилей каждого производителя def func3(client):
query = """
SELECT manufacturer, COUNT(*) AS total_models FROM sales.cars
GROUP BY manufacturer
"""
cars = client.query(query).result_rows
print("\nКоличество автомобилей каждого производителя:\n", pd.DataFrame(cars, columns=['manufacturer', 'total_models']))
# Выбрать модели с двигателем более 2.0 и расходом топлива менее 7.0 def func4(client):
query = """
SELECT brand, model, engine_displacement, fuel_consumption FROM sales.cars
WHERE engine_displacement > 2.0 AND fuel_consumption < 7.0
"""
cars = client.query(query).result_rows
print("\nВыбрать модели с двигателем более 2.0 и расходом топлива менее 7.0:\n",
pd.DataFrame(cars, columns=['brand', 'model', 'engine_displacement', 'fuel_consumption']))
# Найти все продажи с датой после 2023-07-17, включая информацию о продавце и клиенте
def func5(client): query = """
SELECT s.sale_id, s.sale_date, c.passport_series AS client_name, sp.salary
FROM sales.sales s
JOIN clients c ON s.client_code = c.client_code JOIN salespersons sp ON s.seller_id = sp.seller_id WHERE s.sale_date > '2023-07-17'
"""
cars = client.query(query).result_rows
print("\nНайти все продажи с датой после 2023-07-17, включая информацию о продавце и клиенте:\n",
pd.DataFrame(cars, columns=['s.sale_id', 's.sale_date', 'client_name', 'sp.salary']))
# Подсчитать количество продаж по каждому продавцу def func6(client):
query = """
SELECT sp.seller_id, COUNT(*) AS total_sales FROM sales.sales s
JOIN salespersons sp ON s.seller_id = sp.seller_id GROUP BY sp.seller_id
"""
cars = client.query(query).result_rows
print("\nПодсчитать количество продаж по каждому продавцу:\n", pd.DataFrame(cars, columns=['sp.seller_id', 'total_sales']))
# Найти автомобили, у которых опции содержат "Leather" или "Sunroof", и цена менее 40,000
def func7(client): query = """
SELECT product_code, brand, model, options, price FROM sales.cars
WHERE (options LIKE '%Leather%' OR options LIKE '%Sunroof%') AND price < 40000
"""
cars = client.query(query).result_rows
print("\nНайти автомобили, у которых опции содержат Leather или
Sunroof, и цена менее 40,000:\n",
pd.DataFrame(cars, columns=['product_code', 'brand', 'model', 'options', 'price']))
def main():
client = connect_to_db(CLICK_HOUSE_URI, CLICK_HOUSE_PORT, CLICK_HOUSE_USERNAME, CLICK_HOUSE_PASSWORD)
clear_db(client) create_database(client) func1(client) func2(client) func3(client) func4(client) func6(client) func7(client)
if __name__ == "__main__": main()
Результаты выполнения кода из листинга 1 представлены на рисунках 1-3.
Рисунок 1 - Результат выполнения очистки и заполнения таблиц
Рисунок 2 - Результат выполнения первой части запросов
Рисунок 3 - Результат выполнения второй части запросов
Вывод
В ходе выполнения лабораторной работы были получены практические навыки взаимодействия с ClickHouse посредством Python. Освоено подключение к базе данных с использованием официального драйвера clickhouse-connect, создано необходимое окружение для дальнейшей работы с системой.
При выполнении заданий была разработана структура базы данных для автосалона,
состоящая из четырех взаимосвязанных таблиц: автомобилей, клиентов, продавцов и сделок.
Осуществлена загрузка данных в созданные таблицы и разработан ряд запросов разной степени сложности, демонстрирующих возможности ClickHouse по обработке и анализу данных.
Знания, полученные в рамках лабораторной работы, обеспечивают понимание принципов работы с системами управления данными, формирование запросов для извлечения необходимой информации, группировку и фильтрацию данных. Это создает основу для эффективного применения инструмента в профессиональной деятельности.
•
