Как дождаться завершения функции вызова MarkLogic - PullRequest
0 голосов
/ 27 декабря 2018

У меня есть требование, при котором я перебираю 10 000 000 документов, и для каждого документа я выполняю некоторую операцию и сохраняю некоторые значения в /count.xml.Когда я перехожу ко второму документу, я обновляю /count.xml обновленным значением

В настоящее время это то, что я делаю, здесь $ total-records составляет 10 000 000

let $total-records := xdmp:estimate(cts:search( //some code))
let $batch-size := 5000
let $pagination := 0
let $bs := 
   for $records in 1 to fn:ceiling($total-records  div $batch-size )
   let $start := fn:sum($pagination + 1)
   let $end := fn:sum($batch-size + $pagination)
   let $_ := xdmp:set($pagination, $end)
   return
    xdmp:spawn-function
    (
    function() {
     for $each in cts:search( //some code)[$start to $end]
     return //some operation and update '/count.xml' with some updated values
    },
    <options xmlns="xdmp:eval"><commit>auto</commit><update>true</update</options>
    )
let $doc := doc("/count.xml")
return ()

Так что здесьпроблема в том, что мне нужно прочитать файл '/count.xml' после того, как все документы будут повторяться, но с помощью приведенного выше кода с помощью задачи spawn

let $ doc: = doc ("/ count.xml")

не будет последней, так как вышеуказанная задача spawn будет выполняться в разных потоках.

Мне нужно решение, в котором

let $ doc: = doc("/count.xml")

ожидает завершения всех задач вызова.

Я также сталкивался с опцией

<result>{fn:true()}</result>

, но яне знаю, будет ли это работать или нет, потому что переменная

$ bs

нигде не используется, и документация говорит: «Когда вызывающий запрос использует значение future в любой операции, он будет автоматически ждать завершения вызываемой задачи и будет использовать результат. '

Есть ли другиеternative, где строка

let $ doc: = doc ("/ count.xml")

будет выполнена только после того, как все задачи вызова будут завершены

Ответы [ 2 ]

0 голосов
/ 28 декабря 2018

В соответствии с приведенным требованием, нельзя сказать разницу между записью одного результата в запросе через 10, тысяч документов против записи результата после запроса 1 документа ввремя.Поскольку ваш пример не записывает в запрашиваемые документы, его не нужно порождать или запускать в отдельном потоке или транзакции, скорее, как говорит HTH, вы можете использовать агрегатные функции для выполнения одного запроса по всему набору, вычисления окончательного результата.и сохранить его в 1 операции.Скорее всего, это будет выполняться очень быстро (или может быть выполнено).

Если на самом деле требуется, чтобы каждый отдельный документ ДОЛЖЕН был быть запрошен, то последовательно записывается другой общий документ, - это можно наблюдать только с помощью отдельноготранзакции, серийно.Он будет ужасно медленным, почти наверняка дольше, чем время ожидания транзакции вызова.Это означает, что вы должны организовать его извне - если требование состоит в том, что тот же вызывающий абонент запускает процесс, а завершает его (весьма специфичное для реализации требование, которое, если true, вероятно, будет иметь другоепоследствия, выходящие за рамки указанных).

Что-то близкое, что достижимо, но все еще ужасно медленное, - это провести опрос внешних запросов по обновленному общему документу и вернуть «success» после выполнения задания.Но опять же, с таким большим количеством документов, если вы форсируете транзакцию записи для каждой из них, это займет больше времени (или, по крайней мере, не гарантируется, что НЕ займет больше времени), чем тайм-аут одной транзакции, поэтому его следует вызывать «извне».

Здесь я бы порекомендовал пересмотреть требования, чтобы определить желаемую базовую функциональность / результат и, если это действительно необходимо, реализовать точно так, как указано, по сравнению с более производительной реализацией, которая достигает желаемого результата.Если основная функциональность необходима для того, чтобы каждый отдельный запрос был «проверен» с обновлением документа, то необходимо учитывать и другие последствия, такие как откат транзакции.

0 голосов
/ 27 декабря 2018

Чтобы обработать 10 млн документов, вам, вероятно, нужно создать что-то вроде 10.000 пакетов из 1000 документов.Я не думаю, что это будет хорошо работать изнутри MarkLogic.

Я бы посоветовал изучить встроенные функции агрегации MarkLogic.См. Например cts:sum-aggregate.Возможно, вы сможете предварительно рассчитать промежуточные результаты для каждого документа, которые можно агрегировать во время выполнения, используя эти функции агрегирования.Это определенно было бы наиболее эффективным и масштабировалось бы лучше всего.

Альтернативой было бы управление вашими расчетами извне MarkLogic.В противном случае вы в конечном итоге либо заполняете очередь задач, либо работаете с ограничениями по времени ожидания, либо и тем и другим.В этом могут помочь такие инструменты, как Corb2 и DMSDK .

Примечание: вы можете действительно заставить спавнов ждать результата, используя опцию <result>, но либоиспользуйте <result>true</result> или <result>{fn:true()}</result> (обратите внимание на круглые скобки после fn: true, это функция).

HTH!

...