ニコニコ動画のコメントは、人気動画ならば刻々と変化していきます。
久しぶりにアノ動画を・・・と閲覧すると、コメントが様変わりしていて、また違った雰囲気で動画を楽しむ事が出来たりします。しかし逆に、荒らされて「昔のコメント状態の方が良かった」なんて事も良く在る話です。
ダウンローダーでローカルに保存してしまうと、コメントの変化を楽しむ事は出来なくなりますが、それはコメントデータを新たに取得しなおせば良い事。そこで、間を置いて再取得したコメントデータを合理的に保存する為に、コメントデータのマージをするルーチンを作りましたが・・・
注意)コードの実行は、AIR SDK 1.5.3 の adl.exe にて行っています。全ての環境で同じ結果が出るとは限りません。
久しぶりにアノ動画を・・・と閲覧すると、コメントが様変わりしていて、また違った雰囲気で動画を楽しむ事が出来たりします。しかし逆に、荒らされて「昔のコメント状態の方が良かった」なんて事も良く在る話です。
ダウンローダーでローカルに保存してしまうと、コメントの変化を楽しむ事は出来なくなりますが、それはコメントデータを新たに取得しなおせば良い事。そこで、間を置いて再取得したコメントデータを合理的に保存する為に、コメントデータのマージをするルーチンを作りましたが・・・
注意)コードの実行は、AIR SDK 1.5.3 の adl.exe にて行っています。全ての環境で同じ結果が出るとは限りません。
ニコニコメント結合コード
コードはそれほど難しくもなく。
private function commentsMarge(a:XML, b:XML):XML
{
var aTime:Number = Number(a.thread.@server_time);
var bTime:Number = Number(b.thread.@server_time);
if ( aTime > bTime )
{ // b の方が新しいデータ。になるよう入れ替える。
var tmp:XML = a;
a = b;
b = tmp;
tmp = null;
}
//
var chat:XML;
var no:Number;
// 配列へ
var orAry:Array = new Array();
for each(chat in a.chat)
{
no = Number(chat.@no);
orAry[no] = chat;
}
// 結合:noをユニークなIDとして結合。
for each(chat in b.chat)
{
no = Number(chat.@no);
orAry[no] = chat; // レス番が被れば、より新しいデータで上書き。
}
// 整列
var numArray:Array = new Array();
for each(chat in orAry) numArray.push(chat);
orAry = null;
numArray.sort(function (a:XML, b:XML):int
{
var an:Number = Number(a.@no);
var bn:Number = Number(b.@no);
if ( an > bn ) return 1;
if ( an < bn ) return -1;
return 0;
});
// XMLへ
var xml:XML =<packet/>;
xml.appendChild(b.view_counter); // 視聴カウント
//
for each(chat in numArray) xml.appendChild(chat);
//
return xml;
}
引数に与えられる、xml はニコニコから取得したコメントデータXML そのままです。
コメントのレス番順にソートしたものを返してくれます。
重い・・・とてもとても重い
1000コメントあるコメントデータに、新たに1000コメントあるコメントデータを結合してみました。コメント取得の間が結構開いていたので、内容が被るコメントが無く、結合後2000コメントのデータになりました。が、この処理にえらい時間がかかるのです。ルーチンの実行から値が返ってくるまでを getTimer で測ったところ、1400msec ほどかかります。Action Script の処理能力から言って、2000個のデータをどうこうにするのに、1秒もかかるハズはありません。
どこに時間がかかっているのか追求していくと・・・ルーチン最後のループに問題があったようです。
for each(chat in numArray) xml.appendChild(chat);
ただの XML の子ノード追加なのに何故こんなに重いのでしょうか。
文字列にしてみる
最終的に「結合できれば良い」ので、ダメ元で String にして繋げてから XML に戻す方法にしてみたところ・・・
var r:String = "";
for each(chat in numArray) r += chat.toXMLString();
var xl:XMLList = new XMLList(r);
xml.appendChild(xl);
しかし、XML の各ノードのオブジェクトとしての整合性や、機能などを考えると仕方ないのかもしれません。
この時点で、XML のデータ操作は、出来ることなら文字列でやった方が早いという事が言えると思います。
文字列の結合の部分をもうちょっと追求して・・・
xml.appendChild(
new XMLList(
numArray.map(
function (chat:XML, index:int, arr:Array):String
{
return chat.toXMLString();
}
).join("")
)
);
最終的に、およそ10倍の速度アップに成功しました。
ちなみに、appendChild とほぼ同機能の以下の記述を試したところ・・・
for each(chat in numArray) xml.* += chat;
結論
XML のデータ結合は一旦文字列にしてからの方が早い。カナリ。この件の検証結果が、どの程度応用が効くかは状況にも寄りますが、多量のデータを纏めるなんて場合には、使えると思います。

コメントする