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

Мне пришлось добавить возможность гео-пространственного поиска к уже существующему приложению, которое использует search:search API и имеет полнотекстовый поиск и граненый поиск. Я читал о расширении API поиска, но сейчас у меня просто нет времени. Итак, я подумал, что я адаптирую свой код для того, чтобы просто пересекать два набора результатов (один возвращен поиском: поиск API, а другой - возвращен 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;

4 ответа

Решение

В качестве сноски к хорошему совету Дейва другой альтернативой будет использование search: parse () вместо search: search () для преобразования второго поискового запроса в запрос cts: перед запуском 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("*") в геопространственном запросе, но это не имеет отношения к основному вопросу.

Ленти, предикат 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 - это путь к модулю библиотеки, где определена ваша функция синтаксического анализа.

Ресурсы:

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

НТН!

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

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 нужен обзор. Для меня это похоже на проблемы с производительностью, ожидающие своего появления.

Другие вопросы по тегам