Для MarkLogic вам необходимо знать, что поиск индекса происходит только в определенных выражениях и функциях.В этом случае вам нужен более компактный код.Вот форма, которая должна давать те же результаты, но будет использовать индексы простым способом:
<result>
{
for $fileCode in
collection()/
file[identity/@fileType eq "listOfFiles"]/
fileContent/
fileEntry/
fileCode
let $fc1 := $fileCode/@attribute1/string()
let $fc2 := $fileCode/@attribute2/string()
let $fc3 := $fileCode/@attribute3/string()
return
if (collection()/
dmodule/
identity/
dmCode[
@attribute1 eq $fc1][
@attribute2 eq $fc2][
@attribute3 eq $fc3])
then <filePresent>1</filePresent>
else <fileNonPresent>2</fileNonPresent>
}
</result>
Однако этот код будет выполнять один поиск в базе данных на каждую запись listOfFiles
, что не является оптимальным.
Возможна дальнейшая оптимизация.Во-первых, MarkLogic - это документно-ориентированная база данных, в которой каждый документ имеет уникальный URI.Поэтому было бы гораздо эффективнее, если бы вы просто закодировали три значения атрибута в каждый URI документа.Мы можем использовать что-то вроде string-join(($fc1, $fc2, $fc3), '/')
для создания URI.Затем вы можете проверить каждое значение, используя вызов doc()
, который более эффективен, чем поиск в XPath, даже при использовании индексов.И как только это изменение будет сделано, документ listOfFiles
может также хранить URI, а не значения атрибутов.
Во-вторых, я думаю, что формат результатов не очень полезен.Он говорит вам, что некоторые документы отсутствуют, но не какие.Я бы осуществил рефакторинг, чтобы код возвращал только недостающие URI документа.Мы также можем включить дополнительный индекс, доступный в MarkLogic: лексикон URI.Это автоматически поддерживает индекс значения всех URI документов, вроде как ваш listOfFiles
документ.Используя лексикон URI, я мог бы написать:
<result>{
let $uris :=
collection()/
file[identity/@fileType eq "listOfFiles"]/
fileContent/
fileEntry/
fileCode/
string-join(
(@attribute1/string(),
@attribute2/string(),
@attribute3/string()),
"/")
let $uris-present := cts:uris((), "document", cts:document-query($uris))
for $uri in $uris
where not($uri = $uris-present)
return <missing>{ $uri }</missing>
}</result>
Это требует только одного просмотра базы данных и выполняет остальную часть необходимой работы в памяти.Он должен масштабироваться намного лучше, чем ваш исходный запрос или моя первая итерация.Если вы не согласны с моей переработкой формата результатов и по-прежнему хотите видеть результат для каждого ввода fileCode
, вы можете реорганизовать предложение ...where...return...
в ...return...if...then...else...
, как в исходном запросе.
Обязательно используйте инструмент профиля в https://github.com/marklogic/cq - он может помочь вам опробовать альтернативы и определить возможности оптимизации.