1 Востаннє редагувалося frz (24.05.2023 22:04:11)

Тема: Flask - мапінґ даних

В якості "думок вголос", бо ґпт мене не забанив, але щоб в нього щось запитати, потрібно спочатку самому собі сформулювати думку.

Отже, є Flask апка, "версія 0" якої вже успішно зберігає потрібні дані на сервері в csv.

Є вже декілька готових Python функцій, які приймають ім'я csv файлу і надсилають дані в зовнішнє REST API. Кожна функція призначена для конкретного набору даних, наприклад fnABC надсилає тип даних dataABC у відповідний ендпоїнт REST API epABC.

Так як я на даному етапі і розробник, і користувач в одній морді лиця, то дані в csv (набір колонок, їхні назви) чітко відповідають тому що потрібно для саме цього API ендпоїнту, наприклад файл ABC.csv містить колонки з назвами ABC1, ABC2, ABC3 - точно так як очікується в цьому ендпоїнті

    data = {
        "ABC1": abc1value,
        "ABC2": abc2value,
        "ABC3": abc3value
    }

Проте користувач без руля що саме очікується в ендпоїнті, отже його набір даних може бути цілком будь-яким. При цьому Flask апка має підказувати користувачеві, які назви колонок очікуються, і пропонувати зробити мапінґ.

Наприклад, користувач надіслав щось таке:

SDLFHJKDSF,SALDF,ABC2,ALSJG
1,6,4,5
2,9,3,5

З цих даних ABC2 мапиться "само", але потребує підтвердження від користувача, а ще дві колонки з решти трьох треба аби користувач вказав, хто з них хто.

Хаотичні думки, але треба з чогось починати.

запитав, але цей робот потребує дуже детальних запитів, тому поки що не дуже допоміг:

ґпт4 написав:
from flask import Flask, render_template, request
import pandas as pd
import csv
import json

app = Flask(__name__)

@app.route('/upload', methods=['POST'])
def upload_file():
    file = request.files['file']
    df = pd.read_csv(file)
    columns = df.columns.tolist()

    # Тут ви можете зберегти або передати колонки в інший view аби користувач міг вибрати їх.
    # Перетворимо список колонок у json для зручності передачі
    columns_json = json.dumps(columns)

    # Редірект на сторінку мапінгу з передачею назв колонок
    return redirect(url_for('map_columns', columns=columns_json))

@app.route('/map', methods=['GET', 'POST'])
def map_columns():
    if request.method == 'POST':
        # Код для обробки мапінгу від користувача

    else:
        # Відображення форми для користувача
        columns = json.loads(request.args.get('columns'))
        return render_template('map_columns.html', columns=columns)

2

Re: Flask - мапінґ даних

З мапінґом розібрався, ну ще валідація буде потрібна, але згрубша вже ок.

Далі вже трохи з іншим трахаюся, але все ще в рамках Flask аплікації. Сьогодні можна сказати що втратив пів дня. Є функції Python, які мені треба запускати як з самої апки, так і з консолі (в перспективі з crontab). І воно тут мені вимахується. Каже при спробі виклику функції з консолі що не може імпортувати app, бо я не з того місця викликаю. В результаті заліз в хащі, бо почав розділяти функціонал на чисто Flask і чисто не-Flask, потім зрозумів що йду не туди і відновився з вчорашнього коміту.

Отже, дві проблеми:
1) як зробити функцію аби вона мешкала в app.py Flask апки, але щоб її можна було запускати також з лінукс-консолі на тому ж сервері (щоб у перспективі додати в crontab)
2) припустимо, я завершив те що почав і розділив функціонал Flask / неFlask, як тоді використовувати ту ж db модель (ORM) для читання-запису даних по суті двома апками - це ще одна головоломка.

Підозрюю, що доведеться писати просто API ендпоїнти на Flask без html темплейтів, і тоді до них звертатися з консолі через curl / wget. Це мабуть буде "середній варіант", до того ж доволі сучасний з точки зору технологій. Я сьогодні вже з тими обхідними варіантами сиджу безвилазно 14 годин, ну його в пень.

3

Re: Flask - мапінґ даних

доведеться писати просто API ендпоїнти на Flask без html темплейтів, і тоді до них звертатися з консолі через curl / wget

так і пішло

стільки нюансів зразу вилізло - в html темплейті можна всякі констрейнти в формах робити, наприклад без вибору цього дроп-дауну не буде доступна ця кнопка

в API ендпоїнті на кожну недолугу дію користувача повинна бути перевірка із достатньою (навіть десь надлишковою) перевіркою і інформуванням через json output, а в логах для розробника повинно бути ще більше інформації аби потім мати можливість отримати вичерпну відповідь що саме було не так як очікувалося

4

Re: Flask - мапінґ даних

Головоломка з надсиланням даних в зовнішній REST API в батчах. По одному запису у випадку з кількістю близько мільйона запитів процес може займати навіть цілий день, що не варіант. Все разом в батчі не хоче. Чіткої документації скільки влізе в батч нема. При цьому запит падає з невизначеною помилкою 500 Internal Server Error без подальшого пояснення. Виходить що треба підбирати кількість записів для батчу на ходу, у випадку помилки - зменшувати розмір батчу.

import pandas as pd
import json

data = {
    'Name': ['John', 'Emma', 'Ryan', 'Sophia'],
    'Age': [25, 28, 30, 22],
    'City': ['New York', 'London', 'Paris', 'Sydney']
}

df = pd.DataFrame(data)
batch_size = 2
batches = [df[i:i+batch_size] for i in range(0, len(df), batch_size)]
for piece in batches:
    print(piece)
    print("###")
    json_for_piece = piece.to_json(orient="records")
    json_for_batch_loads = json.loads(json_for_batch)
    print(type(json_for_batch_loads))
    print(json_for_batch_loads)
    print("==============================")

5

Re: Flask - мапінґ даних

Дебаґ помилки на віддаленому сервері REST API

500 Internal Server Error

при надсиланні даних в батчах без доступу до внутрішніх логів віддаленого сервера - це особливий витончений вид мазохізму.

6

Re: Flask - мапінґ даних

Віддебажив елементарні запити з батчами - воно явно негаразд на стороні REST API сервера, до логів проду якого на даний момент нема доступу. Є доступ до ґіт репозиторію, тож надалі буде можливість розгорнути середовище в локальній пісочниці і зрозуміти поведінку.

Наразі ж доведеться освоїти multithreading аби без функціоналу батчів надсилати окремі запити, але в декілька потоків.

7

Re: Flask - мапінґ даних

Оскільки в мене частини завдання складаються з шматків того ж pandas dataframe, то важких I/O операцій там не передбачається, тому дивлюся в бік concurrent.futures

8

Re: Flask - мапінґ даних

Якогось хріна в API створюється більше записів ніж було надіслано батчами. Головоломка.

9

Re: Flask - мапінґ даних

Постало питання як зробити асинхронні виклики.

Є функція Python, яка в свою чергу загорнена в ендпоїнт Flask. Коли кнопкою на формі викликати функцію, то сторінка починає відображатися наче "завантажується" - в заголовку закладки крутиться коло або бігає туди-сюди повзунок (в залежності від кількості даних, процес може тривати навіть годинами). Оскільки сказано було не світити аплікацію назовні, то конект йде через ssh тунель. І ось коли я переводжу ноут в режим сну, то відповідно рветься ssh тунель і після пробудження форма не відображає поточний стан.

В логах БД все відображається, але це не юзер-френдлі. Тому думаю в бік асинхронних викликів. Поки що лише знайшов напрямок і ще не в курсі як рухатися далі.

10

Re: Flask - мапінґ даних

Вибив в CEO ресурси в хмарі Azure під проект.

Знайшов недолік: в клієнтських даних є записи із шістнадцятьма знаками після коми, однак API приймає лише 10 знаків після коми. Відповідно хоч у клієнтських даних це унікальні записи, однак після відсікання зайвих знаків після коми створюються дублі, з яких API приймає лише перший екземпляр. Думаю над рішенням. Є одна колонка, яку [поки що] клієнти не використовують в реальних даних, її можна пристосувати для генерування сіквенсу в межах дублів (після відсікання зайвих знаків після коми).

11

Re: Flask - мапінґ даних

frz написав:

Вибив в CEO ресурси в хмарі Azure під проект.

Знайшов недолік: в клієнтських даних є записи із шістнадцятьма знаками після коми, однак API приймає лише 10 знаків після коми. Відповідно хоч у клієнтських даних це унікальні записи, однак після відсікання зайвих знаків після коми створюються дублі, з яких API приймає лише перший екземпляр. Думаю над рішенням. Є одна колонка, яку [поки що] клієнти не використовують в реальних даних, її можна пристосувати для генерування сіквенсу в межах дублів (після відсікання зайвих знаків після коми).

Дата сцаєнтист сказав що йому достатньо 3 знаки після коми

def truncate_after_dot(value):
    parts = str(value).split('.')
    if len(parts) == 2 and len(parts[1]) > 3:
        return float('.'.join([parts[0], parts[1][:3]]))
    return value

columns_to_process = ['col1','col2','col3','col4']
csv_data[columns_to_process] = csv_data[columns_to_process].applymap(truncate_after_dot)

12

Re: Flask - мапінґ даних

Тепер думаю, як з найменшими зусиллями зробити регулярний виклик ендпоїнту Flask. Наче крон - стандартне рішення, однак не все так просто, спершу треба придумати як саме авторизуватися в апці наприклад за допомогою bash.

Чати радять різні RabbitMQ, по моєму це overkill.

13 Востаннє редагувалося frz (30.09.2023 00:28:36)

Re: Flask - мапінґ даних

Прислали баґ на бекенді на виправлення. Апішка повертає 500 Internal Server Error, через що в головній апці замість красивої картинки дуля з маком. На колі з СТО прийшли до висновку, що коли забагато даних, то не вистачає пам'яті і тоді вилітає ексепшн, це підтверджується тим що цей клієнт на якому вилітає помилка дійсно має дуже багато записів транзакцій.

Ну коли API має за один раз повернути мішок даних і не справляється, тоді зазвичай застосовують pagination, я це багато разів використовував в якості того хто витягує дані з API за допомогою запиту GET, по ідеї маю розуміння як це в теорії застосувати на самому сервері.

Але! Сама клієнтська аплікація яка витягує дані і малює гарні картинки - гімно мамонта, розробник якого давно відсутній на проекті, апка не білдиться через відсутні залежності на серверах звідки вони мають скачуватися. Я ще коли прийшов на проект, то казав що закопайте врешті стюардесу її треба рефакторити а це кропіткий і тривалий процес.

Тобто коли в теорії я пофікшу pagination на сервері для видачі даних, тоді на клієнті треба буде застосувати цю ж pagination для зчитування цих же даних. А це в даному сценарії без шансів.

Бажана дата фіксу - до кінця наступного тижня, що нереально. Не пишу про це CEO, бо не хочу йому псувати вихідних. Напишу в понеділок.

От хіба що вдасться суттєво додати пам'яті на сервері API, тоді по ідеї повинно прожувати велику кількість даних успішно.

Upd: Запропонував CEO визначити який саме це інстанс в хмарі що обслуговує API, і додати там оперативки поки не зникне помилка.

14

Re: Flask - мапінґ даних

Вдалося розгорнути дев середовище API. Воно чомусь не відображає всі потрібні ендпоїнти, хоча я клонував гілку main. Не знаю чому так. Або останні зміни були в іншій гілці а не в main, а може останні зміни не закомічені.

Розібрався поки що з одним ендпоїнтом і лише з GET. Виявляється, під користувача створюється окрема база даних. Ще розберуся з POST і можна буде переходити до решти ендпоїнтів, деякі з яких доведеться створювати на деві самому.

Це крутий прогрес, наскільки я можу сам себе оцінити. Звісно, CEO цього не розуміє і йому треба результат - створений функціонал котрого ще нема на проді. Але поки я не пограюся достатньо аби зрозуміти глибоко як все працює, я не зможу повноцінно щось створити.