Pull to refresh

Конвертация даных, или углубление в Talent Open Studio

Reading time 4 min
Views 1.2K
Утро было вполне обычным и ленивым: душ, кофе, сигарета… Пора собираться на работу…
По приходе в офис был встречен новостью о переходе на новый проект в качестве ETL инженера (что это значит я не знал, ну да ладно). Ну, думаю попробуем. До меня там работал один парень, но как всегда много помощи о работе я у него не дождался. И так приступим.


Что такое ETL? Вот что на это говорит вики :
ETL (от англ. Extract, Transform, Load – дословно «извлечение, преобразование, загрузка») – один из основных процессов в управлении хранилищами данных, который включает в себя:
  • извлечение данных из внешних источников;
  • их трансформация и очистка (англ. Data cleansing), чтобы они соответствовали нуждам бизнес-модели;
  • и загрузка их в хранилище данных.

С этим думаю более или менее понятно. Суть моей задачи состояла в том чтобы с некоего .xls документа вытащить данные, преобразовывать их по типу (большинство полей определялось как string), кое что посчитать ( в зависимости от конкретного случая) и записать все это дело в БД. После привести к виду star schema, что это такое можно почитать на той же вики.
И так. С задачей разобрались. Для работы использовалась Talent Open Studio, нарыл пример как и что делать. И началась очень долгая и скучная работа копи-пастом.

Вот как выглядит упрощенный пример по преобразования данных и запись в базу выглядит так:
  • Создается проект;
  • В него добавляется источник данных; ( в нашем случае .xml док);
  • Добавляется получатель данных ( таблица в MySQL);
  • Создаем новый Job;
  • В него закидываем источник и получатель, а также компонент среды tMap;
  • В нем прописываем для каждого поля преобразование данных ( к примеру конверт toInt || toFloat, удаляем лишние символы например "%", и так далее;
  • Нажимаем наш Job на выполнение и смотрим что получилось;


так визуально выглядит простой пример Job'а в TOS
TOS Job

Попадались случаи где приходилось писать довольно длинную проверку на валидность данных, их парсинг и тд. После нескольких таких задач и надоедливого копи-пейста созрела идея оптимизации процесса, как оказалась в данной IDE есть возможность писать свои статические паблик классы. Первый класс для преобразования данных был написан за пару минут. И сразу количество марудной работы уменьшилось в разы. Если к примеру каждый раз приходилось копи-пастить:

obj.toString().equals("#") || obj.toString().equals("") || obj==null ? null
Integer.parseInt(StringHandling.EREPLACE(obj.toString().replace(" ", "").substring(0,obj.toString().replace(" ", "").indexOf(".")),"\\xA0", ""))


то дальше все обходилось одной строчкой

routines.Convert.toInteger(obj)

Но как говорится, не все так просто, особенно если приходится с некоторыми данными проводить какие либо операции, а тем более если приходится работать с данными из предыдущего скопа, так как в Talent Open Studio данные передаются строками, а не целым массивом, и получить доступ к предыдущем скопу не так просто, а точнее я так и не нашел способа кроме как использовать компоненты буфера.

Конкретней к делу, есть следующая задача: имеем набор значений со следующими полями: «Year»,«Quarter»,«StartsFromJan1»,«SomeValue1»,«SomeValue2» ,«SomeValue3» поле StartsFromJan1 может принимать значения «Y»(true) or «N»( false).

Если поле «StartsFromJan1» принимает значение «Y»(true), то данную строку необходимо обрабатывать по ряду правил, если «N» то оставить как есть. К примеру обработка может происходить следующим образом: от ячейки в текущей строке отнимается соответственная ячейка предыдущей строки (если Q4 то отнимаем Q3) с учетом того что если в ней значение поля StartsFromJan1 == N то отнимаем и еще минус одну строку, и так пока не дойдем до Q1, если же в отнимаемой строке поле StartsFromJan1 == Y, то на нем и останавливаемся, для наглядности приведу пример данных:
Year Quarter StartsFromJan1 SomeValue SomeValue
2009 Q1 N 3000 4000
2009 Q2 Y 3500 5000
2009 Q3 N 4000 6000
2009 Q4 Y 5000 7000
2009 Q1 N 3500 4400
2009 Q2 Y 3400 5600
2009 Q3 N 4500 6500
2009 Q4 Y 5600 7800

в нашем случае первый остается без изменений, от второго отнимаем первый, третий не трогаем, от четвертого отнимаем 3 и 2



при разработке задачи возникли следующие проблемы
  • Вычисление данных если поле «StartsFromJan1» принимает значение «Y»
  • Отсеивание пустых строк
  • Максимально уменьшить количество ручной работы


Для решения первой проблемы на выручку пришли те же статические классы. Я использовал 3 одномерных массива (три, потому что строка в которой Quarter == Q1 имеет всегда значение «N» для поля «StartsFromJan1»), создана некая переменная типа Int, которая после каждой обработанной ячейки увеличивалась на единицу, а после обработки последней ячейки в строке и переходе к следующей обнулялась. Далее был создан метод, который конвертировал входящие данные и записывал их в массив, он же обнулял массив при переходе с Q4 к Q1. И в последний метод занимался тем что вытаскивал данные из массива, смотрел нужно ли входящий параметр считать, он же после вызывал метод добавление в массив и возвращал посчитанное или не посчитанное значение ( в зависимости от параметра «StartsFromJan1»).
Далее в компоненте tMap вызывался данный метод в который передавались значения «StartsFromJan1»,«Quarter», «someValue»…

Проблема с пустыми строками… по началу мы просто урезали количество читаемых строк из файла, но данное решение было временным, так как количество данных со временем увеличивается.Решение пришло в виде компонента tFilterRow, в котором просто указывалось некоторое выражение для фильтрации, к примеру Year != null || Year!="", все значения которые соответствовали условию прогонялись через tMap.

после проведения описанных оптимизаций время разработки одного скопа данных сократилось на несколько порядков, количество работы стало также ощутимо меньше, хотя по большей степени все делалось из за огромного нежелания делать однотипную и долговременную работу, особенно если это касается копи-пейста.
Tags:
Hubs:
+1
Comments 2
Comments Comments 2

Articles