2014-12-07 3 views
1

Предположим, у меня есть куча медицинских журналов с корневыми элементами как medicalJournal. Все медицинские журналы принадлежат к коллекции «mj», а коллекция «mj» имеет только медицинские журналы. Журналы других видов тоже имеют свои собственные коллекции (physicsJournal -> «р ^») Чтобы получить все медицинские журналы, которые я пишу простейший запрос в мире:Как пустые cts: и-запрос делают с точки зрения производительности

cts:search(/medicalJournal,cts:and-query(())) 

Однако, равноправное мой говорит, почему бы не поставить запрос коллекции вместо «pj» вместо пустого и запроса и, таким образом, добавить дополнительное ограничение. Обоснование в том, что это может избежать выборки списка всех идентификаторов фрагментов, которые пусты и делают. Хотя, когда я запускал запрос коллекции, В первый раз на счетчике запросов были обнаружены пропуски списков-кешей. Пожалуйста, дайте мне знать, какой вариант следует принять?

ответ

8

Короткий ответ заключается в том, что cts:and-query(()) не имеет собственных затрат, но запрос коллекции будет быстрее, чем ваше выражение для поиска. Я бы не использовать для поиска выражение на всех, так что я бы написать это как:

cts:search(collection(), cts:collection-query($journal-collection)) 

Чем дольше ответ, что ваш может проверить это довольно легко, и получить хорошую информацию от xdmp:plan и «xdmp: запрос -meters`. Вы также можете использовать профилирование запросов.

Начнем с вставки некоторых тестовых документов. При этом используется https://github.com/mblakele/taskbot

(: insert 500k test documents. :) 
import module namespace tb="ns://blakeley.com/taskbot" 
    at "taskbot.xqm" ; 

tb:list-segment-process(
    (: Total size of the job. :) 
    1 to 500 * 1000, 
    (: Size of each segment of work. :) 
    500, 
    "test/asset", 
    (: This anonymous function will be called for each segment. :) 
    function($list as item()+, $opts as map:map?) { 
    (: Any chainsaw should have a safety. Check it here. :) 
    tb:maybe-fatal(), 
    let $type-list := ('mj', 'pj', 'aj', 'bj', 'cj', 'dj') 
    let $type-count := count($type-list) 
    for $i in $list 
    let $idx := 1 + xdmp:random($type-count - 1) 
    let $type as xs:string := subsequence($type-list, $idx, 1) 
    return xdmp:document-insert(
     "test/"||$type||"/"||$i, 
     element article { 
     element id { $type||$i }, 
     element type { $type }, 
     element { $type } { $i }, 
     element issue { 1 + xdmp:random(99) }, 
     element article { 1 + xdmp:random(999) }, 
     (1 to xdmp:random(9)) ! element article-ref { 
      xdmp:random(1000) } }, 
     xdmp:default-permissions(), 
     ($type)), 
    (: This is an update, so be sure to commit each segment. :) 
    xdmp:commit() }, 
    (: options - not used in this example. :) 
    map:new(map:entry('testing', '123...')), 
    (: This is an update, so be sure to say so. :) 
    $tb:OPTIONS-UPDATE) 

бездельничать и ждать документов для загрузки. Вы можете проверить ErrorLog.txt, чтобы увидеть прогресс или обновить статус базы данных. Или просто наблюдайте за своими процессорами.

После загрузки эти тестовые документы включают в себя много избыточности. Это позволяет нам проверять различные способы получения документов. Вот пример, чтобы посмотреть на:

<?xml version="1.0" encoding="UTF-8"?> 
<article> 
    <id>mj192462</id> 
    <type>mj</type> 
    <mj>192462</mj> 
    <issue>31</issue> 
    <article>432</article> 
    <article-ref>589</article-ref> 
    <article-ref>812</article-ref> 
    <article-ref>316</article-ref> 
    <article-ref>512</article-ref> 
    <article-ref>380</article-ref> 
</article> 

Теперь я предпочитаю оставить первый cts:search параметр как collection() и сделать все, что в КТС: параметр запроса. Это более композитно и избегает любого соблазна вытеснить границы поисковых выражений. Поэтому я бы начал с тестирования, что cts:search(//mj, cts:and-query(())) эквивалентен cts:search(collection(), cts:element-query(xs:QName('mj'), cts:and-query(()))). Использование 7.0-4.1 и xdmp:plan Я вижу, что они оба используют один и тот же поиск, который мы можем сокращать как OR(element(mj), link-child(descendant(element(mj)))).

<qry:final-plan> 
    <qry:and-query> 
    <qry:or-two-queries> 
     <qry:term-query weight="0"> 
     <qry:key>213142789040258053</qry:key> 
     <qry:annotation>element(mj)</qry:annotation> 
     </qry:term-query> 
     <qry:term-query weight="0"> 
     <qry:key>11205365121816230941</qry:key> 
     <qry:annotation>link-child(descendant(element(mj)))</qry:annotation> 
     </qry:term-query> 
    </qry:or-two-queries> 
    </qry:and-query> 
</qry:final-plan> 

Обратите внимание, как нет ничего в плане, соответствующий вашему cts:and-query(())? Это потому, что это нок. Реальная работа в запросе, например cts:search(/medicalJournal, cts:and-query(())), выполняется путем обработки поискового выражения /medicalJournal. Это может помочь объяснить, почему я предпочитаю оставлять выражение для поиска как collection() и соответствовать параметру cts:query.

Термин интересный, но не будем вдаваться в него сейчас.

Вместо этого давайте посмотрим на некоторые другие способы добраться до mj статей. Мы можем запросить сбор mj или элементы, где type[.='mj'], или запрос каталога на test/mj/.

collection('mj') 

cts:search(collection(), cts:collection-query('mj')) 

cts:search(collection(), cts:element-value-query(xs:QName('type'), 'mj') 

cts:search(collection(), cts:directory-query('test/mj/', 'infinity')) 

Проверка xdmp:plan выхода для каждого, мы видим, что qry:final-plan показывает два term-query просмотра для первых двух форм. Это очень похоже на element-query на mj, но не всегда на тех же условиях. Затем мы видим один за последние три. Термин ищет сложность запросов к диску, поэтому мы можем сказать, что запрос элемента в два раза сложнее, чем запрос коллекции.

Это в значительной степени отвечает на ваш вопрос, я думаю: cts:search(collection(), cts:collection-query('mj')) может быть быстрее, чем cts:search(collection(), cts:element-query(xs:QName('mj'), cts:and-query(()))), потому что он меньше поисков терминов.

Но давайте продолжим работу с последними тремя и посмотрим, есть ли какая-либо причина использовать ту или иную из трех последних альтернатив. Поиск коллекции и поиск в каталоге используют URI: соответственно URI коллекций и URI каталога. Они довольно сильно оптимизированы, поэтому мы можем ожидать, что они будут быстрее, чем поиск по элементам.

Посмотрим, можем ли мы доказать это, используя xdmp:query-meters. Запуск каждый из последних трех выражений в форме, как это:

xdmp:describe(
    cts:search(collection(), cts:collection-query('mj'))) 
, xdmp:query-meters() 

Для этого упражнения внимания на то, что xdmp:query-meters говорит о кэше дерева и обращениях в кэше списка и промахах. Не обращайте слишком много внимания на elapsed-time, потому что это будет зависеть от того, сколько данных индекса кэшировано, и мы не можем это контролировать. В любом случае вы должны увидеть те же общие удары дерева и промахи со всеми тремя запросами. Я видел по 9 для каждого, но важно то, что нет никакой разницы, потому что результаты одинаковы. Но кеш-листы списков и пропуски складываются по-разному. С коллекцией или каталогом она равна количеству стендов в базе данных: в моем случае 3. Но для элемента-значения это вдвое больше числа трибун: в моем случае 6. Таким образом, все остальные равны, поиск по элементам-значения рискует сделать дважды много ввода-вывода. И все остальное не равно: в URI-поисках меньше вероятность ввода каких-либо операций ввода-вывода, потому что их индексы имеют тенденцию оставаться в памяти все время.

Мы можем заключить, что, хотя ни один из других методов не очень медленный, поиск по URI коллекции или URI каталога является лучшим.

+0

Отличный отклик. Большое спасибо. – callow

+0

Реализация 'cts: search' в JavaScript (ну,' cts.search') в предстоящей версии MarkLogic 8 фактически удаляет первый параметр и по умолчанию используется эквивалент 'cts: search (fn: collection() , $ query, $ options) '. –

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