2

これは、MarkLogicの初心者向けの質問です。このようなxml構造を想像してみてください。これは、私の実際のビジネス上の問題の凝縮です。

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

ドキュメントには複数のPhone要素を含めることができます。

電話番号のリストのいずれかに一致する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要素を返します。代わりに、一致するすべてのドキュメントについて、Person要素からid属性とともにすべてのName要素とCity要素を返すことが私の目標です。例:

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

したがって、このブールcts:search機能の両方を可能にするだけでなく、各ドキュメントのどの部分が返されるかを指定できるような形式が必要だと思います。その時点で、結果をさらに処理することができます。これを効率的に行う必要があるので、たとえば、ドキュメントURIのリストを返し、ループ内の各ドキュメントをクエリするのは効率的ではないと思います。ありがとう!XPATH

4

2 に答える 2

5

あなたのアプローチはあなたが思うほど悪くはありません。好きなように動作させるために必要な変更はわずかです。

まず、のcts:element-value-query代わりにを使用することをお勧めしますcts:word-query。これにより、検索された値を特定の要素に制限できます。その要素の要素範囲インデックスを追加すると最高のパフォーマンスを発揮しますが、必須ではありません。常に存在する単語インデックスにも依存できます。

第二に、の必要はありませんcts:or-querycts:word-queryおよび関数(および他のcts:element-value-queryすべての関連関数)は、1つのシーケンス引数として複数の検索文字列を受け入れます。それらは自動的にor-queryとして扱われます。

第三に、電話番号は結果の「主キー」であるため、一致するすべての電話要素のリストを返すこと方法です。結果として得られるPhone要素は、それらがどこから来たのかをまだ認識していることを理解する必要があります。XPath親と兄弟に簡単に移動できます。

第4に、検索結果をループすることに反対するものは何もありません。少し奇妙に聞こえるかもしれませんが、それほど余分なパフォーマンスは必要ありません。実際、MarkLogicサーバーではほとんど無視できます。多くの結果(数千を超える)を返そうとすると、ほとんどのパフォーマンスが失われる可能性があります。その場合、すべてをシリアル化するときにほとんどの時間が失われます。また、多くの検索結果を処理する必要がある可能性が高い場合は、すぐにページネーションの使用を開始することをお勧めします。

あなたが求めるものを手に入れるために、あなたは次のコードを使うことができます:

<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と少しでこれらすべてを行うことができますXSLT。これにより、名前と番号、およびその他の条件を1つのクエリで簡単に組み合わせることができます。

于 2011-09-23T21:26:25.847 に答える