在marklogic中动态排序结果

Stu*_*Bob 2 xquery dynamic marklogic

所以,这是我的问题 -
我想根据一组确定排序字段和顺序的变量来排序列表

本质上我需要动态地"按顺序".

例如:

    declare function getSearchResults(
        $query as cts:query,
        $sort as xs:string*,
        $direction as xs:string*,    
) as element()*  {

        let $results := 
        cts:search(/*, $query)

        let $sortFields := fn:tokenize($sort, "\|")
        let $dec := $direction = 'desc' or $direction = 'descending'
        let $sorted := sortByFields($results, $sort,$dec)

        return $sorted
};


declare private function sortByFields ($results, $sortFields, $dec)
{
let $asc := fn:not($dec)
for $i in $results

order by

    if ($sortFields[1]='id' and $asc) then $i//ldse:document/@id else (),
    if ($sortFields[1]='id' and $dec) then $i//ldse:document/@id else () descending,

    if ($sortFields[1]='title' and $asc) then $i//title else (),
    if ($sortFields[1]='title' and $dec) then $i//title else () descending

return if (fn:count($sortFields) > 1 ) then (sortByFields($i,$sortFields[2 to fn:count($sortFields)],$dec)) else ($i)
};
Run Code Online (Sandbox Code Playgroud)

此方法不起作用,因为它必须多次排序,并且不会在每次迭代时保留排序顺序.

我也试过这个:

let $sortFields := fn:tokenize($sort, "\|")
let $dec := $direction = 'desc' or $direction = 'descending'
let $asc := fn:not($dec)
for $i in $results
    for $j in 1 to fn:count($sortFields)

    order by

        if ($sortFields[$j]='id' and $asc) then $i//ldse:document/@id else (),
        if ($sortFields[$j]='id' and $dec) then $i//ldse:document/@id else () descending,

        if ($sortFields[$j]='title' and $asc) then $i//title else (),
        if ($sortFields[$j]='title' and $dec) then $i//title else () descending

return $i
Run Code Online (Sandbox Code Playgroud)

但这会重复我的数据.(按每个排序字段返回它)

我宁愿不使用xdmp:eval因为代码注入,有什么方法可以做到这一点吗?

任何帮助或建议将不胜感激.

谢谢你!

DAL*_*DEI 5

需要考虑的几件事情.如果您正在对cts:search()的结果进行排序,则必须先返回所有结果,然后才能对它们进行排序.这意味着你不能做有效的分页.例如,如果你有一百万行并想要前100名...如果你动态订购它,那么你必须获取100万行.如果这是一个问题,则需要更复杂的解决方案.

实现明智,这是使用函数项的好例子......但是为了使升序/降序工作需要静态分析.或者,它可以始终是升序(或降序),但值为正/负.例如

for $r in cts:search(...) 
order by myfunc($r, $criteria)
return $r

declare function myfunc( $r , $criteria ) as xs:double
{
  ... logic to order $r in a natural ordering of -inf ... +f..
  return $ordering
};
Run Code Online (Sandbox Code Playgroud)

但在深入研究之前,我建议先查看搜索:search().

http://docs.marklogic.com/search:search#opt-sort-order

这有一些非常强大的功能,包括能够将复杂的排序定义为xml元素.

最终要有效地进行自定义排序,您可能需要创建范围索引,以便可以在服务器本身而不是代码中完成排序.对于小型数据集来说,它不是一个大问题,但是当你开始搜索数千,数十万或数百万个文档时,你无法在每次搜索时将它们全部存入内存(或者即使你可能会很慢).不仅必须将结果全部拉入内存以开始排序,而且必须针对每个术语评估xquery代码.使用索引,结果集通常可以直接在右侧返回,甚至无需加载文档.

您可以使用其他技术,例如将结果加载到地图或数组中,创建自排序树结构,预先创建数据的自定义子集等.

首先看一下搜索:搜索库...您甚至可以定义自己的搜索语法,供用户输入,所有类型和注入安全,并且多年来非常优化.