Выполните текстовый поиск по большому количеству XML текстовых узлов и решите, будет ли шаблон один раз - PullRequest
2 голосов
/ 07 апреля 2020

У меня есть XML файлы размером от 50 МБ до максимум 2 ГБ с десятками или сотнями тысяч mycomment элементов, которые имеют только текстовый узел. Путь к узлу mycomment не является фиксированным и не определен, и, таким образом, //mycomment - единственный способ получить все из них. Длина mycomment/text() составляет от 50 до 500 символов. Мне нужно искать один шаблон во всех mycomment текстовых узлах, чтобы классифицировать файл. Если шаблон " mypattern1234 " найден в одном из текстовых узлов, переменная hit устанавливается в 1, иначе она пуста. Это хорошее решение для расчета hit следующим образом:

  <xsl:variable name="hit">
    <xsl:if test="//mycomment[contains(text(),' mypattern1234 ')]">1</xsl:if>
  </xsl:variable>

:-) Я использую XSLT v1.0. Спасибо.

Ответы [ 3 ]

2 голосов
/ 07 апреля 2020

Вы не сможете обрабатывать входной документ объемом 2 ГБ, если не переключитесь на потоковый процессор XSLT 3.0, такой как Saxon-EE.

Если вы используете потоковый процессор, то я бы предложил делая это как

<xsl:source-document href="input.xml" streamable="yes">
  <xsl:if test="//text()[parent::comment][contains(.,' mypattern1234 ')]>1</xsl:if>
</xsl:source-document>

Это немного меньше затрат, если смотреть только на текстовые узлы и затем изучать их контекст, а не сопоставлять узлы элемента и затем настраивать поиск дочерних текстовых узлов.

Я ожидаю, что поиск в 2 Гб будет запущен примерно через минуту, в зависимости от вашего оборудования. Однако сканирование исходного документа должно быть остановлено, как только будет найдено совпадение, поэтому, если вы найдете совпадение в начале документа, оно будет намного быстрее, чем это.

1 голос
/ 07 апреля 2020

Не ясно, могут ли элементы mycomment иметь смешанное содержимое или текстовые узлы, чередующиеся с комментариями или инструкциями по обработке. Обычно, если вы ожидаете, что элементы mycomment будут иметь только текстовое содержимое, я бы проверил на mycomment[contains(., ' foo ')], нет необходимости выбирать вплоть до дочерних узлов текстового узла. Если вы хотите сделать это, то я бы использовал mycomment/text()[contains(., ' foo ')], ваша проверка text() в качестве аргумента для contains выберет первый текстовый дочерний узел, поэтому, например, <mycomment>foo <!-- a comment --> mypattern1234 </mycomment> текст не будет обнаружен.

Что касается эффективности, то это будет очень сильно зависеть от используемого процессора XSLT.

0 голосов
/ 18 апреля 2020

Помимо XML технологий ripgrep ускоряет поиск на порядки:

#!/bin/zsh

DATABASE="$1"
SEARCH_PATTERN="$2"

if [ "${#SEARCH_PATTERN}" != 0 ] && [ "${#DATABASE}" != 0 ] ; then

RAWHIT=`rg -C 5 "$SEARCH_PATTERN" "$DATABASE"`

if [ "${#RAWHIT}" != 0 ] ; then
HIT=`echo $RAWHIT | rg -c -U "<comment>.*$SEARCH_PATTERN.*</comment>"`
if [ "${#HIT}" != 0 ] ; then
    echo "Pattern found"
else
    echo "Pattern not found"
fi 
else
    echo "Pattern not found"
fi
else
    echo "Missing Search Pattern or Database"
fi

Время работы и измерение времени на платформе i5:

> time ./run.sh DB50C1000000P.xml Foo4711
Pattern found
./run.sh DB50C1000000P.xml Foo4711  0,23s user 0,58s system 98% cpu 0,828 total

> time ./run.sh DB50C1000000P.xml Foo4711a
Pattern not found
./run.sh DB50C1000000P.xml Foo4711a  0,23s user 0,59s system 98% cpu 0,829 total

Загрузка базы данных: База данных

...