根据“搜索开发者指南”: 每个约束都被命名,并且名称在选项节点中的所有运算符和约束中必须是唯一的。
我们正在使用内容丰富包来生成如下输出:
`<TM360:Measurements Measurements="Distance">
<Measurements:Distance Amount="3" Unit="inches"/>
</TM360:Measurements>
<TM360:Measurements Measurements="Volume">
<Measurements:Volume Amount="5.0" Unit="liters"/>
</TM360:Measurements>`
查看“金额”: localName属性不是唯一的,但包含它的元素是唯一的。
是否有办法绕过约束名称唯一性限制来构建约束搜索,例如“Amount:5.0”,其中包括上述两个条目的索引?
处理这种情况的最佳方法是什么?
答案 0 :(得分:2)
为获得最佳效果,您必须重构或丰富该XML。搜索API旨在充分利用MarkLogic的索引功能,这些功能基于QNames。您今天拥有的XML有一个元素QName:TM360,以及一些属性QNames,其中没有一个是强选择性的。
您可以使用XSLT或递归转换来重新格式化该XML。我建议你定位这样的东西:
<dist:inches xmlns:dist="ns://fubar.distance">3</dist:inches>
<vol:liters xmlns:vol="ns://fubar.volume">5.0</vol:liters>
作为副作用,这使您可以编写更简洁的XPath查询,并为您的节点提供更具体的模式类型。
这个用例可能是设计的,但您可能还想考虑将所有这些测量标准化为SI单位的标准子集,例如http://en.wikipedia.org/wiki/Cgs,以便比较更容易。
答案 1 :(得分:2)
您可以创建自定义约束来实现此目的。我使用以下三个脚本成功完成了此操作:
这是设置脚本,它创建了两个&#34; Amount&#34;范围索引并添加几个示例文档(test1.xml和test2.xml):
xquery version "1.0-ml";
import module namespace admin = "http://marklogic.com/xdmp/admin" at "/MarkLogic/admin.xqy" ;
declare namespace TM360 = "http://example.com/TM360";
declare namespace Measurements = "http://example.com/Measurements";
declare function local:make-amount-index($parent-name) {
admin:database-range-element-attribute-index(
(: data type :) "decimal",
(: parent name :) "http://example.com/Measurements",$parent-name,
(: attribute name :) "", "Amount",
(: collation :) "",
(: value positions :) false()
)
};
(: Set up the indexes (or you can add these via the Admin UI) :)
let $dbid := xdmp:database(),
$rangespec1 := local:make-amount-index("Distance"),
$rangespec2 := local:make-amount-index("Volume"),
$config := admin:get-configuration(),
$config := admin:database-add-range-element-attribute-index($config, $dbid, $rangespec1),
$config := admin:database-add-range-element-attribute-index($config, $dbid, $rangespec2)
return
admin:save-configuration($config)
,
(: Add some sample docs :)
xdmp:document-insert("/test1.xml",
<TM360:Measurements Measurements="Distance">
<Measurements:Distance Amount="3" Unit="inches"/>
</TM360:Measurements>),
xdmp:document-insert("/test2.xml",
<TM360:Measurements Measurements="Volume">
<Measurements:Volume Amount="5.0" Unit="liters"/>
</TM360:Measurements>)
下面是search.xqy,它进行了两次搜索:
search:search("Amount:3",$options)
search:search("Amount:5",$options)
特别注意$ options节点,它定义了自定义约束:
xquery version "1.0-ml";
import module namespace search="http://marklogic.com/appservices/search"
at "/MarkLogic/appservices/search/search.xqy";
declare variable $options :=
<options xmlns="http://marklogic.com/appservices/search">
<constraint name="Amount">
<custom facet="false">
<parse apply="parse-amount"
ns="http://example.com/custom-constraint"
at="/custom-constraint/custom-constraint.xqy">
</parse>
</custom>
</constraint>
</options>;
(: matches test1.xml :)
search:search("Amount:3",$options),
(: matches test2.xml :)
search:search("Amount:5",$options)
最后,这里是自定义约束.xqy代码,它将约束文本转换为跨两个Amount索引的cts OR查询:
xquery version "1.0-ml";
module namespace my = "http://example.com/custom-constraint";
declare namespace Measurements = "http://example.com/Measurements";
declare default function namespace "http://www.w3.org/2005/xpath-functions";
(: Convert the constraint text into an OR query against "Distance" and "Volume" :)
declare function my:parse-amount($constraint-qtext as xs:string,
$right as schema-element(cts:query))
as schema-element(cts:query)
{
let $value := xs:decimal($right//cts:text)
return
<cts:or-query>{
my:make-amount-query("Distance",$value),
my:make-amount-query("Volume" ,$value)
}</cts:or-query>
};
declare function my:make-amount-query($parent-name, $value) {
cts:element-attribute-range-query(
(: parent name :) QName("http://example.com/Measurements", $parent-name),
(: attribute name :) xs:QName("Amount"),
(: operator :) "=",
(: value :) $value
)
};
如果您希望约束也作为构面运行,那么您还需要实现start-facet和finish-facet函数(并相应地增加选项节点中的定义。{{3} }包括如何执行此操作的示例。
答案 2 :(得分:1)
使用cts函数会相对简单。你可以这样做:
declare namespace Measurements = "http://example.com/Measurements";
cts:search(doc(), cts:element-attribute-value-query(
(xs:QName("Measures:Distance"), xs:QName("Measures:Volume")),
xs:QName("Amount"),
$myamount
))
幸运的是,您也可以将其表示为MarkLogic 8.0-5中的单个搜索约束,并将其与search:search
或(现在)内置的REST API一起使用:
xquery version "1.0-ml";
declare namespace TM360 = "http://example.com/TM360";
declare namespace Measurements = "http://example.com/Measurements";
xdmp:document-insert(
"/amount3.xml",
<TM360:Measurements Measurements="Distance">
<Measurements:Distance Amount="3" Unit="inches"/>
</TM360:Measurements>
),
xdmp:document-insert(
"/amount5.xml",
<TM360:Measurements Measurements="Volume">
<Measurements:Volume Amount="5.0" Unit="liters"/>
</TM360:Measurements>
)
;
import module namespace search="http://marklogic.com/appservices/search"
at "/MarkLogic/appservices/search/search.xqy";
declare variable $options :=
<options xmlns="http://marklogic.com/appservices/search">
<constraint name="Amount">
<value>
<element ns="http://example.com/Measurements" name="Distance"/>
<element ns="http://example.com/Measurements" name="Volume"/>
<attribute ns="" name="Amount"/>
</value>
</constraint>
</options>;
(: matches /amount3.xml :)
search:search("Amount:3",$options),
(: matches /amount5.xml :)
search:search("Amount:5.0",$options)
如果您有所有元素属性组合的范围索引,您还可以使用范围约束,如Evan建议的那样。
HTH!