2

这是一个新手 MarkLogic 问题。想象一下这样的 xml 结构,浓缩了我的真实业务问题:

<Person id="1">
  <Name>Bob</Name>
  <City>Oakland</City>
  <Phone>2122931022</Phone>
  <Phone>3123032902</Phone>
</Person>

请注意,一个文档可以并且将会有多个Phone元素。

我需要从每个具有与任何电话号码列表匹配的电话元素的文档中返回信息。该列表中可能有几十个电话号码。

我试过这个:

let $a := cts:word-query("3738494044")
let $b := cts:word-query("2373839383") 
let $c := cts:word-query("3933849383") 
let $or := cts:or-query( ($a, $b, $c) )
return cts:search(/Person/Phone, $or)

它会正确执行查询,但它会在 Results 元素内返回一系列Phone元素。我的目标是为每个匹配的文档返回所有NameCity元素以及来自 Person 元素的 id 属性。例子:

<results>
  <match id="18" phone="2123339494" name="bob" city="oakland"/>
  <match id="22" phone="3940594844" name="mary" city="denver"/>
etc...
</results>

所以我认为我需要某种形式cts:search,既允许这种布尔功能,又允许我指定每个文档的哪些部分被返回。那时我可以进一步处理结果XPATH。我需要有效地执行此操作,例如,我认为返回文档 uri 列表然后在循环中查询每个文档的效率不高。谢谢!

4

2 回答 2

5

你的方法并不像你想象的那么糟糕。只需进行一些更改即可使其按您喜欢的方式工作。

首先,你最好使用cts:element-value-query而不是cts:word-query. 它将允许您将搜索值限制为特定元素。当您为该元素添加元素范围索引时,它的性能最佳,但这不是必需的。它也可以依赖始终存在的单词索引。

其次,不需要cts:or-query. cts:word-querycts:element-value-query函数(以及所有其他相关函数)都接受多个搜索字符串作为一个序列参数。它们被自动视为or-query

第三,电话号码是结果中的“主键”,因此返回所有匹配电话元素的列表要走的路。您只需要意识到生成的 Phone 元素仍然知道它们来自哪里。您可以轻松地使用XPath导航到父母和兄弟姐妹。

第四,没有什么反对循环搜索结果。这听起来可能有点奇怪,但它不会花费太多额外的性能。实际上,在 MarkLogic Server 中几乎可以忽略不计。当您尝试返回许多结果(超过数千个)时,大多数性能可能会丢失,在这种情况下,大部分时间都浪费在序列化所有结果中。如果您可能需要处理大量搜索结果,明智的做法是立即开始使用分页。

要获得您的要求,您可以使用以下代码:

<results>{
    for $phone in
        cts:search(
            doc()/Person/Phone,
            cts:element-value-query(
                xs:QName("Phone"),
                ("3738494044", "2373839383", "3933849383")
            )
        )
    return
        <match id="{data($phone/../@id)}" phone="{data($phone)}" name="{data($phone/../Name)}" city="{data($phone/../City)}"/>
}</results>

祝你好运。

于 2011-09-23T20:44:11.133 回答
3

这是我要做的:

let $numbers := ("3738494044", "2373839383", "3933849383")
return
<results>{
    for $person in cts:search(/Person, cts:element-value-query(xs:QName("Phone"),$numbers))
    return
    <match id="{data($person/@id)}" name="{data($person/Name)}" city="{data($person/City)}">
      {
        for $phone in $person/Phone[cts:contains(.,$numbers)]
        return element phone {$phone}
      }
    </match>

}

首先,在将多个值传递给word-queryvalue-query及其表亲时存在隐式 OR ,并且此查询更有效地从索引中解析,因此请尽可能执行此操作。

其次,一个人可能会匹配多个电话号码,因此您需要额外的内部循环来有效地按个人分组。

我不会为此创建范围索引 - 不需要,也不一定更快。默认情况下有元素值的索引,因此您可以利用这些索引element-value-query

SearchAPI你可以用and做所有这些XSLT。这将使在单个查询中开始组合名称和数字以及其他条件变得容易。

于 2011-09-23T21:26:25.847 回答