1

XQuery ベースの XML データベース内に多数のレコードがあるとします。

<widgets>
   <widget id="1" name="Foo Widget" price="19.99" />
   <widget id="2" name="Bar Widget" price="29.99" />
   <widget id="3" name="Baz Widget" price="39.99" />
   <!-- etc. -->
</widget>

「多数」とは、100 万以上を意味します。

XQuery を使用して、リストから 1 つの項目をランダムに取得したいとします。

let $widgets := for $widget in //widgets/widget
  order by util:random()
  return $widget

for $val in subsequence($widgets, 1, 1)
  return $val

レコードの数が増えると、データベースからすべてをロードしてメモリ内で並べ替えるように見えるため、評価の実行に膨大な時間がかかります。それはO(n log 2n)かもしれないと思います。ため息が出るほどの遅さ。

これを行うための怠惰でより良い方法はありますか?

「アイテムの数を数えてから、ゼロからカウントまでの数をランダムに選択する」方法がありますが、これは避けたいと思います。

理想的には、次のような機能があれば、データベースがそれを実行できます。

let $widgets := for $widget in //widgets/widget
  order by util:random()
  limit 1
  return $widget

これはFLOLWRでしょうね。しかし、SQL (または実際には SPARQL やその他の多くのクエリ言語) では十分に一般的なことですが、XQuery 仕様には含まれていません。

これを取得する方法はありますか?where 句を追加すればそれは可能ですが、where 句は order 句の前に評価されるため、あまり役に立ちません。

助言がありますか?(XQuery を送信するアプリケーションは Java で作成されており、XML データベースは eXist です。それが少しばかりのカーブボール的で突飛なアイデアに役立つ場合)。

4

1 に答える 1

3

中間変数を使用しない場合、オプティマイザーはより良い仕事をするかもしれませんが、それは大きな可能性があります。

subsequence(
 for $widget in //widgets/widget
  order by util:random()
  return $widget
 ,1,1)

「避けたい方法」の方がパフォーマンスが良いと思いますが、その証拠はベンチマークにあります。

//widgets/widget[util:random(count(//widgets/widget))]
于 2011-08-30T17:25:51.130 に答える