1

ドキュメントの (適度に複雑な) セクションがデータベースで変更されたときに、古い値と新しい値の違いを保存するというログ要件があります。変更されたデータのみを報告する必要があります。現在のソリューションはかなりうまく機能しますが、最適ではなく、更新が大量に発生し始めるとパフォーマンスの問題が発生する可能性があるという懸念があります。

私の現在のソリューションは、主に次のようになります。

for $element in $data/section//element()[text()]
return
  if (not($old-data//*[fn:name() = fn:name($element) and text() = $element/text()])) then
    element log:difference {
       ...
    }
  else ()

//*[fn:name() = fn:name($element)]私の問題は、コンストラクトがもたらす何千もの比較を行うと、(比較的) 長い時間がかかることをプロファイラーが示していることです。ほんの数十ミリ秒ですが、多くの更新が追加されるため、それを回避する方法があるはずだと感じています.

xml の構造は十分に明確に定義されているため、1 つのドキュメントのフィールドが他のドキュメントと同じ相対 xpath を持つことを確認できます。したがって、技術的には//、手動で xml ツリーをたどるという犠牲を払って、 の使用を削除できます。しかし、それはかなりの複雑さであり、構造はかなりフラットなので、はるかに効率的かどうかはわかりません.

また、ドキュメントのこのセクションに含めることができるフィールドのセットは限られているため、それぞれを手動で (完全修飾された xpath を使用して) 順番に比較することもできますが、それは避けたいと思います。フィールドのリストが変更された場合に、将来このコードを再検討する必要がないことをお勧めします。

解決策はそれらの線に沿ったものになるのでしょうか、それとも私が見逃したもっと明白なものがありますか?

述語を使用せずに要素名の文字列値を直接使用して xpath を構築する方法はありますか? 通常、xpath の評価にはそれほど時間がかからないため、そのほうが効率的だと思います。

おそらく、要素の相対 xpath を抽出して、他のドキュメントの正確な場所を調べることはできますか?

marklogic 自体に組み込みの xml 比較ツールがありませんか?

4

2 に答える 2

3

名前空間プレフィックスの違いにだまされる可能性があるため、使用fn:nameは悪い考えです。を使った方が良いでしょうfn:node-name。また、可能な限り「//」も避けます。

詳細な比較に戻ると、これは XML diff のように聞こえます。MarkLogic には XML 差分ツールが組み込まれていないため、REST 風の Web サービスとして設定し、MarkLogic http://docs.marklogic.com/xdmp:http-postを使用して呼び出すのが最善の方法です。かなりの数の XML 差分ツールがあります。

XQuery にとどまりたい場合、ソリューションはおそらく遅くなります。再帰的なツリー ウォークとfn:deep-equal. 単純な要素の差分が見つかった場合はいつでも、降順を停止できます。これにより、ツリーが刈り込まれ、実行する作業が制限されます。これがどのように機能するかの非常に大まかなスケッチです。適切な LCS http://en.wikipedia.org/wiki/Diffには程遠いですが、役に立つかもしれません。私のラップトップでは、これは 10 ミリ秒未満で実行されます。

declare function local:diff(
  $a as node(), $b as node())
as element(diff)*
{
  if (deep-equal($a, $b)) then ()
  else if (empty($a/*) or empty($b/*)) then element diff {
    element a { $a }, element b { $b } }
  else
    let $seq-a := $a/*
    let $seq-b := $b/*
    let $count := max((count($seq-a), count($seq-b)))
    return
      for $x in 1 to $count
      return local:diff($seq-a[$x], $seq-b[$x])
};

let $a := xdmp:query-meters()
let $_ := xdmp:sleep(1)
let $b := xdmp:query-meters()
return local:diff($a, $b)
于 2013-03-04T17:21:45.263 に答える
1

インデックスを構築し、そのアプローチをベンチマークすることは価値があると思います。

私はmarklogicに精通していませんが、APIドキュメントにXSLキー関数として認識しているものがあります

(更新: これはキーをフェッチするだけのようです。それらを作成するには、XSLT を直接使用する必要があると思います。 これは良いハウツーです。element /@idでキーを生成する小さなスタイルシートが実現可能です。)

スタイルシートを文字列として追加して、I/O 時間を少し節約することもできます。

xdmp:xslt-eval(
  <xsl:stylesheet version="2.0"><xsl:key name="element_ids" match="element" use="@id"></xsl:stylesheet>,
  doc("input.xml")
)

すべての要素にキーとして使用できる識別子がある場合、ファイルを解析するときにインデックスを作成し、そのリストを格納されている (以前の) バージョンのキーと比較できます。そこから、処理する場所のリストが得られます。インデックスのおかげで、それらは非常に迅速に検索およびアクセスされます。

XQuery を使用したい場合は、'map' 関数が同様のインターフェイスを提供します。

于 2013-03-04T15:12:37.937 に答える