Выражение пути в MarkLogic cts.search

#marklogic

#marklogic

Вопрос:

У меня сложилось впечатление, что XQuery и серверные JavaScript-API в MarkLogic в значительной степени эквивалентны. Но, похоже, в cts:search vs cts.search есть большая разница. В cts:search я могу указать элемент, который будет найден и возвращен. Например, я могу получить все рецепты, использующие циннаомон в качестве ингредиента, из книги рецептов:

 cts:search(//recipe, cts:element-word-query(xs:QName('ingredients'), 'cinnamon'))
  

В то время как cts.search не принимает выражение пути и вернет документ книги рецептов целиком:

 cts.search(cts.elementWordQuery(xs.QName('ingredients'), 'cinnamon'))
  

Тот же вопрос был задан в списке рассылки MarkLogic, но я не вижу там ответа: https://developer.marklogic.com/pipermail/general/2015-March/016508.html

Ниже приведен минимальный пример:

 <book>
  <recipe>
    <ingredients>cinnamon, peppermint</ingredients>
    <instruction/>
  </recipe>
  <recipe>
    <ingredients>sugar, peppermint</ingredients>
    <instruction/>
  </recipe>
  <recipe>
    <ingredients>coconut oil</ingredients>
    <instruction/>
  </recipe>
</book>
  

Xquery будет:

 cts:search(//recipe, cts:element-word-query(xs:QName('ingredients'), 'cinnamon'))
  

и ответ:

 <recipe>
  <ingredients>cinnamon, peppermint</ingredients>
  <instruction></instruction>
</recipe>
  

Ответ №1:

Существуют технические причины, почему это так. cts:search Функция в XQuery на самом деле не функция, а специальная форма, имеющая функциональный синтаксис. Это означает, что первый аргумент на самом деле не вычисляется, а затем не передается в функцию (если вы подумаете об этом, это был бы очень неэффективный способ продолжения!). В Javascript cts.search функция является реальной функцией. Чтобы избежать неэффективности, мы удалили первый параметр, поэтому вам нужно извлечь из результата ту часть, которая вас интересует.

Если вы хотите ограничить набор результатов теми, которые находятся внутри элемента recipe , завершите свой запрос символом cts:element-query(xs:QName("recipe"), $your-query)

Комментарии:

1. Спасибо за ваш быстрый ответ! Я вижу, как использовать, cts.elementQuery чтобы ограничить область поиска recipe узлом. Но оно по-прежнему возвращает весь документ вместо единственных совпадающих узлов. Предположим, что в моей кулинарной книге 1000 рецептов, и только в нескольких из них используется корица, как получить соответствующие рецепты в последовательности?

2. @FanLi, не могли бы вы поделиться со мной примером книги рецептов, содержащей элемент «ингредиенты»

3. Привет @AkbaraLI, я добавил пример в свой вопрос. Спасибо за предложение.

Ответ №2:

Это должно приблизить вас

https://docs.marklogic.com/cts.elementQuery

Применяется с помощью cts.andQuery по мере необходимости.

В значительной степени верно, что интерфейсы JS и XQuery функционально эквивалентны, но есть несколько мест (это одно из них), где сам язык напрямую не поддерживает эквивалентность. Другое — последовательности XQuery, которые не имеют собственного эквивалента в JS, поэтому предоставляются через дополнительные классы JS.

Любой запрос cts (сложный) может быть сконструирован из примитивных объектов / методов запроса cts. Первым параметром в XQuery cts::search() является ‘выражение с возможностью поиска’, которое по сути является тем же самым, что и ограничивающая область — может быть объединено с cts.andQuery для получения того же эффекта (как в XQuery, так и в JS). В зависимости от того, какое именно выражение вы использовали в XQuery, вам нужно найти для него эквивалентный cts.query для JS (или xquery).

Отсюда cts.elementQuery, который аналогичен cts::search(//имя элемента, ..)

Комментарии:

1. Спасибо за ваше объяснение! У меня все еще есть некоторые сомнения, как и в моем ответе на ответ @mholstege.

Ответ №3:

Учитывая, что в javascript-версии cts:search() отсутствует первый параметр версии xquery’, я не понимаю, как он может возвращать что-либо, кроме узлов документа. Оптимизации индексации, которые используют cts:search и cts.search, имеют степень детализации «фрагментов» (обычно документов) — предназначены для поиска нескольких совпадающих документов из потенциально неограниченного набора. Оттуда вам нужно перейти к структуре документа. XQuery особенно хорош в этом — обход пути является родным для языка, JavaScript не так сильно.

Я предлагаю вам использовать search.search вместо cts: search — это API более высокого уровня, предназначенный для упрощения подобных задач.

Ответ №4:

Основываясь на ответе ДАЛДЕЯ, вы можете использовать search api для возврата только элементов рецепта:

 const search = require('/MarkLogic/appservices/search/search');

let options = fn.head(xdmp.unquote(`
<options xmlns="http://marklogic.com/appservices/search">
  <return-results>true</return-results>
  <searchable-expression>//recipe</searchable-expression>
  <extract-document-data>all</extract-document-data>
  <additional-query>
    <cts:element-word-query xmlns:cts="http://marklogic.com/cts">
      <cts:element>ingredients</cts:element>
      <cts:text xml:lang="en">cinnamon</cts:text>
    </cts:element-word-query>
  </additional-query>
</options>`)).root;

search.search("", options)        // returns a Sequence of search:response
  .toArray()[0]                   // get the first result
  .getElementsByTagName("recipe") // find all recipe elements 
  

Этот код возвращает список узлов элементов рецепта. Результатом для предоставленной вами книги будет этот одноэлементный узел:

 <recipe xmlns:search="http://marklogic.com/appservices/search">
  <ingredients>cinnamon, peppermint</ingredients>
  <instruction/>
</recipe>
  

На самом деле это не очень хорошее решение (с точки зрения быстроты и простоты), но оно может сработать как обходной путь.

Я также пытался использовать функции jsearch, но не нашел способа передать searchable-expression параметр. Возможно, я пропустил это, потому что я еще не использовал это много.

Дальнейшие чтения:

Ссылка на параметры запроса
поиск:поиск

Комментарии:

1. Спасибо! Это решение генерирует требуемые результаты.