「Help:テンプレートの制限」の版間の差分

削除された内容 追加された内容
更新。
m substitution
1行目: 1行目:
{{DEFAULTSORT:てんふれとのせいけん}}{{HJ:h|Editor toc ja}}
{{DEFAULTSORT:てんふれとのせいけん}}{{HJ:h|Editor toc ja}}
ウィキペディアの使用しているソフトウェア[[Help:メディアウィキ|メディアウィキ]]には、テンプレート呼び出しやテンプレートの代入展開によって'''ページに読み込まれるデータ量を制限'''するためのパラメータがいくつかあります。このページでは、なぜ、そしてどのようにこの制限が用いられているかについて解説しています。
ウィキペディアの使用しているソフトウェア[[Help:メディアウィキ|メディアウィキ]]には、テンプレート呼び出しやテンプレートの置換展開によって'''ページに読み込まれるデータ量を制限'''するためのパラメータがいくつかあります。このページでは、なぜ、そしてどのようにこの制限が用いられているかについて解説しています。


== 概要 ==
== 概要 ==

2008年9月29日 (月) 13:01時点における版

ウィキペディア日本語版ヘルプページです。


ウィキペディアの使用しているソフトウェアメディアウィキには、テンプレート呼び出しやテンプレートの置換展開によってページに読み込まれるデータ量を制限するためのパラメータがいくつかあります。このページでは、なぜ、そしてどのようにこの制限が用いられているかについて解説しています。

概要

メディアウィキでは、ウィキテキスト(ウィキソース)をもとにHTMLページが生成されますが、読み込みデータについては構文解析の一種(再帰下降構文解析)を使用しています。ウィキテキストは「プリプロセッサ」を用いて「ツリー」と呼ばれるデータ構造に変換され、このツリーを用いてHTMLソースが生成されます。

構文解析の過程では、生成されるページの複雑性を把握するためにいくつかのカウンターが使用されます。カウンターは解析開始時点でゼロに設定され、解析中に該当するプロセスがあると数値が計上されていきます。カウンターには上限値が設定されており、上限値を越えると展開ができなくなります。

極端に長いページやテンプレートをたくさん呼び出しているような複雑なページは解析に時間がかかります。このことは利用者にとって不便なだけでなく、処理不可能なほど巨大なデータをメディアウィキに解析させることでDoS攻撃の手段として悪用される可能性もあります。このような攻撃を予防し、ページの読み込みが常識的なスピードで行われることを保証するために、このような制限が設定されています。読み込みデータの制限は、2006年8月より導入されました。2008年2月から新しいプリプロセッサが導入され、制限の方法が変更されました(meta:Migration to the new preprocessor参照)。

制限がおこりやすい事例

読み込み制限は、同じテンプレートを何度も使用している場合によく起こります。例えば、長い表の各行に同じテンプレートを呼び出しているような場合です。テンプレート自体のデータが小さくても、テンプレート呼び出しの際ごとにテンプレートページのソース全体量が計上されますので、思っているよりも簡単に制限値に達することになります。また、当然ながら、呼び出しているテンプレートのサイズが大きければ大きいほど、制限に達するのも早くなります。サイズが大きい理由としては、テンプレート本体が複雑であったり、テンプレートの説明文が付随していたり、呼び出し先で必要なデータ以外の多くのデータを含んでいたりすることが考えられます。

制限値に達しているか判別するには

生成されたページ本体のHTMLソース中には、ソースの比較的末尾にHTMLコメントによってカウンターの数値が描き込まれています。そこで、ブラウザのHTMLソースを表示する機能を利用してHTMLソースを確認することで、そのページのカウンターの数値を知る事ができます。

例えば、沖縄県2008年4月23日 (水) 09:39 (UTC) の版)のページの生成されたHTMLソースにはつぎのコメントが含まれています。

<!-- 
NewPP limit report
Preprocessor node count: 1941/1000000
Post-expand include size: 61082/2048000 bytes
Template argument size: 14804/2048000 bytes
Expensive parser function count: 2/500
-->

/の前の数値が計上された数値、/の後の数値が制限値です。カウンターの仕様により、表示される数値は常に制限値よりも小さくなります。もし/の前の数値が制限値(/の後の数値)に近ければ、読み込まれなかったテンプレートがある可能性があります。呼び込まれなかったテンプレートがある場合、この旨を伝えるエラーメッセージがHTMLソース中に表示されます。

読み込み制限の仕組み

解析の過程で使われる制限には、「プリプロセッサ・ノード数」、「展開後読み込み量」、「テンプレート引数量」、「高負荷条件文関数使用回数」の4種があります。

プリプロセッサ・ノード数

「プリプロセッサ・ノード数」(Preprocessor node count)のカウンターは新プリプロセッサから採用されました。これは、データの量ではなく、ページの複雑性を計測しています。解析によってページが展開される時には、HTMLの構造に対応する「ツリー」と呼ばれるデータ構造を生成しますが、このツリーのノードの数を計るものです。このカウンターが制限値を越えると、解析が中止され、生成HTMLページ中に "Node-count limit exceeded" のエラーメッセージを生成します。ノード数にはテンプレートだけでなく、リンク、セクション見出し、HTML要素などがすべて計上されています。

展開後読み込み量

ソフトウェアはページ内のソースコードに従って構文解析を行い、テンプレートを展開します。この時、テンプレートによって生成されるHTMLソースコードの長さ(「展開後読み込み量」(post-expand include size))が、「展開後カウンター」に計上されます。もし計上後の数値が「展開後読み込み制限値」を越えていれば、テンプレートはページ内に読み込まれず、生成されたHTMLソース中にエラーメッセージが出力されます。数値が「展開後読み込み制限値」内であれば、テンプレートによって生成されたHTMLコードがページ本体のHTMLの中に組み込まれ、「展開後カウンター」の数値が新しい値に設定されます。

テンプレートは再帰的に展開されるため、もし読み込まれているテンプレート自体に他のテンプレートが呼び出されている場合、呼び出されている下位のテンプレートの値も、最終的に呼び出されているページのカウンターの数値に影響します。そのため、下位のテンプレートを呼び出している途中に制限値を超過した場合、テンプレートの展開が途中でとまってしまうこともありえます。

例えば、テンプレート {{A}}{{B}}{{B}}{{B}}{{B}}{{B}} が含まれており、テンプレート {{B}} のソースには、100バイトのプレインテキストが含まれているとします。テンプレート {{A}} を呼び出す前の段階で、展開後カウンターに余裕が150バイトしかなかったと仮定します。この時、テンプレート {{B}} の展開が2回行われた後のテンプレート {{A}} が生成するHTMLソースは200バイトを越えますので、結果としてテンプレート {{A}} は呼び出し先のページに表示されません。

また、カウンターはテンプレートがページに読み込まれるたびに増加しますので、1ページ内に何度も使用されているテンプレートがあった場合、読み込まれている回数分、カウンターの数値が増加することになります。

新プリプロセッサの導入前は、テンプレートの展開前のデータ量も計測しており、これがテンプレートの制限でもっとも問題になっていました。特別:ParserDiffTestは古いプリプロセッサと新しいプリプロセッサの出力結果の違いを差分表示する特別ページです。/を使って直接解析ページを指定したリンクも作れます(例:特別:ParserDiffTest/皇室の系図一覧。リンク先は非常に重いページとなっていますので、クリックする際にはご注意下さい)。

また、新プリプロセッサでは、条件文を用いたテンプレートの実行されない部分を展開しません。例えば、{{#if:yes|{{bar}}|{{foo}} }}というコードがあったとすると、テンプレート {{bar}} は展開され、テンプレート {{foo}} は展開されません。ただし、最終的な出力結果には表れないテンプレートの引数が展開後読み込み量に計上されることがあります。例えば {{#if:{{foo}}|yes|no}} というコードがあったとすると、解析の際に条件文の決定のためにテンプレート {{foo}} の展開が必要なため、 {{foo}} の展開量が展開後カウンターに計上されます。

テンプレート引数量

「テンプレート引数量」(template argument size)カウンターは、代入されるテンプレート変数の引数を計上します。

高負荷条件文関数使用回数

「高負荷条件文関数使用回数」(expensive parser function count)は、条件文中の負荷の高い関数の使用回数を500以下に制限するものです。対象となるのは次の2つです。

  • #ifexist:この関数は、指定されたページが存在するかどうかで出力を切り替えるのに使用されます。使用回数が制限値を超えると、それより後の #ifexist では、ページの存在はすべてないものとして返されます。
  • PAGESINCATEGORY:与えられたカテゴリに含まれるページ数を返します。

カウンタが500を越えているページはCategory:高負荷な構文解析関数の呼び出しが多過ぎるページへ自動的にカテゴライズされます。

制限内でやりくりするには

ページがテンプレートの制限に達した場合、もっとも一般的な解決法は、下記の方法を用いてテンプレートを短くすることです。これでも解決しない場合、テンプレート呼び出しではなく、ページ本体に直接記述するデータを増やすことを考えてみてください。その際には特別ページのテンプレートを展開が利用できます。

noinclude と onlyinclude タグおよびコメントの使用

テンプレートの展開時には <noinclude> タグに囲まれている部分、もしくは <onlyinclude> タグの外にある部分は呼び出し先に展開されません。またHTMLコメントも展開されません。したがって、これらの部分は「展開後カウンター」の数値には一切影響を与えませんが、新プリプロセッサ導入前に用いられていた、「展開前カウンター」には計上されていました。このカウンターの制限によりテンプレートが展開されない場合が少なくなかったため、テンプレートの説明文を /doc というサブページに切り離し、<noinclude> タグで囲んでテンプレート本体に読み込むようにすることで、テンプレートの読み込みサイズを小さくすることが行われています。新プリプロセッサでは展開前カウンターを使用しないので、説明文が切り離されているかどうかは読み込み制限にほとんど影響がなくなります。詳しくはHelp:テンプレートの説明文を参照してください。

同じテンプレートの呼び出しを避ける

テンプレートAを何度も呼び出す代りに、Aを引数にとるテンプレートBを呼び出すということが可能な場合があります。

参考文献