2013-08-09 2 views
0

С 5 МБ документа следующий запрос принимает libxml2 3 секунды для оценки. Я могу что-то сделать, чтобы ускорить процесс? Мне нужен результирующий набор узлов для дальнейшей обработки, поэтому нет count и т. Д.Высокая производительность запроса документа XPath

Спасибо!

descendant::text() | descendant::* 
[ 
self::p or 
self::h1 or 
self::h2 or 
self::h3 or 
self::h4 or 
self::h5 or 
self::h6 or 
self::dl or 
self::dt or 
self::dd or 
self::ol or 
self::ul or 
self::li or 
self::dir or 
self::address or 
self::blockquote or 
self::center or 
self::del or 
self::div or 
self::hr or 
self::ins or 
self::pre 
] 

Edit:

Использование descendant::node()[self::text() or self::p or ... как предложено Jens ERAT (см принятый ответ) значительно улучшили скорость; от оригинала 2.865330s, чтобы просто улучшить 0.164336s.

+0

Я хотел бы увидеть некоторые отзывы о вашем бенчмаркинге для различных предложений здесь. –

+0

@JensErat Я измерил это и отредактировал мой вопрос. Большое спасибо за ваш совет. –

ответ

3

Бенчмаркинг без какого-либо документа для сравнения очень сложный.

Две идеи для оптимизации:

  • Использование в качестве нескольких шагов descendant:: оси, как это возможно. Они дороги и, вероятно, вы можете немного ускориться. Вы можете комбинировать text() и элементов испытаний, как это:

    descendant::node()[self::text() or self::h1 or self::h2] 
    

    и распространяется на все элементы (я держу запрос короткий для лучшей читаемости).

  • Используйте строковые тесты вместо тестов узлов. Они могли бы быть быстрее (вероятно, нет, см. Комментарии к ответу). Конечно, вы должны держать тест text().

    descendant::node()[self::text() or local-name(.) = 'h1' or local-name(.) = 'h2'] 
    

Если вы часто запрашивая тот же документ, подумайте об использовании собственной базы данных XML, как Basex, Exist DB, Зорба, MarkLogic, ... (первые три являются бесплатными) , Они помещают индексы в ваши данные и должны иметь возможность обслуживать результаты намного быстрее (и поддерживать XPath 2.0/XQuery, что значительно упрощает разработку). Все они имеют API для большого набора языков программирования.

+0

Я знаком с некоторыми внутренними компонентами движка XPath в libxml2, и использование 'local-name()' вместо NodeTest, конечно, медленнее. Однако ваше первое предложение должно привести к измеримому ускорению. – nwellnhof

+0

Полезно знать, спасибо за отзыв. –

+1

Я просто попробовал свое первое предложение на тестовом документе, и это привело к ускорению в 15 раз. – nwellnhof

0

У вас есть libxml2, скомпилированный с включенной опцией -with-threads? Если да, то самый простой, что нужно сделать было бы бросить быстрый процессор с большим количеством ядер в задаче

+2

libxml2 не использует потоки для ускорения оценки выражений XPath. – nwellnhof

0

Ваш запрос эквивалентен

(descendant::text() | descendant::p 
    | descendant::h1 | descendant::h2 | descendant::h3 | descendant::h4 | descendant::h5 | descendant::h6 
    | descendant::dl | descendant::dt | descendant::dd | descendant::ol | descendant::ul | descendant::li 
    | descendant::dir | descendant::address | descendant::blockquote | descendant::center 
    | descendant::del | descendant::div | descendant::hr | descendant::ins | descendant::pre 
) 

Но я не в состоянии измерить разницу в скорости его ,

+1

Я предполагаю, что это будет медленнее, чем быстрее, поскольку документ (должен быть | может быть) сканироваться несколько раз, по одному для каждого «потокового» шага. Я не уверен, насколько оптимизирован умный libxml2. –

+0

Это намного медленнее, чем исходный запрос, использованный в моем вопросе. См. Ответ @ JensErat. –

Смежные вопросы