Есть awk скрипт который вытаскивает из больших xml файлов нужные куски.
Логика — простейшая, для каждой строки проверяем, не открывается на ней ли искомый тег, и если открывается, то все строки, включая ту на которой встретился закрываюший тег, добавляем в локальную переменную конкатенацией строк. Когда найден закрывающий тег — то выводим содержимое этой переменной и очишаем ее.
Иногда, из за необъснимы странностей во входном файле, тег или не закрывается или еще что-то, и локальная переменная вырастает до двух мегабайт, и скорость конкатенации такой строки замедлятся в сотни раз.
Как можно переделать скрипт, чтобы его ускорить. Мне в голову приходит один способ: сохранять номера строк, на которых встретился открывающий и парный закрывающий тег, и уже во втором проходе вычитывать файл заново и выводить только нужные строки (номера которых были найдены на первом проходе. Вопрос — а можно как-то решить эту задачу за один проход.
* thriving in a production environment *
Re: Как ускорить awk скрипт выкусывания частей из большого xml?
Здравствуйте, Igor Sukhov, Вы писали:
IS>Есть awk скрипт который вытаскивает из больших xml файлов нужные куски.
IS>Логика — простейшая, для каждой строки проверяем, не открывается на ней ли искомый тег, и если открывается, то все строки, включая ту на которой встретился закрываюший тег, добавляем в локальную переменную конкатенацией строк.
Зачем? Почему бы сразу не распечатывать?
На перле это было бы в одну строчку, типа:
Здравствуйте, jazzer, Вы писали:
IS>>Есть awk скрипт который вытаскивает из больших xml файлов нужные куски.
IS>>Логика — простейшая, для каждой строки проверяем, не открывается на ней ли искомый тег, и если открывается, то все строки, включая ту на которой встретился закрываюший тег, добавляем в локальную переменную конкатенацией строк.
J>Зачем? Почему бы сразу не распечатывать?
забыл сказать, что распечатывать надо не все узлы с определяемые искомыми тегами, а только те у которых есть подтеги с определенным значением.
* thriving in a production environment *
Re[3]: Как ускорить awk скрипт выкусывания частей из большого xml?
Здравствуйте, Igor Sukhov, Вы писали:
J>>Зачем? Почему бы сразу не распечатывать? IS>забыл сказать, что распечатывать надо не все узлы с определяемые искомыми тегами, а только те у которых есть подтеги с определенным значением.
Маленькая такая деталь
И подтеги на других строчках и вообще могут быть в конце главного 15-мегабайтного тега?
Тогда да, запоминать позиции — это самое правильное. Причем можно прямо там же через fseek/ftell.
Здравствуйте, jazzer, Вы писали:
J>>>Зачем? Почему бы сразу не распечатывать? IS>>забыл сказать, что распечатывать надо не все узлы с определяемые искомыми тегами, а только те у которых есть подтеги с определенным значением.
J>Маленькая такая деталь
=) J>И подтеги на других строчках и вообще могут быть в конце главного 15-мегабайтного тега?
нет, подтеги должны быть близко — в пределах 10 килобайт, но почему то не всегда так.
J>Тогда да, запоминать позиции — это самое правильное. Причем можно прямо там же через fseek/ftell.
а как из скрипта узнать текущее cмещение от начала файла чтобы потом передать это в fseek ?
* thriving in a production environment *
Re: Как ускорить awk скрипт выкусывания частей из большого xml?
Здравствуйте, Igor Sukhov, Вы писали:
IS>Есть awk скрипт который вытаскивает из больших xml файлов нужные куски.
все это мне напоминает про "забивание гвоздей микроскопом", только несколько наоборот... например "починка смартфона, кувалдой" )
--
xslt разве не справляется с поставленной задачей? населектить в нем нужных тегов плевое дело и более надежно, чем не предназначенными для парса XML средствами (а также лекго адаптируемо к практически любым будущим изменениям)
тормозит?
Re[5]: Как ускорить awk скрипт выкусывания частей из большого xml?
Здравствуйте, Igor Sukhov, Вы писали:
IS>Здравствуйте, jazzer, Вы писали:
J>>>>Зачем? Почему бы сразу не распечатывать? IS>>>забыл сказать, что распечатывать надо не все узлы с определяемые искомыми тегами, а только те у которых есть подтеги с определенным значением.
J>>Маленькая такая деталь IS>=) J>>И подтеги на других строчках и вообще могут быть в конце главного 15-мегабайтного тега? IS>нет, подтеги должны быть близко — в пределах 10 килобайт, но почему то не всегда так.
J>>Тогда да, запоминать позиции — это самое правильное. Причем можно прямо там же через fseek/ftell. IS>а как из скрипта узнать текущее cмещение от начала файла чтобы потом передать это в fseek ?
Если ты про awk — понятия не имею, имхо, это невозможно там. Я бы для начала выкинул это старье нафиг и заюзал либо перл, либо специализированные инструмент типа xslt.
В перле, когда сматчил начало тега — просто зовешь tell и запоминаешь позицию. Когда нашел свой подтег — делаешь tell опять, вычисляешь разницу (длину) и зовешь seek на начало фрагмента и затем read с длиной.
Но в перле, опять же, все может работать и без этих приседаний, простым аккумулированием строки, как ты делал изначально. Перл все-таки на порядок более продвинутый инструмент, чем awk. Попробуй просто переписать свой awk-скрипт на перл — вполне возможно, удивишься, что все работает и так.
Здравствуйте, zaufi, Вы писали:
IS>>Есть awk скрипт который вытаскивает из больших xml файлов нужные куски.
Z>все это мне напоминает про "забивание гвоздей микроскопом", только несколько наоборот... например "починка смартфона, кувалдой" ) Z>-- Z>xslt разве не справляется с поставленной задачей? населектить в нем нужных тегов плевое дело и более надежно, чем не предназначенными для парса XML средствами (а также лекго адаптируемо к практически любым будущим изменениям) Z>тормозит?
я же сказал что xml большой. несомненно у меня есть код который решает ту же задачу в 5 строчек через парсинг ДОМа, но памяти жрет по 50 гигов, что в принципе ок, но все равно долго. авк построчно делает все тоже самое только быстрее. ну и да — будущие изменения для меня пока не приоритет.
* thriving in a production environment *
Re[6]: Как ускорить awk скрипт выкусывания частей из большого xml?
Здравствуйте, jazzer, Вы писали:
J>>>Маленькая такая деталь IS>>=) J>>>И подтеги на других строчках и вообще могут быть в конце главного 15-мегабайтного тега? IS>>нет, подтеги должны быть близко — в пределах 10 килобайт, но почему то не всегда так.
J>>>Тогда да, запоминать позиции — это самое правильное. Причем можно прямо там же через fseek/ftell. IS>>а как из скрипта узнать текущее cмещение от начала файла чтобы потом передать это в fseek ?
J>Если ты про awk — понятия не имею, имхо, это невозможно там. Я бы для начала выкинул это старье нафиг и заюзал либо перл, либо специализированные инструмент типа xslt.
xslt? какой например?
J>В перле, когда сматчил начало тега — просто зовешь tell и запоминаешь позицию. Когда нашел свой подтег — делаешь tell опять, вычисляешь разницу (длину) и зовешь seek на начало фрагмента и затем read с длиной.
J>Но в перле, опять же, все может работать и без этих приседаний, простым аккумулированием строки, как ты делал изначально. Перл все-таки на порядок более продвинутый инструмент, чем awk. Попробуй просто переписать свой awk-скрипт на перл — вполне возможно, удивишься, что все работает и так.
да не хочется лезть в перл только потому что строчки объединяются так медленно. не думаю что в перле это будет сильно быстрее, реализация наверняка одинаковая. подумалось — самое простое это начать складывать в массив и объединять строки непосредсвенно перед выводом...
* thriving in a production environment *
Re[7]: Как ускорить awk скрипт выкусывания частей из большого xml?
Здравствуйте, Igor Sukhov, Вы писали:
IS>>>а как из скрипта узнать текущее cмещение от начала файла чтобы потом передать это в fseek ?
J>>Если ты про awk — понятия не имею, имхо, это невозможно там. Я бы для начала выкинул это старье нафиг и заюзал либо перл, либо специализированные инструмент типа xslt.
IS>xslt? какой например?
xsltproc, емнип... но я его на большие файлы не натравлял никогда
J>>В перле, когда сматчил начало тега — просто зовешь tell и запоминаешь позицию. Когда нашел свой подтег — делаешь tell опять, вычисляешь разницу (длину) и зовешь seek на начало фрагмента и затем read с длиной.
IS>да не хочется лезть в перл только потому что строчки объединяются так медленно. не думаю что в перле это будет сильно быстрее, реализация наверняка одинаковая. подумалось — самое простое это начать складывать в массив и объединять строки непосредсвенно перед выводом...
Ну по моему опыту, сколько я не писал скриптов в awk — всегда приходилось переделывать в перл. Просто потому что awk слишком ограниченный и примитивный. Так что в какой-то момент я просто забил — выигрыша от awk никакого, только головная боль и необходимость помнить еще один язык. (Единственный плюс — будет работать в ортодоксальных посиксовых инсталляциях, в которых не предполагается наличие перла.) Так что, имхо, "лезть в перл" на порядок продуктивнее, чем "лезть в awk".
Но хозяин — барин, конечно же.
Здравствуйте, jazzer, Вы писали:
J>Здравствуйте, Igor Sukhov, Вы писали:
IS>>>>а как из скрипта узнать текущее cмещение от начала файла чтобы потом передать это в fseek ?
J>>>Если ты про awk — понятия не имею, имхо, это невозможно там. Я бы для начала выкинул это старье нафиг и заюзал либо перл, либо специализированные инструмент типа xslt.
IS>>xslt? какой например? J>xsltproc, емнип... но я его на большие файлы не натравлял никогда
ок, будем знать. но на больших файлах оно все равно умрет, т.к. реализовтать выборку по xpath выражения в потоковом режиме или невозможно или каждое выражение придется вычислять за новый проход по файлу.
J>>>В перле, когда сматчил начало тега — просто зовешь tell и запоминаешь позицию. Когда нашел свой подтег — делаешь tell опять, вычисляешь разницу (длину) и зовешь seek на начало фрагмента и затем read с длиной.
IS>>да не хочется лезть в перл только потому что строчки объединяются так медленно. не думаю что в перле это будет сильно быстрее, реализация наверняка одинаковая. подумалось — самое простое это начать складывать в массив и объединять строки непосредсвенно перед выводом...
J>Ну по моему опыту, сколько я не писал скриптов в awk — всегда приходилось переделывать в перл. Просто потому что awk слишком ограниченный и примитивный. Так что в какой-то момент я просто забил — выигрыша от awk никакого, только головная боль и необходимость помнить еще один язык. (Единственный плюс — будет работать в ортодоксальных посиксовых инсталляциях, в которых не предполагается наличие перла.) Так что, имхо, "лезть в перл" на порядок продуктивнее, чем "лезть в awk". J>Но хозяин — барин, конечно же.
awk гораздо проще, учить перл ради одной проблемы лениво. хотя в awk обнаружилась интересная вещь — т.к. массивы ассоциативные, то индексы в for o in c выражениях выбираются в каком-то внутреннем (для массива) порядке и их приходися сортировать вручную . в перле такого же конечно нет
* thriving in a production environment *
Re[9]: Как ускорить awk скрипт выкусывания частей из большого xml?
IS>awk гораздо проще, учить перл ради одной проблемы лениво. хотя в awk обнаружилась интересная вещь — т.к. массивы ассоциативные, то индексы в for o in c выражениях выбираются в каком-то внутреннем (для массива) порядке и их приходися сортировать вручную . в перле такого же конечно нет
вообще говоря, awk не рассчитан на standalone использование.
Нормальное использование awk -- в пайпе в перемешку с другими шелловскими утилитами, тем же sort.
Скажем, многие вещи проще сделать двумя-тремя awk объединенными через пайп, чем пытаться все зафигачить в один монструозный awk скрипт.
Re[10]: Как ускорить awk скрипт выкусывания частей из большого xml?
IS>>awk гораздо проще, учить перл ради одной проблемы лениво. хотя в awk обнаружилась интересная вещь — т.к. массивы ассоциативные, то индексы в for o in c выражениях выбираются в каком-то внутреннем (для массива) порядке и их приходися сортировать вручную . в перле такого же конечно нет
D>вообще говоря, awk не рассчитан на standalone использование. D>Нормальное использование awk -- в пайпе в перемешку с другими шелловскими утилитами, тем же sort.
в контексте моей задачи это как будет выражаться. например у меня есть гигабайтовый xml файл,
если я грепом вытащу куски которые в которых будет нужная мне информация а потом это все pipe in в awk скрипт — то это думаешь будет быстрее???
в таком случае awk скрипту придется перебрать 10 мегабайт а не гигабайт... строк.
D>Скажем, многие вещи проще сделать двумя-тремя awk объединенными через пайп, чем пытаться все зафигачить в один монструозный awk скрипт.
не всегда. проще использовать и поддерживать один простой скрипт чем 3 простых скрипта.
* thriving in a production environment *
Re[11]: Как ускорить awk скрипт выкусывания частей из большого xml?
IS>в контексте моей задачи это как будет выражаться. например у меня есть гигабайтовый xml файл, IS>если я грепом вытащу куски которые в которых будет нужная мне информация а потом это все pipe in в awk скрипт — то это думаешь будет быстрее??? IS>в таком случае awk скрипту придется перебрать 10 мегабайт а не гигабайт... строк.
раз уж речь зашла за скорость, то попробуй менять локаль.
В С локали (export LC_ALL=C) все будет быстрее, а для некоторый версий grep/awk (скажем, тех версий которые стоят у меня на работе) на *порядки* быстрее чем в US_UTF8 и других локалях.
D>>Скажем, многие вещи проще сделать двумя-тремя awk объединенными через пайп, чем пытаться все зафигачить в один монструозный awk скрипт. IS>не всегда. проще использовать и поддерживать один простой скрипт чем 3 простых скрипта.
ну awk скрипт же не обязан в отдельном файле.
Я имею в виду что у тебя будет один shell скрипт который содержит пайпы, состоящие из множества коротких (заинлайненных) awk-скриптов..
Re[9]: Как ускорить awk скрипт выкусывания частей из большого xml?
Здравствуйте, Igor Sukhov, Вы писали:
IS>awk гораздо проще, учить перл ради одной проблемы лениво. хотя в awk обнаружилась интересная вещь — т.к. массивы ассоциативные, то индексы в for o in c выражениях выбираются в каком-то внутреннем (для массива) порядке и их приходися сортировать вручную . в перле такого же конечно нет
Синтаксис очень похож, перл же создавался как объединение всех существовавших на тот момент текст-ориентированных утилит, включая awk.
Ради смеха можешь попробовать http://perldoc.perl.org/a2p.html
Ну и можешь еще кинуть свой awk-скрипт сюда, я покажу, как он будет выглядеть на перле.
J>Ну и можешь еще кинуть свой awk-скрипт сюда, я покажу, как он будет выглядеть на перле.
у awk (помимо концептуальной чистоты) есть еще мимнимум одно важное преимущество перед перлом -- awk это часть стандарта POSIX, а перл -- это часть никакого стандарта.
Re[11]: Как ускорить awk скрипт выкусывания частей из большого xml?
J>>Ну и можешь еще кинуть свой awk-скрипт сюда, я покажу, как он будет выглядеть на перле.
D>у awk (помимо концептуальной чистоты) есть еще минимум одно важное преимущество перед перлом -- awk это часть стандарта POSIX, а перл -- это часть никакого стандарта.
Так я про это упомянул. Имхо, преимущество совершенно неважное, если только ты не пишешь скрипт, который будет работать ты не знаешь где. Если ты пишешь скрипт для себя — нафиг POSIX не уперся.
Здравствуйте, Igor Sukhov, Вы писали:
IS>Здравствуйте, dilmah, Вы писали:
IS>>>awk гораздо проще, учить перл ради одной проблемы лениво. хотя в awk обнаружилась интересная вещь — т.к. массивы ассоциативные, то индексы в for o in c выражениях выбираются в каком-то внутреннем (для массива) порядке и их приходися сортировать вручную . в перле такого же конечно нет
D>>вообще говоря, awk не рассчитан на standalone использование. D>>Нормальное использование awk -- в пайпе в перемешку с другими шелловскими утилитами, тем же sort. IS>в контексте моей задачи это как будет выражаться. например у меня есть гигабайтовый xml файл, IS>если я грепом вытащу куски которые в которых будет нужная мне информация а потом это все pipe in в awk скрипт — то это думаешь будет быстрее???
Дарю безумную идею: начинаешь копировать теги независимо от того, что внутри. В начале каждого тега запоминаешь размер выходного файла. Пока копируешь — проверяешь, нужно ли внутри то, что тебе нужно, и взводишь флажок. Когда тег закончился — проверяешь флажок: если не установлен — закрываешь файл, делаешь файлу truncate -s предыдущий размер (откатывая таким образом записанный тег) и переоткрываешь файл. Достаточно грепа
На перле можешь попробовать вот так (у меня сработало, по крайней мере, печатаем тег <tag>, если внутри нашлось <GOOD>):
BEGIN{
$p=$f=$i=0; #position,found,insideopen(out,">","out.xml")
}
($p,$i)=(tell out,1) if/<tag>/; # <tag> beginprint out if $i; # print if inside
$f=1 if $i && /<GOOD>/; # check for <GOOD>if (/<\/tag>/) { # <tag> endif(!$f) { # if <GOOD> wasn't foundseek out,$p,SEEK_CUR; # unwind/truncate out filetruncate out,$p
}
$i=$f=0
}
запускать perl -n имя_скрипта
то же самое в одну строчку, полная команда, можешь попробовать прогнать на своем гигафайле:
cat test.xml | perl -ne 'BEGIN{$p=$f=$i=0;open(out,">","out.xml")}($p,$i)=(tell out,1)if/<tag>/;print out if$i;$f=1if$i&&/<GOOD>/;if(/<\/tag>/){if(!$f){seek out,$p,SEEK_CUR;truncate out,$p}$i=$f=0}'
Здравствуйте, Igor Sukhov, Вы писали:
IS>забыл сказать, что распечатывать надо не все узлы с определяемые искомыми тегами, а только те у которых есть подтеги с определенным значением.
sgrep не поможет?
Re: Как ускорить awk скрипт выкусывания частей из большого xml?
Здравствуйте, Igor Sukhov, Вы писали:
IS>Иногда, из за необъснимы странностей во входном файле, тег или не закрывается или еще что-то, и локальная переменная вырастает до двух мегабайт, и скорость конкатенации такой строки замедлятся в сотни раз.
Если проблема именно в конкатенации, можно складывать строки в массив. На пробовал?