0

かなり複雑なプログラムで構築されたsearch:search callを使用して検索されている、何万もの大規模で複雑な(小さいものもありますが、大きいものは10MB以上)ドキュメントを含むmarklogic(4.2)データベースがあります。 。通常の使用では、ページネーションを使用して一度にいくつかの結果を返し、一致のスニペットを生成すると、正常に機能します。これで、クライアント開発者の1人は、DB内のすべてのドキュメントを返すクエリを作成した場合でも、そのクエリからすべての結果を一度に返す必要があります。しかし、彼は試合の内容のほとんどを気にしません。いくつかのID要素(1つは数値、もう1つはフリーテキスト)であり、どちらもインデックスが付けられており、両方ともドキュメント内の同じxpathに常にあります。

重要なのは、これほど大きなデータセット全体で2つの要素をクエリする効率的な方法を思い付くことができないということです。常にドキュメント全体をロードする必要があり、クエリは長い草の中に消えて数万回実行され、基本的には返されません。

検索によってフィルタリングされた要素の1つで要素値レキシコンを使用してみました。これはすぐに返されますが、いくつかの欠点があります。*誤検知が返されます。これは必ずしも取引を妨げるものではありませんが、最適ではありません。*要素の1つだけを取得します。そのリストを繰り返して、彼が興味を持っている他の要素をフェッチしようとすると、当然のことながら、それは永遠にかかります(すべての一致に対してドキュメント全体のロードに戻るため)。

これらの2つの要素を含むフィールドを宣言すると役立つかどうか疑問に思いました(1つのIDを取得するためだけにドキュメント全体をロードするのではなく、レキシコンを使用して値の1つを取得し、フィールドでそれを探すことができます)。しかし、私はこれまでフィールドを使用したことがなく、フィールドは常に単語クエリであり、要素フィールドではないように見えます。これは、フィールドで行う必要のある種類のことには理想的ではありません。

また、両方のIDのエンコードされた形式を含む新しい要素をドキュメントに作成すると、両方を含む1つのインデックスを作成し、上記のレキシコンアプローチを使用して、少なくとも一致するドキュメントに絞り込むことができると思いました。フィルタリングされていない検索。しかし、それはかなりハッキーなアプローチのように感じます。

私が本当に探しているのは、「これが検索です。これが私が興味を持っている(インデックス付けされた)要素です。一致するドキュメントの値を取得します」と言う方法です。それを行う方法はありますか?

答えは「ノー」だと思いますが、聞いてみる価値はあります。

ない場合、どの代替アプローチが最も効果的かについて誰かが提案を持っていますか?

ありがとう。


ドキュメント形式の例:

<doc:entity>
  <doc:metadata>
    <doc:sap-metadata>
      <doc:info>
        <doc:id>12345678</doc:id>
        <doc:number>AS-1990 13:45</doc:number>
        <!-- more document info here -->
      </doc:info>
    </doc:sap-metadata>
  </doc:metadata>
  <doc:content>
    <!-- a lot of text content here... -->
  </doc:content>
</doc:entity>

検索コード(ファーストカット):

検索コードは巧妙なものではありません。ただの標準的なsearch:検索語を含む検索呼び出しと(少なくとも1つの制約-明確にするために単純なケースに固執しています):

search:search(fn:concat("relevant:1 ", $search-term), $search-options)

$search-termユーザーが提供するプレーンテキスト検索です。$search-optionsかなり多くのxmlですが、エキゾチックなものは含まれていないと思います。以下によって生成された、制約とファセットの定義およびカスタムスニペットの束です。

declare function func:do-snippet(
  $result as node(),
  $ctsquery as schema-element(cts:query),
  $options as element(search:transform-results)?
) as element(search:snippet)
{
  element search:snippet{
    element search:match {
      fn:doc(xdmp:node-uri($result))/doc:entity/doc:metadata/doc:sap-metadata/doc:info/doc:id,
      fn:doc(xdmp:node-uri($result))/doc:entity/doc:metadata/doc:sap-metadata/doc:info/doc:number
    }
  }
};

検索コード(セカンドカット):

これは、idのelement-value-lexiconを使用して、検索語に一致するIDのリストを生成し(明らかにフィルター処理されていない)、そのIDを使用してドキュメント番号を照会します。

let $query := ...
let $options := ...
for $id in cts:element-values(fn:QName("http://my.document.namespace", "id"), (), (), cts:query(search:parse($query, $options)))
  return element document {
    attribute id {$id},
    attribute number {
      cts:element-values(fn:QName("http://my.document/namespace", "number"), (), (), cts:element-value-query(fn:QName("http://my.document.namespace", "id"), $id ))
    }}

その最初のcts:element-values呼び出しは素晴らしく迅速に返されますが、応答を繰り返し、cts:element-valuesそれぞれに対して別の呼び出しを行うのは非常に時間がかかります。

4

1 に答える 1

1

試すことができるアプローチがいくつかあります: ストリーミング結果、共起、およびエンコードされたレキシコン値。

エンコードされたレキシコンの値についてはすでに触れましたが、それが最も効率的なアプローチだと思います。ハックのように感じるかもしれませんが、関数ベースのインデックスと同等の道徳的機能です。適切にスケーリングする必要があります。

また、範囲インデックスとレキシコン関数を使用すると、cts:element-value-co-occurrences. これは、エンコードされた値ほどにはスケーリングされませんが、前もって行う作業は少なくなります。「マップ」オプションも考慮してください: http://docs.marklogic.com/cts:element-value-co-occurrences

最後に、開発者が望むものを単純に与えることができます。search:parse通常どおりクエリを解析するか、コンストラクタを使用してクエリを構築するために使用しcts:queryます。cts:search次に、一致するノードを取得して返すために呼び出します。結果は大きくなりますが、それは避けられません。XDMP-EXPNTREECACHEFULLエラーが発生する場合があります: http://blakeley.com/blogofile/2012/03/19/let-free-style-and-streaming/を参照してください。両側で多少のトリッキーなコーディングが必要になる場合がありますが、これにより、任意の大きな結果シーケンスを返すことができます。

于 2012-09-24T14:27:25.117 に答える