У меня есть база данных marklogic (4.2), которая содержит десятки тысяч больших, сложных (некоторые меньше, но большие - 10 МБ +) документов, поиск в которых выполняется с помощью довольно сложного, программно построенного поиска: поисковый вызов . При нормальном использовании, возвращая несколько результатов за раз с использованием разбивки на страницы и генерируя фрагменты совпадений, он отлично работает. Теперь одному из разработчиков клиента необходимо вернуть все результаты этого запроса сразу, даже в том случае, если он построил запрос, который возвращает все документы в БД. Однако его не волнует большая часть содержания матчей; всего пара элементов идентификатора (один числовой и один свободный текст), оба из которых проиндексированы, и оба всегда находятся в одном и том же xpath в документе.
Дело в том, что я не могу придумать эффективный способ запроса двух элементов в таком большом наборе данных; ему всегда нужно загружать весь документ, и запрос просто исчезает в высокой траве, делая это несколько десятков тысяч раз, и в основном никогда не возвращается.
Я пробовал использовать лексику значения элемента на одном из элементов, отфильтрованных поиском. Это быстро возвращается, но имеет несколько недостатков: * возвращает ложные срабатывания. Это не обязательно является препятствием для сделки, но не оптимально. * получает только один из элементов; как только я пытаюсь повторить этот список и получить другой интересующий его элемент, неудивительно, что это займет вечность (потому что мы возвращаемся к загрузке всего документа для каждого совпадения).
Мне было интересно, может ли помочь объявление поля, содержащего эти два элемента (я мог бы использовать лексикон, чтобы получить одно из значений, а затем искать его в поле, а не загружать целые документы только для того, чтобы получить один идентификатор). но я никогда раньше не использовал поля, и похоже, что это всегда словесные запросы, а не элементные, что не кажется идеальным для того, что мне нужно с ними делать.
Я также подумал, что, возможно, создание нового элемента в документе, который содержит закодированную форму обоих идентификаторов, позволит мне создать один индекс, содержащий оба идентификатора, а затем использовать подход лексики, о котором я упоминал выше, чтобы сузить его до документов, которые, по крайней мере, соответствуют нефильтрованный поиск. Хотя это кажется довольно хакерским подходом.
На самом деле я ищу способ сказать «вот поиск, вот (проиндексированные) элементы, которые меня интересуют, теперь получают их значения для соответствующих документов». Есть ли способ сделать это?
У меня такое ощущение, что ответ - «нет», но спросить стоит.
Если нет, есть ли у кого-нибудь предложения о том, какие альтернативные подходы могут работать лучше всего?
Спасибо.
Пример формата документа:
<doc:entity>
<doc:metadata>
<doc:sap-metadata>
<doc:info>
<doc:id>12345678</doc:id>
<doc:number>AS-1990 13:45</doc:number>
<!-- more document info here -->
</doc:info>
</doc:sap-metadata>
</doc:metadata>
<doc:content>
<!-- a lot of text content here... -->
</doc:content>
</doc:entity>
Код поиска (первый разрез):
В поисковом коде нет ничего умного; просто стандартный поиск: поисковый вызов с поисковым запросом и (по крайней мере, одно ограничение - для ясности я придерживаюсь простого случая):
search:search(fn:concat("relevant:1 ", $search-term), $search-options)
$search-term
- это поиск в открытом тексте, предоставляемый пользователем. $search-options
- довольно много xml, но я не думаю, что он содержит что-то экзотическое; просто набор ограничений и определений фасетов и настраиваемый фрагмент, сгенерированный:
declare function func:do-snippet(
$result as node(),
$ctsquery as schema-element(cts:query),
$options as element(search:transform-results)?
) as element(search:snippet)
{
element search:snippet{
element search:match {
fn:doc(xdmp:node-uri($result))/doc:entity/doc:metadata/doc:sap-metadata/doc:info/doc:id,
fn:doc(xdmp:node-uri($result))/doc:entity/doc:metadata/doc:sap-metadata/doc:info/doc:number
}
}
};
Код поиска (второй разрез):
Здесь используется лексика-значение-элемента для идентификатора, чтобы сгенерировать список идентификаторов, которые соответствуют поисковому запросу (без фильтров, очевидно), а затем использовать этот идентификатор для запроса номера документа:
let $query := ...
let $options := ...
for $id in cts:element-values(fn:QName("http://my.document.namespace", "id"), (), (), cts:query(search:parse($query, $options)))
return element document {
attribute id {$id},
attribute number {
cts:element-values(fn:QName("http://my.document/namespace", "number"), (), (), cts:element-value-query(fn:QName("http://my.document.namespace", "id"), $id ))
}}
Этот первый cts:element-values
вызов возвращается красиво и быстро, но повторение ответа и выполнение еще cts:element-values
для каждого из них очень медленно.