Част 2

Докато все още съм на софтуерна вълна, искам да си припомня моменти от работата ми по докторската дисертация и някои приложни публикации.

Преди няколко години (2018-2019) се опитвах да "правя" Data Science или по-скоро да се ровя в неструктурирани данни, извлечени от Twitter. В archive.org има набор от Twitter архиви по месеци със съобщения, взети през Spitzer. В интерес на истината, ако потърсите в Google "Spitzer Firehose", може би ще излезе научна студия в съавторство с мой колега и ментор - проф. Снежана Сълова.

Основната особеност на архивите е тяхната структура и съдържание. За един месец има създадени папки за всеки отделен ден, в него за всеки отделен час, а в последните има 60 архива за всяка минута. Архивите съдържат JSON файлове с вариращ размер, според броя туитове, хванати през Spitzer за съответната минута. Всеки туит се съхранява като обект с около 220 свойства. Процесът по разархивиране на информацията трябваше да бъде автоматизиран, тъй като ръчното обработване на 31x24x60 (44640) файла не е разумно занимание. За целта използвах Windows PowerShell, като предварително имах нужда да обновя .NET Framework и Windows Management Framework.

За да разархивирам съдържанието на папка за едно денонощие, използвах следния сегмент:


$Zips = Get-ChildItem -filter "*.bz2" -path "D:\twitter\07\01\" -Recurse
$WinRar = "C:\Program Files\WinRAR\winrar.exe"
$Destination = "D:\twitter\07\01\";
foreach ($zip in $Zips)
{
$dir = $zip.Directory.Name
&$Winrar x $zip.FullName $Destination$dir"\"
Get-Process winrar | Wait-Process
}

На първия ред се оказва директорията, от която ще се разархивира информация, като параметър -Recurse означава, че ще се изпълни кодът и в подпапки (за всеки час от деня). С параметър -filter се определя кои файлове ще бъдат включени в операцията - JSON архивите са с разширение .bz2. На втория ред се извиква програмата, с която ще се извърши действието, а третия ред указва изходната локация.

Информацията, която ни беше нужна от JSON файловете, също трябваше да бъде предварително обработена. За научната публикация се бяхме спряли на анализ на мнения от социалните мрежи за 3 туристически курорта в Харватия (Dubrovnik, Rijeka, Plitvice). Лесен начин за обработване на такъв обем от JSON обекти се оказа инструмент с името jq. Отново чрез PowerShell успях да подготвя скрипт, които търси срещане на името на курорта в текстовата част на туита (свойство text на обекта). За филтриране на туитовете, свързани с тези дестинации използвах следния сегмент:


$files = Get-ChildItem "D:\twitter\07\01\" -Recurse -Include *.json
for ($i=0; $i -lt $files.Count; $i++) {
jq -r 'select(.text | tostring | contains(\"Dubrovnik\")) | [.text] | select(length > 0) | @csv' $files[$i].FullName >> "D:\twitter\results\Dubrovnik.csv"
}

На първия ред отново определяме директорията и типа файл, който ще се използва. В цикъла чрез jq се избира полето text, преобразува се на String и се филтрира спрямо избран термин. Проверката се изпълнява, само ако туит съобщението има дължина поне от 1 символ. Резултата се съхранява в csv файл с оператор >> за дописване към края на файла (append).

Следващата стъпка беше да почистим резултатните туитове от някои служебни символи, числа, емотикони и т.н.:


$text = preg_replace('/' . preg_quote('RT ') . '.*?' . preg_quote(': ') . '/', ' ', $text);
// премахване на споделяне RT :
$text = preg_replace("~\s*@(.+?)\s~", ' ', $text);
// премахване на споменавания на потребители
$text = preg_replace("~http(.*)\b~", ' ', $text);
// премахване на хипервръзки
$text = preg_replace('/'.'[\p{Z}]{2, }/u', ' ', $text);
// премахване на всички символи, който не са част от латиницата или кирилицата
preg_replace('/([0-9|#][\x{20E3}])|[\x{00ae}|\x{00a9}|\x{203C}|\x{2047}|\x{2048}|\x{2049}|\x{3030}|\x{303D}|\x{2139}|\x{2122}|\x{3297}|\x{3299}][\x{FE00}-\x{FEFF}]?|[\x{2190}-\x{21FF}][\x{FE00}-\x{FEFF}]?|[\x{2300}-\x{23FF}][\x{FE00}-\x{FEFF}]?|[\x{2460}-\x{24FF}][\x{FE00}-\x{FEFF}]?|[\x{25A0}-\x{25FF}][\x{FE00}-\x{FEFF}]?|[\x{2600}-\x{27BF}][\x{FE00}-\x{FEFF}]?|[\x{2900}-\x{297F}][\x{FE00}-\x{FEFF}]?|[\x{2B00}-\x{2BF0}][\x{FE00}-\x{FEFF}]?|[\x{1F000}-\x{1F6FF}][\x{FE00}-\x{FEFF}]?/u', ' ', $text);
// премахване някои емотикони
$text = preg_replace('~[0-9]+~', ' ', $text);
// премахване на числа
$text = preg_replace('~[[:punct:]]~', ' ', $text);
// премахване на пунктуация
$text = preg_replace('~„|“|–|”|…|«|»|—~', ' ', $text);
// допълнително пунктуационни знаци

Липсват ми страничните ми занимания покрай дисертацията и анализ на текст. Препоръчвам силно две книги, които ми помогнаха да навляза по-бързо в обработката на текст на Светла Коева, Езикови ресурси и технологии за българския език и Компютърна морфология - ресурси и инструменти на Елена Паскалева.

Глава I.

Първият ми сериозен пост е свързан с мигриране на базата данни на Moodle платформа от Linux в Windows среда. Тъй като най-вероятно ще пропусна нещо важно, ако не си го запиша, смятам да обясня процеса по главоблъскане в продължение на около седмица. Не съм импортирал база данни с размер 20 GB до този момент (състоял се и отминал заедно с 2021 г.).

Поради очевидно големия размер нямаше изобщо смисъл да пробвам през интерфейса на PhpMyAdmin. За това използвах стандартния CMD на Windows, за да изпълня команда за импортиране. Попаднах на тази публикация и следвах стъпките. Първият опит отне около 5 часа. Бяха се импортирали около 150 от общо 500+ таблици. В случая процесът прекъсна с грешка. Реших да пробвам като използвам допълнително параметър -f за прескачане на грешки. Тук процесът стигна до към 260 таблици, след което поради външни "битови" фактори стана ясно, че времето е от значение и трябва да се импортира цялата база данни по-бързо (в рамките на 12 часа). Поради някаква причина реших, че използването на по-нова версия на XAMPP и прочие може да повлияят на процеса. С това си изгубих още време...

По съвет на мой колега се опитах с помощно средство да разцепя дъмп файла на по-малки части. Използвах Sqldumpsplitter, но за съжаление цялата информация на кирилица стана неразчетима (encoding and cyrillic, oof). Пробвах да запиша повече параметри по време на изпълнение на импортирането и забелязах, че с течение на времето скоростта за записване на еднакъв брой редове в таблиците се увеличаваше. От 4000 записа за секунда, за две секунди, за три до 4000 за 2 минути, 10 минути и т.н. Реших да си поиграя с настройките на my.ini.

Усилията ми четвърти ден да се справя със задачата най-сетне се увенчаха с успех и то за около 5 часа след използване на следната конфигурация:

key_buffer=16M
max_allowed_packet=1024M
sort_buffer_size=512K
net_buffer_length=1024M
read_buffer_size=256K
read_rnd_buffer_size=512K
myisam_sort_buffer_size=8M
innodb_buffer_pool_size=4G
innodb_log_file_size=1G
innodb_log_buffer_size=256M
innodb_write_io_threads = 16
innodb_flush_log_at_trx_commit=1
innodb_lock_wait_timeout=50

След като всичко сработи и изтеглихме необходимите справки, разбира се спряхме виртуалния сървър. Следващия път обаче се появи проблем с входа в PhpMyAdmin. Moodle извеждаше грешка при опит за достъп до базата данни. По подразбиране вписването в XAMPP става автоматично, без въвеждане на root и празна парола. Възможно е да се смени типа автентикация от config.inc.php, но това не помогна. Помислих, че може би нещо е станало и вече след като знаех как да импортирам бързо, пуснах отново CMD-то и зададох необходимите команди. Тествах и изключих XAMPP. Отново се появи проблемът при повторно зареждане. След усилено търсене се оказа, че при експортиране заедно с dump.sql се запазват мета данни за автентикация (моята интерпретация). Поради факта, че няма зададена парола (user:root, pass:) mysql използва unix-socket плъгин. Решението е да се добави в my.ini в края на секция [mysqld] ред skip-grant-tables. Пропуснах да кажа какви други глупости и ненужни процедури пробвах, за да подкарам този DB бехемот, но колкото по-скоро забравя, по-добре...

Предговор

Обикновено предговор се дава като коментар от автора за причините да бъде написана дадена творба. За "Пикник край пътя" от общ обем 207 страници в първите 15 се разказва за трудния път до издаването на нeредактирана и нецензурирана версия на фантастичната повест. И наистина докато излезе оригиналът в и извън пределите на СССР минава доста време.

През годините съм търсил удобен момент да започна и да пиша свободно. С този "блог" целя да споделям опит, идеи и впечатления от света, работата ми като преподавател, уеб разработчик и интересите ми в т. ч. музика, игри, Интернет събития и др. Вече 10 години се занимавам с не малък брой начинания и започвам да забравям бързо след като намеря нещо колоритно, над което да се впусна в по-сериозни размисли или достигна до решение на труден проблем.