Пересечение набора результатов search:search с набором результатов cts:search, в котором использовался геопространственный поиск cts:polygon.

Мне пришлось добавить возможность геопространственного поиска в уже существующее приложение, которое использует поиск: API поиска и имеет полнотекстовый поиск и фасетный поиск. Я читал о расширении API поиска, но сейчас у меня просто нет времени. Итак, я подумал, что адаптирую свой код, чтобы просто выполнить пересечение двух наборов результатов (один возвращается API-интерфейсом search:search, а другой возвращается cts:search, который позволяет cts:polygon искать). К сожалению, пересечение сильно снижает время выполнения. Есть ли лучший способ оптимизировать или ускорить следующее выражение ниже?

$results_fts//search:result[./search:metadata/Vhe eq $geo_results//root/Vhe]

Вот мой код:

declare variable $geo_results := 
let $qr := cts:search(doc(), cts:and-query(($q-geospatial,
            cts:word-query("*", ("case-insensitive","whitespace-insensitive","wildcarded","diacritic-insensitive"))   ))   )  (:Search all * within the polygon:)
return $qr;

declare variable $results_fts := 
let $qrs := search:search($q-text, $options, xs:unsignedLong(xdmp:get-request-field("start","1")), 12000)  (:max page length to get all records:)
return $qrs;

declare variable $results := 
let $qrt := if (xdmp:get-request-field("map-code")) then 
(:intersect geospatial search with the full text search:)
                <search:response>
                  { $results_fts//search:result[./search:metadata/Vhe eq $geo_results//root/Vhe] } 
                  { $results_fts//search:facet }
                  { $results_fts//search:qtext }
                  { $results_fts//search:metrics }
                </search:response>
          else $results_fts
return $qrt;

person Lenti Pacurar    schedule 05.03.2015    source источник


Ответы (4)


В качестве примечания к хорошему совету Дейва другой альтернативой может быть использование search:parse() вместо search:search() для преобразования второго поискового запроса в cts:query перед запуском cts:search().

http://docs.marklogic.com/search:parse?q=search:parse&v=8.0&api=true

Затем добавьте сгенерированный cts:query() search:parse() в список подзапросов в существующем cts:and-query() и запустите одиночный поиск.

Мне непонятно, что делает предложение cts:word-query("*") в геопространственном запросе, но это не имеет отношения к главному.

person ehennum    schedule 05.03.2015
comment
Спасибо, ребята, за ваш ценный вклад! Я сделаю все возможное, чтобы попробовать каждый вариант, предложенный здесь, и позже приму один из ответов. Все ответы полезны. - person Lenti Pacurar; 09.03.2015

Ленти, предикат XPath, который вы используете, сравнивает каждый поиск: результат Vhe с каждым $geo_results Vhe — потенциально много работы, в зависимости от того, сколько гео-результатов найдено. Я думаю, вы, возможно, переоцениваете объем работы, который потребуется для расширения API поиска. Если вы пойдете по этому пути, MarkLogic может выполнить оптимизацию за вас.

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

declare function geo:parse(
  $constraint-qtext as xs:string, 
  $right as schema-element(cts:query))
as schema-element(cts:query)
{
  (: TODO: you don't show above how you construct the geospatial query,
   : but do that here using $right//cts:text as input. 
   :)
  (: If MarkLogic complains that your geospatial query doesn't match
   : the return type, you probably need to serialize it like this: 
       return <root>{$q-geospatial}</root>/*
   :) 
};

Вы также устанавливаете ограничение в параметрах API поиска:

<constraint name="my-custom">
  <custom facet="false">
   <parse apply="parse" ns="..." at="..." />
  </custom>
</constraint>

... где ns - это пространство имен, для которого "geo:" является префиксом выше, а at - это путь к библиотечному модулю, в котором определена ваша функция синтаксического анализа.

Ресурсы:

person Dave Cassel    schedule 05.03.2015

И в дополнение к предложениям Дейва и Эрика вы также можете сделать обратное тому, что предложил Эрик: взять cts:query из cts:search и встроить его как дополнительный запрос в параметры поиска для search:search. Для этого вы можете воссоздать $options во время выполнения. Таким образом, вы сможете использовать все возможности, предоставляемые библиотекой поиска.

ХТХ!

person grtjn    schedule 05.03.2015

Вот поворот идей, предложенных Гертом и Эриком. Я думаю, что это минимизирует изменения в вашем существующем коде.

declare variable $Q-GEO :=
  cts:and-query(
    ($q-geospatial,
     (: TODO This smells funny. :)
     cts:word-query(
       "*",
       ("case-insensitive", "whitespace-insensitive", "wildcarded",
        "diacritic-insensitive")) )) ;

declare variable $Q-FT := cts:query(search:parse($q-text, $options)) ;

search:resolve(
  document { cts:and-query(($Q-GEO, $Q-FT)) }/*,
  $options,
  xs:unsignedLong(xdmp:get-request-field("start", "1")),
  (: TODO Rarely a good idea to fetch so many records :)
  12000)

Я согласен с предыдущими комментариями, что word-query * и 12000 нуждаются в пересмотре. Для меня это выглядит как проблемы с производительностью, которые ждут своего часа.

person mblakele    schedule 05.03.2015