Обработка текста, баз.

Тема в разделе "Мысли, идеи и полезные статьи.", создана пользователем capturis, 10.02.16.

  1. capturis

    capturis Участник

    Сообщения:
    56
    Симпатии:
    104
    Баллы:
    46
    Все чаще стал обращать внимание на посты на разных форумах формата "как убрать дубли из файла", "как почистить текст от мусора" и т.п. примитивные задачи, которые становятся трудно разрешимыми при увеличении исходных файлов свыше определенного предела.
    Очевидно те, кто задает такие вопросы, не знают как это делается, а я знаю и с удовольствием расскажу.
    Речь пойдет об утилитах командной строки линукс-подобных операционных систем. Для эффективной работы с большими, нет не так - с ОГРОМНЫМИ файлами (логи серверов, почты etc.), в линуксах давным-давно разработаны специальные, крайне эффективные программы, способные за считанные мгновения перелопатить гигантский объем информации.
    При этом как правило сохраняются очень маленькие требования к железу.

    Итак, приступим.
    Первая задача, с которой сталкивается начинающий дорвейщик - где взять ключи. Допустим на просторах интернетов мы нашли некую базу кейвордов на 1 млрд строк(1052839850 если быть точным). В распакованном виде (txt) ~ 59,8 ГБ
    Я для тестов скачал, хочу время засечь)))
    Популярные решения вроде кейвордкипера ее не тянут(или требуют кучу оперативки, хз). А нам надо выдернуть из нее нужные ключи.
    Для этого есть утилита grep.
    Она умеет искать в текстовом файле или в папке (папках рекурсивно) совпадения по маске, в том числе с использованием регулярных выражений.
    Полностью команда будет выглядеть например так:
    Код:
    grep реферат Keywords.txt > реферат.txt #вроде ничего сложного))
    Это дело заняло у меня 7 минут 28 секунд. Найдено 3810304 совпадений.
    Далее.
    Полученные ключи нужно почистить от мусора. Под мусором можно понимать разное в зависимости от задачи. Здесь будем считать мусором любые символы, отличающиеся от букв, цифр и пробелов.
    Для замены символов используется команда sed.
    Она обрабатывает каждую строку по порядку, пока не дойдет до конца файла.
    В рамках нашей задачи будет выглядеть примерно так:
    Код:
    sed 's/[^a-zA-Zа-яА-Я0-9\ ]\+/ /g;s/^[ ]*//;s/[ ]*$//;s/\ \{2,\}/\ /g' file1.txt > file2.txt 
    Здесь все лишние символы заменяются пробелом. И сразу же убираются пробелы в начале и в конце строки, а также образовавшиеся после замены двойные пробелы.
    После удаления мусора могли возникнуть дубли строк, чтобы их удалить можно воспользоваться командой sort.
    Работает очень просто. Сортирует входящий поток(файл) и при надобности оставляет только уникальные строки (ключ "-u").
    Код:
    sort -u file1.txt > file2.txt
    Естественно, поддерживается перенаправление вывода и можно объединить эту команду в конвеер с предыдущей.
    Код:
    sed 's/[^a-zA-Zа-яА-Я0-9\ ]\+/ /g;s/^[ ]*//;s/[ ]*$//;s/\ \{2,\}/\ /g' file1.txt | sort -u > file2.txt
    В дело пускать отсортированный по алфавиту список ключей нельзя. Надо перемешать:
    Код:
    sort -R file1.txt > file2.txt
    Вроде все норм, но великоват файлик, надо порезать split:
    Код:
    split -l 10000 --additional-suffix=.txt file.txt
    Разобьет файл на части по 10000 строк в каждой и добавит нужное расширение.
    Здесь мы вкратце познакомились с обработкой строк, а что же делать если надо обработать CSV? Тут тоже есть методы.
    Вырезать первый столбец из файла с разделителем "точка с запятой" cut:
    Код:
    cut -d';' -f1 file1.csv > file2.txt # аналогично 3 и 5 столбцы:
    cut -d';' -f3,5 file1.csv > file2.csv
    Такого же результата можно добиться с помощью прогаммы awk:
    Код:
    awk -F';' '{print $1}' file1.csv > file2.txt 
    awk -F';' '{print $3 ";" $5}' file1.csv > file2.csv
    Эта программа работает чуть медленнее, зато имеет гораздо более широкие возможности. Например можно вывести значение первого столбца строки, во втором столбце которой присутствует нужная маска:
    Код:
    awk '$2 ~ /LEGO/ {print $1}' file1.csv > file2.csv
    Вообще awk и sed имеют слишком много возможностей, чтобы пытаться описать их за один раз, да и написано в интернете по этому поводу уже немало. Кому будет интересно найдут. Вот для начала:
    awk
    sed

    Еще пара прикладных примеров:
    Бывает нужно сгенерировать базу кейвордов из исходных. Допустим сделать список формата "купить X в городе Y"
    У нас есть список товаров и список городов в файлах. Читаем файл с товарами, заменяем начало строки на нужную фразу с подстановкой и записываем в файл:
    Код:
    cat товары.txt | while read line;do sed "s/^/купить $line в /" города.txt; done > 3.txt
    Будьте осторожны, не надо скармливать этому скрипту слишком большие файлы - на выходе получается произведение строк. Хотя ничего страшного не случится, лишь бы места на диске хватало))

    Проверка статистики поисковой выдачи.
    Допустим есть кучка запросов, по которым надо проверить выдачу и узнать, какие сайты в топе. Чем больше запросов, тем интереснее.
    Парсим топ до требуемой глубины. Складываем в один файл в формате "ссылка;запрос"
    Код:
    #Выводим все ссылки, по убыванию:
    cut -d';' -f1 top3.txt | sort | uniq -c | sort -nr > link.txt
    #Выводим все домены, по убыванию:
    cut -d'/' -f3 top3.txt | sort | uniq -c | sort -nr > domains.txt
    Здесь только малая часть того, что можно сделать с текстом в линуксе, используя встроенные утилиты.
    Если появятся трудности с освоением или интересные задачи, велком в комментарии.
     
    cafen, instocky, bender и 31 другим нравится это.
  2. armor

    armor Участник

    Сообщения:
    87
    Симпатии:
    50
    Баллы:
    41
    годнота!
     
  3. mordvin

    mordvin Модератор Команда форума

    Сообщения:
    215
    Симпатии:
    161
    Баллы:
    67
    Зачот :) из под винды реально? Эмуляторы там итп?
     
  4. Insider

    Insider Администратор Команда форума

    Сообщения:
    1.025
    Симпатии:
    685
    Баллы:
    209
    VMWare или VirtualBox и вперед :)
     
    instocky и mordvin нравится это.
  5. capturis

    capturis Участник

    Сообщения:
    56
    Симпатии:
    104
    Баллы:
    46
    Есть проект для запуска всего этого добра в винде https://www.cygwin.com/ но там какие-то заморочки с переводом строки и ключами утилит, впрочем я с ним особо не возился, да и давно это было. Виртуальная машина хорошее решение.
     
    instocky нравится это.
  6. sim0n

    sim0n Новичок

    Сообщения:
    49
    Симпатии:
    7
    Баллы:
    13
  7. Eric

    Eric Новичок

    Сообщения:
    81
    Симпатии:
    30
    Баллы:
    19
    Крутяк! Спасибо, половину юзаю завно уже, но узнал кое что новое.

    Попробуй ппомоги с такой задачей, есть список урлов, среди которых могут попадаться разные страницы, но на одном и том же домене

    Пример (видно что домены повторяются)
    Код:
    https://domain111.com/threads/qweqwe.1/
    https://domain111.com/threads/blabla.2/
    https://domain222.com/threads/qweqwe.1/
    https://domain222.com/threads/blabla.2/
    https://domain333.com/threads/qweqwe.1/
    https://domain333.com/threads/blabla.2/
    
    нужно убрать повторные страницы на одном и том же домене, чтобы один домен встречался один раз

    пример результата
    Код:
    https://domain111.com/threads/qweqwe.1/
    https://domain222.com/threads/qweqwe.1/
    https://domain333.com/threads/qweqwe.1/
    
    (оставлять в результате нужно полный урл, а не только домен, как оставить только домен это просто)
    Буду очень признателен если можно это сделать, а то в exel извращаюсь, а там максимум 1млн строк

    Есть мысли что можно взять разделить на части по символу "/" и получить домен, а что дальше не понимаю
     
  8. Дядя Жора

    Дядя Жора Активный участник

    Сообщения:
    399
    Симпатии:
    168
    Баллы:
    81
  9. capturis

    capturis Участник

    Сообщения:
    56
    Симпатии:
    104
    Баллы:
    46
    Правильные мысли.
    Код:
    cut -d'/' -f3 file.txt | sort -u | while read line; do grep "$line" file.txt | head -n1 >> file2.txt;done
    Вырезаем домен, удаляем дубли, ищем совпадения и выводим только первое.
     
    kirill и Eric нравится это.
  10. Eric

    Eric Новичок

    Сообщения:
    81
    Симпатии:
    30
    Баллы:
    19
    Проверил, сработало :) Спасибо

    Очень хотелось именно в консоли делать это, но посмотрю и эту софтину, спасибо
     
    capturis нравится это.
  11. AZANIR

    AZANIR Участник

    Сообщения:
    103
    Симпатии:
    27
    Баллы:
    40
    ТС спасибо воспользовался вашим методом установил в систему GnuWin и файл в 3500 строк в доли секунды удалило дубли ) . вообщем будем работать с данной софтиной)
    и применять в шаблонах очень кстати круто особенно когда у тя гиговые файлы на дубли пробить)
     
  12. capturis

    capturis Участник

    Сообщения:
    56
    Симпатии:
    104
    Баллы:
    46
    Допустим у нас есть база с данными в формате CSV с такой структурой:
    Код:
    строка|строка;строка;строка;строка|пикча.jpg;пикча.jpg;пикча.jpg;пикча.jpg|Tag;Tag2;Tag3|номер|номер|номер
    В каждой строке свой набор тегов, в целом их не так много. Надо выдернуть из базы все теги и все строки с ними разложить по соответствующим файлам. Как видно, здесь два вида разделителей.
    Сначала выдернем все теги, вдруг еще понадобятся:
    Код:
    cut -d'|' -f4 file.txt | sed 's/;/\n/g' | sort -u > tags.txt
    
    Потом основное:
    Код:
    cat tags.txt | while read line; do grep "$line" file.txt > "$line".txt; done
    
     
    kirill нравится это.
  13. btr

    btr Участник

    Сообщения:
    150
    Симпатии:
    32
    Баллы:
    30
    @capturis есть у тебя skype или jabber? Проконсультироваться у тебя хотел, если ты не против.
     
  14. capturis

    capturis Участник

    Сообщения:
    56
    Симпатии:
    104
    Баллы:
    46
    Добавил контакты в профиль.
     
  15. mixwor

    mixwor Новичок

    Сообщения:
    70
    Симпатии:
    3
    Баллы:
    23
    Есть csv файл с ключами такого формата:
    Код:
    "texet x driver quad tm 4082r";"1";"2";"6";"28";"409"
    Можно ли как то отсортировать его по кол-ву запросов?
     
  16. bro

    bro Участник

    Сообщения:
    228
    Симпатии:
    89
    Баллы:
    36
    Код:
    cat file.txt |sed 's/"//g' | sort -t ';' -gk 6 > result.txt
    Кавычки пришлось убрать, иначе можно так:
    Код:
    sort -t ';' -nk 5 file.txt > result.txt
    но тогда он отсортирует как то так (по первой цифре, а не целому числу):
    Код:
    "texet x driver quad tm 4082r";"1";"2";"6";"28";"10"
    "texet x driver quad tm 4082r";"1";"2";"6";"28";"201"
    "texet x driver quad tm 4082r";"1";"2";"6";"28";"3"
    "texet x driver quad tm 4082r";"1";"2";"6";"28";"409"
    "texet x driver quad tm 4082r";"1";"2";"6";"28";"410"
    "texet x driver quad tm 4082r";"1";"2";"6";"28";"500"
     
    Николай Максимов, btr и mixwor нравится это.
  17. capturis

    capturis Участник

    Сообщения:
    56
    Симпатии:
    104
    Баллы:
    46
    Кавычки убирать не обязательно, если использовать их в качестве разделителя
    Код:
    sort -t'"' -nk 12
     
    btr, mixwor и bro нравится это.
  18. bro

    bro Участник

    Сообщения:
    228
    Симпатии:
    89
    Баллы:
    36
    Да, твой вариант логичнее.
     
    capturis нравится это.
  19. btr

    btr Участник

    Сообщения:
    150
    Симпатии:
    32
    Баллы:
    30
    не достучался в jabber, тут спрошу =)
    1.Есть список ключей(в одном файле).
    2.Есть 30 файлов с содержимым мультикей(data1;data1-1;data1-2)
    нужно равномерно подмешать ключи с первого файла в 30 фалов, чтоб строки выглядели так:
    кей;data1;data1-1;data1-2

    в 30 файлах количество строк разное, нужно привести к одинаковому, то есть количество строк в первом файле нужно разделить на 30, получаем нужное количество ключей в каждый файл.

    Я решил эту задачу на зенке, но больно долго она мешает =(((((
    3 ляма ключей в первом файле, мешает 6 часов, а что если 30 лямов ключей будет, страшно подумать.
     
  20. capturis

    capturis Участник

    Сообщения:
    56
    Симпатии:
    104
    Баллы:
    46
    Если я правильно понял, надо чтобы на выходе получилось 30 файлов одинакового размера без повторов в первой колонке?
    Это можно сделать так.
    Сначала объединяем все мультикеи в один файл.
    Код:
    cat *m-key.txt > m-key-all.txt
    Вырезаем нужное количество мультикеев:
    Код:
    cat m-key-all.txt | head -n `cat keys.txt | wc -l` > m-key-all2.txt
    Объединяем:
    Код:
    paste keys.txt m-key-all2.txt|sed 's/\t/;/' > out.txt
    И делим на нужное к-во строк:
    Код:
    split -l 100000 --additional-suffix=.txt out.txt
    Думаю в 6 минут уложится))
    PS: с джаббером разберемся.
     
    kirill и btr нравится это.

Поделиться этой страницей