- PR -

XSLTで集計

投稿者投稿内容
ほむら
ぬし
会議室デビュー日: 2003/02/28
投稿数: 583
お住まい・勤務地: 東京都
投稿日時: 2003-08-08 09:47
ども、ほむらです。
--------------
引用:

おお、ほむらさんの新コードだと0.7secでした。すごい。

<xsl:if test="name(preceding-sibling::item[@value=$v]) = ''">

のところって、キャッシュとか最適化とか働いてるんでしょうか。線形探索に見えたので、ここまで速くなるとは思いませんでした。

色々いじっていて気づいたのですが、

<xsl:sort data-type="number" select="@value"/>

はなくても速度が変わりませんでした。なので、ソートが速度に関係しているわけでもなさそうです。面白い・・・


0.7Secですか。。。一体どんなマシンでやっているんです?
うちでは7秒くらいかかったんですが・・・(笑

ソートについてはFor-eachが開始される前に一度行なってしまうだけなので
速度にはあまり関係していないと思います。

修正前で問題だったのは すべてのノードについて自分より後ろにある
同じノードを無条件にカウントしていることです。
表示はしなくともカウントしているので同じノードが40個あったら40回カウントしています
(表示用に再度カウントしなおしてもいますし)

処理回数で言えば 40! でしょうか。こうやって書くと恐ろしいことしていましたね(笑
修正後は’集計するのは一度で十分’ということで
ノードがあかないかの処理をname()で識別するようにしました。
これならば 同じノードが40個あった場合でも 40回ですみます

処理的には線形探索になっているんだと思います。(たぶん)
キャッシュとかはないのではないしょうか。。
メモリ上で処理するのならXML文書の総なめにしても一瞬で終わりそうな気がします。。。
XML文書そのものにキャッシュは働いているかもしれませんけど。

# SAX使ったらどれくらいの速度になるんだろう
# このケースって一番SAX向きな感じ
ocean
ベテラン
会議室デビュー日: 2003/07/06
投稿数: 65
投稿日時: 2003-08-08 11:29
引用:

0.7Secですか。。。一体どんなマシンでやっているんです?
うちでは7秒くらいかかったんですが・・・(笑



サンプルの生成方法に問題がありました。8個の項目をコピー&ペーストで延々増殖させて作ったため、最初の8個で「前に同じノードがあった場合」にヒットしてしまい、超高速に処理されていました。お恥ずかしい。

100個ごとに数字を1つ増やすように生成法を変更したところ、以下のようになりました。

// 2000個

私の最初のコード:8.9sec
私の最後のコード:1.6sec
ほむらさんのコード:4.4sec

線形探索みたいですね。

引用:

# SAX使ったらどれくらいの速度になるんだろう
# このケースって一番SAX向きな感じ



ためしに C++Builder5 + MSXML4 でSAXを試したところ、0.1secでした。速い! (std::map<WideString, size_t>でカウントした。WideStringはBSTRのラッパー)



[ メッセージ編集済み 編集者: ocean 編集日時 2003-08-08 11:43 ]
ocean
ベテラン
会議室デビュー日: 2003/07/06
投稿数: 65
投稿日時: 2003-08-08 11:42
まだデータ生成方法に問題があるような気がしてきたので(valueが0〜20で少ない)それぞれ0,1,....,1999のvalueをもつ、2000個のデータで試してみました。すると・・・

私のコード:
MSXML4.DLL: XSL プロセッサ スタックがオバーフローしていま
す。無限のテンプレート再帰が原因となった可能性があります。

ほむらさんのコード:10sec

致命的です(T^T)。 XSLTって、こういうことにも気をつけなきゃいけないんですね。

SAXはこのデータで1.0secでしたが、コンソールへの表示をしなければ0.1secでした。


[ メッセージ編集済み 編集者: ocean 編集日時 2003-08-08 11:57 ]

[ メッセージ編集済み 編集者: ocean 編集日時 2003-08-08 11:59 ]
ocean
ベテラン
会議室デビュー日: 2003/07/06
投稿数: 65
投稿日時: 2003-08-08 15:38
<xsl:key>を使うと、場合によっては(?)高速化することがわかりました。(このサイトにヒントを得ました)

0*100,1*100,...,19*100 の XML では 4.3sec ですが、
0,1,....,1999 の XML では 5.3sec でした。

コード:

<?xml version="1.0" encoding="Shift-JIS"?>

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:key name="value" match="/root/item" use="@value"/>

<xsl:template match="/root">
<root>
<xsl:for-each select="item">
<xsl:variable name="value" select="@value"/>
<xsl:if test="not(preceding-sibling::item[@value = $value])">
<item value="{$value}" count="{count(key('value', $value))}"/>
</xsl:if>
</xsl:for-each>
</root>
</xsl:template>

</xsl:stylesheet>



#それにしても、編集の時 [code] が HTML タグに化けるのはなぜだろう??

[ メッセージ編集済み 編集者: ocean 編集日時 2003-08-08 15:50 ]
ocean
ベテラン
会議室デビュー日: 2003/07/06
投稿数: 65
投稿日時: 2003-08-09 14:33
MSXML4依存でいいなら、XSLT では msxsl:scriptを使うのが一番速いようです。
動いたというだけで、このような記述が正しいのかは今ひとつ自信がありません。

#ところで、「けい」さんのレスがないのが寂しいですね。

コード:

<?xml version="1.0" encoding="Shift_JIS"?>

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:user="urn:my-script">

<xsl:template match="/root">
<root>
<xsl:for-each select="user:count(item/@value)">
<item value="{@value}" count="{@count}"/>
</xsl:for-each>
</root>
</xsl:template>

<msxsl:script language="JScript" implements-prefix="user"><![CDATA[

function count(nodelist)
{
var doc = new ActiveXObject("MSXML2.FreeThreadedDOMDocument.4.0");

var root = doc.createElement("root");

var hash = {};

var min = null;
var max = null;

var node;

while (node = nodelist.nextNode())
{
var value = parseInt(node.nodeValue);

min = (min == null) ? value : Math.min(min, value);
max = (max == null) ? value : Math.max(max, value);

if (hash[value] == undefined)
{
hash[value] = 1;
}
else
{
++hash[value];
}
}

if (min != null && max != null)
{
for (var value = min; value <= max; ++value)
{
var count = hash[value];

if (count == undefined)
{
count = 0;
}

var item = doc.createElement("item");
item.setAttribute("value", value);
item.setAttribute("count", count);
root.appendChild(item);
}
}

return root.selectNodes("item");
}

]]></msxsl:script>

</xsl:stylesheet>



[ メッセージ編集済み 編集者: ocean 編集日時 2003-08-09 14:37 ]
けい
常連さん
会議室デビュー日: 2001/09/12
投稿数: 48
投稿日時: 2003-08-10 13:46
皆さんありがとうございます。

> #ところで、「けい」さんのレスがないのが寂しいですね。
すみません。
書き込んだ後、別件(某TechEd)で忙しくなってしまい、ご無沙汰してしまいました。
久々に来たら、レスが一人歩きをはじめててびっくり。

もともとの用途は、
「サーバ側にxmlデータがあって、
 クライアント(ブラウザ)に集計した結果を見せたいんだけど、
 集計にサーバのCPUを使いたくない。」
と言うものだったので、scriptを使っちゃってもよかったんですが、
せっかくだから、XSLTだけで出来ないかなと思ったわけです。
#数秒くらいならユーザが我慢してくれれば(^^;

皆さんの提案してくださったコードを順番に試してみたいと思います。


[ メッセージ編集済み 編集者: けい 編集日時 2003-08-10 13:47 ]

スキルアップ/キャリアアップ(JOB@IT)