Как в XQuery избежать снижения производительности простого запроса с разбивкой на страницы?

У меня есть база данных ML с несколькими десятками тысяч документов и запрос, который возвращает несколько простых вычисленных значений для всех или для подмножества этих документов. Количество документов выросло до такой степени, что опция «все документы» больше не работает надежно без тайм-аута и будет только ухудшаться по мере роста количества документов. Очевидным решением является использование клиентским приложением другой формы и разбивка результатов на страницы. Это автономный пакетный процесс, поэтому общая скорость не является проблемой - мы просто хотели бы, чтобы отдельные запросы были разумными.

Страничная версия запроса очень проста:

declare namespace ns = "http://some.namespace/here"

declare variable $fromCount external;
declare variable $toCount external;

<response> {
  for $doc in fn:doc()/ns:entity[$fromCount to $toCount]
  return
  <doc> omitted for brevity </doc>
} </response>

Проблема в том, что запрос тем медленнее, чем дальше по документу находится запрошенная страница; предположительно потому, что ему нужно загружать каждый документ по порядку, проверять, является ли он правильным типом, и повторять до тех пор, пока он не найдет $fromCount ns:entitys, прежде чем он даже начнет строить ответ.

Одна проблема заключается в том, что в базе данных есть другие типы документов, поэтому просто использовать fn: doc нереально (хотя они находятся в разных каталогах, поэтому xdmp:directory() может быть вариантом; кое-что я изучу.)

Также в настоящее время нет индекса для элемента ns:entity; это поможет? Это всегда корневой узел документа, а документы довольно большие, поэтому меня беспокоит размер индекса. Кроме того, (медленная часть) этого запроса не интересует значение элемента, а только то, что он существует.

Я думал об использовании search: api для встроенного разбиения на страницы, но это кажется излишним для запроса, который предназначен для сопоставления всех документов; конечно, можно вручную создать запрос, который search:search() будет строить внутренне.

Похоже, что мне действительно нужен эффективный список всех корневых узлов определенного типа в базе данных. Поддерживает ли Marklogic такую ​​вещь? Если нет, решит ли проблему индекс?


Изменить: Оказывается, в моем случае ответом является использование опции xdmp:directory(), поскольку ML, по-видимому, хранит быстрый список всех документов в памяти. Тем не менее, если есть более общее решение проблемы, оно обязательно заинтересует, поэтому я оставлю вопрос здесь.


person Will Goring    schedule 08.10.2012    source источник
comment
Было бы полезно, если бы вы могли подробнее рассказать о том, что должны делать ваши запросы. Да, индекс диапазона элементов в ns: entity, вероятно, поможет ускорить постраничный запрос. Кроме того, если вас интересует только существование элемента, а не его значение, и каждый xs: entity является фрагментом, то xdmp: exists (), вероятно, является самым быстрым способом сделать это определение. Если вы действительно собираетесь выполнять поиск в документах, тогда Search API не является излишним, поскольку он обеспечивает, среди прочего, оптимизированный поиск по страницам - зачем изобретать это колесо заново?   -  person wst    schedule 08.10.2012


Ответы (1)


Ваш анализ верен:

предположительно потому, что ему нужно загружать каждый документ по порядку, проверять, является ли он правильным типом, и повторять до тех пор, пока он не найдет $ fromCount ns: entitys, прежде чем он даже начнет строить ответ

Обычный ответ - cts:search плюс опция unfiltered. Вы обнаружили, что xdmp:directory работает быстрее, но вы все равно сможете измерять время разбиения на страницы как O (n), даже если масштаб меньше. См. http://docs.marklogic.com/guide/performance/unfiltered#chapter - в основном база данных защищает от ложных срабатываний, если вы этого не сделаете.

Другой подход может заключаться в использовании cts:uris и его опции limit, но для этого может потребоваться управление состоянием разбивки на страницы с точки зрения начальных значений, а не количества страниц. Например, если последним элементом на странице 1 было «cat», вы должны использовать «cat» как arg2 при вызове cts:uris для следующей страницы. Вы по-прежнему можете использовать значения начала и конца пагинации. Это все равно O (n), но в гораздо меньшем масштабе.

person mblakele    schedule 08.10.2012