前々回のPSに書いた、このブログのロゴ画像を「時替わり」で いろいろ出すのが意外に気に入ったので(+そこでも書いたように、ERNIE-ViLG Demoで描いた画像が気に入ったのも大きい)、それを改良した。
例によって やることは難しくないのだが、実装には結構手こずった。欲張るせいもあるが、老化で頭が回らなくなっているのだろうか?
以下のようにしたかった。
- ロゴとして特別に選んだ・作った画像でなく、ブログの投稿に使った画像全体(あるいは新規も)から、気に入ったものを随時選んで出し、あるいは「引っ込め」たい。
- → 表示する画像を特別なディレクトリにアップロードするとか、それ用の名前にするとか、注釈(キャプション)を特別なファイルに入れるとかせず、WPの仕組みだけで実現して操作を楽にしたい。
- かといって、前に書いたように、複数画像の対象への一括設定/解除やキャプションの一括更新ができないとかの馬鹿らしい・面倒なこともしたくない。
一方、表示候補の画像を検索するために対象に「マーク」を付けたいのだが、標準のWPだと画像にはタグなどが付けられないという問題がある。
それらが付けられるのは、投稿などだけ。
WPのカスタムフィールドを使えば実装できそうだが、使い勝手が良くない。そこで、プラグインで何とかできないか探したところ、Media Library Assistant(以下、MLA)というものが見付かった。※ 本来は、WPのギャラリー(複数画像をまとめて出す部品: この投稿の一番下にあるもの)を高機能にするものだが、上記のような、画像など(attachment)にタグなどを付ける機能を持っている。
※これは ものすごく高機能で、僕の用途には もったいないくらいで、とても使いこなせない。今回も、本来の用法でないために却って苦労したw
なお、単にランダムに画像を出すだけなら いろいろあるのだが、特に、タグなどで出す候補を指定できるものは なかった。
次のような処理にした。
- ギャラリーに表示する候補画像(画像以外、動画なども可能なはず)一覧を抽出できるように、MLAのattachment tag(Att. tag(画像: 右端の列))にギャラリー名(今回は"my_gallery"とした)を設定する。
- こうすることで、ギャラリーに登録された画像を一覧することができる。
- 画像のキャプションはWPのTitle(画像: サムネイルの右の列)に設定する。
- カスタムフィールドなどでも可能だが、使い勝手(特に一括更新)を考慮して そうした。
- ページの表示時は以下の処理を行う。 (注: 変更あり。最後に書く。: 9/14 8:42)
- 表示する画像情報がキャッシュされているか調べる。
- キャッシュされている場合、
- キャッシュから取得した画像情報からURLとキャプションを取得する。
- キャッシュされていない場合、
- ギャラリーの全画像数を取得する。
- 乱数で その中の1枚を選ぶ。
- 選んだ画像のURLとキャプションを取得する。
- そのURLとキャプションをキャッシュに格納する(今回は生存時間(TTL)は20分とした)。
- 画像のURLとキャプションをページの右上に表示する。
なお、前の版では、表示する画像をページ表示部とは別のプログラムで検索・選択していたが、今回はページ表示部だけで完結している。一長一短だが、こちらのほうが保守性は良い。
それから、やはり前に書いたが、表示する画像をページを表示するたびに検索するのは重そうなので、画像の生存時間(TTL)分キャッシュしておいて、その間は検索しないようにした。
キャッシュにはPHPのAPCuを使った。最初はファイルを使ったが、排他制御が厄介なのでAPCuにした。APCuにはTTL経過後にエントリがなくなる機能があるので、生存時間の実装がとても容易だった。
が、APCuにも排他制御の問題(複数のプロセスが同時にキャッシュを更新する場合)はあって、(この用途では必要ではないが、)一応実装した。apcu_entry()という関数を使った。
複数プロセスで同時に※キャッシュに書き込もうとした場合は、(当然ながら)先の情報を採用し、後から書き込むプロセスは、それまでに選んだものを破棄して先に書き込まれた情報を使う(すげ替える)ようにした。破棄した分の処理が無駄になって効率が悪いが、正しい方法は すぐには分からないので、とりあえず こうした。
※実際には同時でなく、どちらかが先になる。マルチプロセッサ/コアの場合は難しいが、OSが ちゃんと処理しているのだろう。
いろいろ苦労して(また疲れて)、動くようになった。結果は このページの右上のとおり(見るたびに変わっているはず)。
と、一言で終わってしまうが、いくら苦労したって、ちゃんと動けば それで終わりだw
- Media Library Assistant(MLA)でのギャラリーの設定画面
- ギャラリーの画像の一覧
- ギャラリーの表示例 (動作確認用情報を出している状態)
(9/13 20:31, 9/14 8:42) 表示する画像の選択方法について
上述のように、当初は乱数で選ぶようにしていたが、様子を見ていたら、(PSにも書いたように、)ばらつき・偏りが大きいことが分かった。具体的には、頻繁に出る画像と なかなか出ないものがあった。気になって調べてみたら、最高/最低頻度の比が10前後と随分大きかった。
乱数の作り方・使い方に問題があるかと思って改良してみたが、余り改善できなかった。それから、通常の生成関数方法(PHPのrand())以外に いろいろ試したら※頻度比は2-3程度になったが、全く気に入らなかった。
僕としては全部の画像を平等に出したいので、特定のものが頻繁に出るのは全く許容できない。もし、特別気に入っているものを頻繁に出したいなら、そういう処理にする。
そういう用途では、音楽プレーヤーのような「シャフル」がいいのだろう。(処理が複雑になるのを別とすれば、)画像数が少なければ問題ないが、多くなった場合には一覧を作るのに時間が掛かりそうだ。
※試した内容や結果などの詳細は別の稿に書きたい。(→ 書いた) ただ、どの方法も「元」は同じ処理のようなのか、(下にも書いたが、)何万回も試行(実行)しないとだめなのか、頻度比に大きな違いはなかった。= 「効果なし」だった。
どうやら試行(実行)回数が少ないとばらつきが出るようだが、1000回以上でも頻度比が2では使い物にならないと感じた。
それで、実際の使い方に立ち戻って考えてみた。: ページを見る方にとっては、ページの変わる順番がどうであろうと、(一定時間経過後に)見るたびに変わればいいので、ライブラリ(ギャラリー)に格納された順番に表示するようにした。 → 最初はギャラリーの最初の画像を、切り替わりの時間になったら次に、最後まで行ったら最初に戻るようにした。
切り替わり時間(20分)ごとにリロードして表示されている画像の内容またはURLを記録するのを数十回も続けるのを2周以上※するような奇特熱心な読者にはバレるが、さすがにそういう方は居ないので大丈夫だ。
※計算したら、一周で約10時間掛かる・・・ → 実際にやるなら、スクリプトなどが良さそうだw
なんて余計なことを書かなければ いいのに、技術者なので つい書くw
変更後の処理は以下である。
- 現在表示されている画像の情報がキャッシュされているか調べる。
- キャッシュされている場合、
- キャッシュに格納した時刻から、現在表示されている画像の表示(経過)時間を求める。
- 画像の表示時間が切り替え時間(今回は20分)を超えている場合、
- キャッシュから取得した画像情報から現在表示されている画像の番号を取得する。
- 取得した番号+1の画像を選択する。
- ただし、ギャラリー中の画像数以上になったら0(最初)にする。
- そうでない場合は、以降は実行しないで終わる。
- キャッシュされていない場合、
- ギャラリー中の最初の画像(番号= 0)を選択する。
- 選択した画像のURLとキャプションを取得する。
- 画像の番号を指定してギャラリーから取り出す。
- そのURLとキャプションと画像番号をキャッシュに格納する(生存時間(TTL)は無限)。
- 画像のURLとキャプションをページの右上に表示する。
この変更のため、最後に表示した(現在表示されている)画像の番号も画像情報のキャッシュに保存するようにした。また、最後に表示した画像が分からなくなっては困るので、そのキャッシュの生存時間(TTL)を無限にし、画像を切り替えるタイミングは自分で計算するようにした。
この場合も複数プロセスでのキャッシュに対する同時アクセスは起こるが、どのプロセスの次の画像も同じ番号になるはずなので、構わず上書きするようにした。
PS. 本題には関係ないが、前の版もそうだったが、乱数が一様でないような感じがする。前の版は中央辺りに頻度の高いものがあり、その隣は頻度が他の1/2くらいと低かった。
今回は、まだサンプル数が少ないものの、全く出ない値(≒ 画像)がある。特に、最小と最大が出ていないのは、プログラムに誤りがあるのかも知れない。。。
(9/14 9:05) その後、やっぱり我慢ならないので、本文に追記したとおり、乱数は止めた。