まだプログラマーですが何か?

プログラマーネタ中心。たまに作成したウェブサービス関連の話も https://twitter.com/dotnsf

タグ:wordpress

2018/09/15 に開催された WordCamp Tokyo 2018 にスピーカーとして参加してきました:
WordPress meets IBM Watson ! 〜WordPress のコンテンツデータを IBM Watson に機械学習させてみよう〜

kimura-kei


セッションの中で話せたことだけでなく、その背景にあった部分も含めてブログにまとめました。


【WordPress 歴】
まず私自身の WordPress 歴を話しておきます。利用者という意味では結構早い段階から使っていたつもりでしたが、(WordPress をカスタマイズして使ってサービスを作る、という)開発者としては 2013 年からだと思います。この年に転職を経験しており、その転職先では WordPress を使ったサービス開発案件を何度も経験しました。業務で本格的に PHP を使うようになったのもこの頃からです。自分自身の印象として、WordPress は「サービスを高速開発するフレームワークの1つ」だと思っています。実際、テンプレートやプラグインの充実度が半端なく、ちょっとググればやりたいことを実現するプラグインが見つかるので、完成形に近いサービスをすぐに作ることができて感動しました。同時に WordPress のシステム内部についても興味を持つようになりました。当時はまだ REST API が標準ではなかったため、自分で MySQL テーブルの構造を調べて、データを効率よくインポート/エクスポートするにはどうすればよいか、を調べたり、ツールを作ったりしていました。今回発表させていただいた内容でもこの頃の知識が役立ちました。


【2度目の応募】
WordCamp でスピーカーとして登壇させていただいたのは初めてでしたが、スピーカーとしての応募は初めてではありません。WordCamp の存在を知ったのは 2013 年頃だったと思います。記憶が正しければこの頃(おそらく 2014 年)に一度スピーカーとして応募しています。少しビジネス寄りの利用を想定した内容だったのですが、この時は残念ながら登壇することはありませんでした。そしてこの時から「いつかはこの舞台でスピーチしたいなあ」という目標のようなものができたのでした。

そして今年、今回もどちらかというとビジネス寄りの内容だったと思いますが、よく言えば「流行りに乗っかる」形で人工知能と絡めたセッションのスピーチで応募し、念願だった登壇者に選んでいただきました。


【直前のトラブル】
今回のセッションは 15 分間の中で説明とライブデモを見せる、というものでした。このライブデモで実際に動いている所をお見せすることで理解をより具体的に深めていただく、という目的がありました。

ところがこのデモ環境にトラブルがありました。ちゃんと動く環境を(仮想環境で)用意して、そのイメージのバックアップもとって、何かあってもバックアップからリストアすれば大丈夫、と思っていました。ところがこの環境で使って、セッションが expire するまでは普通に使えるのですが、expire 後に何故かログインできなくなる、という問題が発生してしまいました。要は肝心のデモ環境に管理者権限でログインできなくなってしまう、という症状が出てしまったのでした。プラグインを紹介するデモなので、管理者コンソールに入れないのは致命傷でした。

判明したのがデモ直前だったこともあり、原因は未だによくわかっていないのですが、このトラブルに結構振り回されました。結論としては「セッションの直前にデモ環境をデモデータ含めて新規に構築する」という綱渡り的な対処で乗り切りました。冷や汗モノ・・・ (^^;


【セッションは無事に】
そんな綱渡りをしながらもセッションは無事に(3分オーバーでw)終えることができました。事前の練習では1分余らせて終える練習をしていたつもりが、本番になると調子に乗ってしまったのか、話す時間が多くなってしまったようです。

当日の資料の配布版はこちらで公開しています:


IBM Watson の NLC(Natural Language Classifier) というサービスを使って、WordPress の中に溜まったデータを Watson に学習させて、問い合わせすることに挑戦する、という内容を紹介させていただきました。全セッション中の最終セッションだったにもかかわらず多くの皆様に参加いただき、また終了後も多くの質問や感想をその場でいただくことができて、とても充実したセッションでした。この場をお借りしてお礼申し上げます。

セッション内でも触れましたが、機械学習の現場では「学習データ不足」が解決するべき課題となっています。WordPress のような広く使われている CMS のコンテンツデータを学習データとすることができればどんなに楽か・・・という思いもあってのセッションテーマおよびデモでした。同じような悩みを持っていたり、興味を持って参加いただけた皆さんの参考になれば嬉しいです。

また上述の通り、自分にとってはこの場でセッションすることがここ数年の目標の1つでした。とてもいい形で実現することができたと思っています。参加者の皆様、サポートスタッフの皆様、スポンサーの皆様、貴重な機会を本当にありがとうございました。

uXTscPOQ



データのマイグレーションなどで WordPress を使う場合、元データのユーザーデータごと移行するケースがあると思います。そんなユーザー情報を WordPress の機能で追加するのではなく、外部アプリケーションから直接データベースを操作して追加する方法を紹介します。

なお、今回紹介するケースでは WordPress 4.8.2 を使いました。また WordPress のテーブルプリフィクス値はデフォルトの 'wp_' であると仮定して以下を紹介します。異なる設定で利用している場合は適宜読み替えてください。加えて、今回紹介する PHP ファイルを MySQL サーバーとは異なるホストから実行する場合は、このファイル内で指定したユーザーが MySQL にリモートログインできるような設定があらかじめされている必要がある点をご注意ください。


まず WordPress を普通にセットアップすると、いくつかのテーブルが自動的に生成されます。その中でユーザー情報を管理するのは wp_users と wp_usermeta の2つです:


wp_users はその名の通り WordPress のユーザーテーブルとなっていて、1レコードが1ユーザーの情報を意味します。詳しくは後述しますが、単に「ユーザーを登録する」だけであればこのテーブルに1レコード追加するだけで事は足ります。

一方、wp_usermeta はユーザーの属性に関わる値を管理するテーブルです。例えばユーザーのニックネームや権限といった wp_users だけでは管理できない一部の情報や、システムが内部的に利用するセッション情報、最終アクション日時といった情報を wp_usermeta テーブルで管理します。以下では「管理画面にアクセスできる権限を持ったユーザーを追加する」例を紹介しますが、この場合は wp_usermeta も操作する必要があります。


まず wp_users テーブルの属性を desc コマンドで調べた結果がこちらです:
mysql> desc wp_users;
+---------------------+---------------------+------+-----+---------------------+----------------+
| Field               | Type                | Null | Key | Default             | Extra          |
+---------------------+---------------------+------+-----+---------------------+----------------+
| ID                  | bigint(20) unsigned | NO   | PRI | NULL                | auto_increment |
| user_login          | varchar(60)         | NO   | MUL |                     |                |
| user_pass           | varchar(255)        | NO   |     |                     |                |
| user_nicename       | varchar(50)         | NO   | MUL |                     |                |
| user_email          | varchar(100)        | NO   | MUL |                     |                |
| user_url            | varchar(100)        | NO   |     |                     |                |
| user_registered     | datetime            | NO   |     | 0000-00-00 00:00:00 |                |
| user_activation_key | varchar(255)        | NO   |     |                     |                |
| user_status         | int(11)             | NO   |     | 0                   |                |
| display_name        | varchar(250)        | NO   |     |                     |                |
+---------------------+---------------------+------+-----+---------------------+----------------+
10 rows in set (0.01 sec)

プライマリキーは ID(auto_increment)で、他のフィールドは全て Not Null 属性です。ただ user_registered と user_status にはデフォルト値が設定されています。ということはこれらを除いた user_login, user_pass, user_nicename, user_email, user_url, user_activation_key, display_name を指定すればレコードは作れそうです。

というわけで、とりあえずは以下のような関数(createWpUser)およびファイル(wp-user-import.php(改良前))を PHP で作ってみました:
<?php

$wp_db_name = 'wpdb';            //. WordPress DB
$wp_db_host = 'localhost';       //. WordPress ホスト名
$wp_db_username = 'adminuser';   //. WordPress DB の管理者ユーザー名
$wp_db_password = 'adminpass';   //. WordPress DB の管理者パスワード
$wp_table_prefix = 'wp_';        //. WordPress DB のテーブルプリフィクス


function createWpUser( $u_email, $u_password ){
  global $wp_db_name, $wp_db_host, $wp_db_username, $wp_db_password, $wp_table_prefix;

  $pdo = new PDO( 'mysql:dbname='.$wp_db_name.';host='.$wp_db_host.';charset=utf8', $wp_db_username, $wp_db_password );
  if( $pdo != null ){
     $pdo->query( 'SET NAMES utf8' );

     $sql1 = 'insert into ' . $wp_table_prefix . 'users(user_login,user_pass,user_nicename,user_email,user_url,user_activation_key,display_name) values( :user_login, MD5(:user_pass), :user_nicename, :user_email, "", "", :display_name )';
     $stmt1 = $pdo->prepare( $sql1 );
     $stmt1->bindParam( ':user_login', $u_email );
     $stmt1->bindParam( ':user_pass', $u_password );
     $stmt1->bindParam( ':user_nicename', $u_email );
     $stmt1->bindParam( ':user_email', $u_email );
     $stmt1->bindParam( ':display_name', $u_email );
     $r1 = $stmt1->execute();
  }
}

?>

createWpUser 関数のパラメータはメールアドレスとパスワードの2つだけです。メールアドレスは user_login, user_nicename, user_email, display_name に設定します。パスワードは MySQL の MD5 関数を使ってハッシュ化したものを指定します。また user_url および user_activation_key には '' を指定して insert を実行しています。

このファイルを使って、1ユーザーを作成するサンプルがこちらです(test1.php):
<?php

require_once './wp-user-import.php';

$r1 = createWpUser( 'user1@xxx.com', 'P@ssw0rd' );  //. ID: user1@xxx.com , パスワード: P@ssword のユーザーを新規作成する

?>

試しにこの test1.php を実行すると、WordPress に user1@xxx.com という ID のユーザーが登録されます:
$ php -f test1.php


管理者権限でログインして管理ページを開くと、たしかに指定したユーザーが追加されていることが確認できます(この画面で「権限グループ」が「なし」になっていることがわかります):
2017103001


この時点で作成したユーザーは有効なので、指定した ID とパスワードでログインすることはできます:
2017103002


ただ管理機能については権限を一切持っていないユーザーなので、無理やり URL を指定して管理ページにアクセスしてもエラー画面となります:
2017103003


とりあえずはここまで。wp_users に1レコード追加するだけで(管理や投稿の権限を持たない)ユーザーを作ることができることがわかりました。とりあえずこの状態になれば、後から管理者がこれらのユーザーの権限を(手動で)変える、ということも可能ではあります。


次に管理者や投稿者の権限を持ったユーザーを同様に外部から作成する方法を紹介します。先程と同様に wp_usermeta テーブルの属性を同様に調べた結果がこちらです:
mysql> desc wp_usermeta;
+------------+---------------------+------+-----+---------+----------------+
| Field      | Type                | Null | Key | Default | Extra          |
+------------+---------------------+------+-----+---------+----------------+
| umeta_id   | bigint(20) unsigned | NO   | PRI | NULL    | auto_increment |
| user_id    | bigint(20) unsigned | NO   | MUL | 0       |                |
| meta_key   | varchar(255)        | YES  | MUL | NULL    |                |
| meta_value | longtext            | YES  |     | NULL    |                |
+------------+---------------------+------+-----+---------+----------------+
4 rows in set (0.00 sec)

umeta_id がプライマリキー(auto_increment)で、user_id は wp_users.ID を示す外部キーです。そしてこの user_id で指定したユーザーに対して、meta_key と meta_value で属性を加えることができるようになっています。

ユーザーの権限に関わる設定をするには、meta_key の値が 'wp_user_level' 及び 'wp_capabilities' となる2つのレコードを追加して指定することになります。具体的には対象のユーザーの権限に応じて、以下のような値を設定します:
ユーザー権限wp_user_level の設定値wp_capabilities の設定値
購読者0a:1:{s:10:"subscriber";b:1;}
寄稿者1a:1:{s:11:"contributor";s:1:"1";}
投稿者2~4a:1:{s:6:"author";b:1;}
編集者5~7a:1:{s:6:"editor";b:1;}
管理者8~10a:1:{s:13:"administrator";b:1;}


というわけで wp-user-import.php を少し改良します。createWpUser 関数のパラメータを2つから3つに変更し、3つ目のパラメータで上記の wp_user_level を指定するものとします:
<?php

$wp_db_name = 'wpdb';            //. WordPress DB
$wp_db_host = 'localhost';       //. WordPress ホスト名
$wp_db_username = 'adminuser';   //. WordPress DB の管理者ユーザー名
$wp_db_password = 'adminpass';   //. WordPress DB の管理者パスワード
$wp_table_prefix = 'wp_';        //. WordPress DB のテーブルプリフィクス


function createWpUser( $u_email, $u_password, $wp_user_level = 0 ){
  global $wp_db_name, $wp_db_host, $wp_db_username, $wp_db_password, $wp_table_prefix;

  $pdo = new PDO( 'mysql:dbname='.$wp_db_name.';host='.$wp_db_host.';charset=utf8', $wp_db_username, $wp_db_password );
  if( $pdo != null ){
    $pdo->query( 'SET NAMES utf8' );

    $sql1 = 'insert into ' . $wp_table_prefix . 'users(user_login,user_pass,user_nicename,user_email,user_url,user_activation_key,display_name) values( :user_login, MD5(:user_pass), :user_nicename, :user_email, "", "", :display_name )';
    $stmt1 = $pdo->prepare( $sql1 );
    $stmt1->bindParam( ':user_login', $u_email );
    $stmt1->bindParam( ':user_pass', $u_password );
    $stmt1->bindParam( ':user_nicename', $u_email );
    $stmt1->bindParam( ':user_email', $u_email );
    $stmt1->bindParam( ':display_name', $u_email );
    $r1 = $stmt1->execute();

    $user_id = null;
    $sql2 = 'select last_insert_id() as user_id from ' . $wp_table_prefix . 'users';
    $stmt2 = $pdo->query( $sql2 );
    if( $row = $stmt2->fetch( PDO::FETCH_ASSOC ) ){
      $user_id = $row['user_id'];
    }

    if( $user_id ){
      //. wp_user_level
      $sql3 = 'insert into ' . $wp_table_prefix . 'usermeta(user_id,meta_key,meta_value) values( :user_id, "wp_user_level", :wp_user_level )';
      $stmt3 = $pdo->prepare( $sql3 );
      $stmt3->bindParam( ':user_id', $user_id );
      $stmt3->bindParam( ':wp_user_level', $wp_user_level );
      $r3 = $stmt3->execute();

      //. wp_capabilities
      $wp_capabilities = null;
      if( $wp_user_level == 0 ){
        $wp_capabilities = 'a:1:{s:10:"subscriber";b:1;}';
      }else if( $wp_user_level == 1 ){
        $wp_capabilities = 'a:1:{s:11:"contributor";s:1:"1";}';
      }else if( 2 <= $wp_user_level && $wp_user_level <= 4 ){
        $wp_capabilities = 'a:1:{s:6:"author";b:1;}';
      }else if( 5 <= $wp_user_level && $wp_user_level <= 7 ){
        $wp_capabilities = 'a:1:{s:6:"editor";b:1;}';
      }else if( 8 <= $wp_user_level && $wp_user_level <= 10 ){
        $wp_capabilities = 'a:1:{s:13:"administrator";b:1;}';
      }
      if( $wp_capabilities != null ){
        $sql4 = 'insert into ' . $wp_table_prefix . 'usermeta(user_id,meta_key,meta_value) values( :user_id, "wp_capabilities", :wp_capabilities )';
        $stmt4 = $pdo->prepare( $sql4 );
        $stmt4->bindParam( ':user_id', $user_id );
        $stmt4->bindParam( ':wp_capabilities', $wp_capabilities );
        $r4 = $stmt4->execute();
      }
    }
  }
}
?>

createWpUser の3つ目のパラメータ(無指定時は 0)の値を上記の wp_user_level と見なして、wp_usermeta テーブルにユーザー権限に合わせた値を作成するように変更しました。また wp_usermeta テーブルにレコードを作成する際に wp_users.ID の値が必要になるので、MySQL の last_insert_id() 関数を使って作成したユーザーの ID を取得しています。

そして、例えば管理者権限を持ったユーザーを作成したい場合は以下(test2.php)のようなコードを用意します:
<?php

require_once './wp-user-import.php';

$r2 = createWpUser( 'user2@xxx.com', 'P@ssw0rd', 10 );  //. ID: user2@xxx.com , パスワード: P@ssword のユーザーを管理者権限で新規作成する

?>

試しにこの test2.php を実行すると、WordPress に user2@xxx.com という ID の管理者ユーザーが登録されます:
$ php -f test2.php

2017103004


このユーザーの ID とパスワードでログインすると、管理者ダッシュボードにアクセスして、管理者権限でのオペレーションが可能です:
2017103005



というわけで、PHP から WordPress の MySQL データベースを直接操作してユーザーを登録することができました!


(参考) WordPress Codex 日本語版:ユーザーの種類と権限

ワードプレスのインポートプラグインを使わず、データベース内のテーブル(wp_posts とか、wp_terms とか、・・)に直接 SQL を実行して、記事をインポートする方法を紹介します。単なる記事だと(簡単すぎて)つまらないので、カテゴリ付きの記事の、そのタイトルと本文をインポートすることに挑戦しました。 なお、ワードプレスのデータベーステーブルプリフィックスは設定によって変更可能ですが、以下はデフォルトである 'wp_' に設定されているものとして紹介します。


【記事のインポート】
単純な記事のインポートだけであれば wp_posts テーブルに post_status = 'publish', post_type = 'post' でデータを挿入するだけです(必要に応じて post_date や post_author なども):
insert into wp_posts( post_content, post_title, post_status, post_type ) values( '(本文)', '(タイトル)', 'publish', 'post' );

単純に記事を公開状態でインポートするだけなら、必要な記事のぶん上記コマンドを繰り返して実行するだけです。以下はカテゴリ情報を有効にする場合の追加作業です。


この SQL を実行した結果、auto_increment なプライマリキーである ID 値が確定します。この ID 値は記事のカテゴリーを指定する際に必要になるので取得しておきます。
select last_insert_id() as ID from wp_posts;


【カテゴリーのインポート】
記事にカテゴリを付与する手順は少し複雑です。

まずカテゴリの名称(と slug)を wp_terms テーブルに挿入します:
insert into wp_terms( name, slug ) values( '(カテゴリー名)', '(カテゴリー名を urlencode したもの)' );

この SQL を実行した結果、auto_increment なプライマリキーである term_id 値が確定するので、この値を取得します:
select last_insert_id() as term_id from wp_terms;

この term_id が所得できたら、次は wp_term_taxonomy テーブルにこの term_id と、term_id が示すカテゴリの記事が何件あるのかという情報を taxonomy 情報(='category')と一緒に wp_term_taxonomy テーブルに挿入します:
insert into wp_term_taxonomy( term_id, taxonomy, count ) values( (term_id の値), 'category', (このカテゴリに属する記事数) );

この SQL を実行した結果、auto_increment なプライマリキーである term_taxonomy_id 値が確定するので、この値を取得します:
select last_insert_id() as term_taxonomy_id from wp_term_taxonomy;

term_taxonomy_id が取得できたら、最初に取得した記事の ID 値と、カテゴリを示す term_taxonomy_id 値との組み合わせを wp_term_relationships テーブルに挿入します:
insert into wp_term_relationships( object_id, term_taxonomy_id ) values( (ID の値), (term_taxonomy_id の値) );

ちとややこしいですが、ここまでの作業でカテゴリに紐付いた記事のインポートが実現できます。ワードプレスDBのテーブルスキーマとの関連だとこんな感じになります:
2017072000


まとまったデータコンテンツをワードプレスに移行する、という場合は上記の作業を必要なだけ繰り返し自動的に行うようなツールを(プログラミングで)作ることになります。本文&タイトル&カテゴリ程度が決まっている単純構成であれば、(それらのデータを取り出す部分さえ作れれば)自動化もそんなに難しくないと思ってます。


超有名なコンテンツ管理システムであるワードプレスは数多くのプラグインも提供されており、プラグインを組み合わせるだけで色々な目的のサイトが構築できてしまいます。

ふとした事情でクラウドファンディング的なサイトを試験的に用意する必要が生じたのですが、「ワードプレスだけでサクッとクラウドファンディングサイトが作れたりしないだろうか?」と思い立って調べてみました。結論としては「色々あるけど、とりあえずクラウドファンディングが作れるプラグインは見つけた」ので、調べて構築した内容を以下に紹介します。


まず、クラウドファンディング用のワードプレスプラグインは有料/無料あわせて数多く存在しています。その中で以下に紹介するのは IgnitionDeck という団体(?)から提供されている IDCF(IgnitionDeck CrowdFunding) (及び IDCF 対応のテーマ)です:
2017040812



IDCF をワードプレスに導入するにはワードプレス管理画面のプラグイン導入から "IgnitionDeck" を検索し、"IgnitionDeck Crowdfunding & Commerce" を見つけて「今すぐインストール」します:
2017040801


他のプラグイン同様に、インストール後「有効化」をクリックすると、このプラグインが有効になります:
2017040802


IDCF プラグインを有効にしても、この段階では IgnitionDeck 未登録のためまだ使えません。管理画面に "IgnitionDeck" というメニューが追加されているので、メニューから IDCF を選び、 "Activate Now" ボタンをクリックして登録画面に遷移します:
2017040803


登録といっても名前、メールアドレス、そしてパスワードを入力するだけです。簡単:
2017040804


登録が完了すると次に行うべき手順が紹介された画面が表示されます。↓下図の3ステップです:
2017040805


1ステップ目、(ここまでの作業でいつの間にか導入されていた)"500 Framework" テーマを有効にします:
2017040806


2ステップ目、IDCF の設定を行います(そのまま Save でも可):
2017040807


そして3ステップ目、というかクラウドファンディングサイトとしてのスタート地点です。クラウドファンディングのプロジェクトが開始できるようになったので、何か1つ追加してみます:
2017040808


プロジェクトを保存すると、ワードプレスのトップ画面のプロジェクト一覧から確認できるようになります:
2017040802


プロジェクトを選択して開くと、クラウドファンディングの説明や目標額が確認でき、支援表明もできるようになっていることが確認できます:
2017040803


IDCF には有料のオプションもあり、サポートや追加で使えるツールキットが用意されているようです。が、まだあまり調べていません。こちらは気が向いたらということで。。


軽く使ってみた限りでの感想ですが、管理画面が英語なのはともかくとして、目標額などを入力すると自動的に米ドル扱いになってしまうことに気付きました(要は金額のデータとして "100" と入力すると、自動的に「100 米ドル」扱いになってしまう)。これをカスタマイズするには IDC メニューの CURRENCY SETTINGS から "JPY" を選択して更新しておくことで変更できました:
2017040801


もう一点、ファンディングの支援レベル(例えばレベル1はステッカーのみ、レベル2は商品そのもの1つ、レベル3は商品を10個まとめて、・・・みたいなもの)を複数追加しようとしたのですが、うまくできませんでした。ググってみると、同じ現象で悩んでるっぽい人向けの FAQ っぽいページを見つけたのですが「会員専用ページです」みたいなメッセージから先に進めず、未だに原因やワークアラウンドが分かっていません。会員としてログインしてるはずなんだけどな・・・ もしかすると、ここが無料版の制限なのかもしれません:
2017040801


もう一点。実際にユーザーがこのプロジェクトを支援しようと "Support Now" して、"Next Step" に進もうとすると、、:
2017040901


こんな画面に推移します:
2017040902


ここで何らかの入力フォーム(project_purchase_form ?)が出て来る想定なんだろうけど、ここをどうすると表示できるようになるのか? カスタマイズするにはどうするのか? といった情報を探していたのですが、どうやらここから先は無料版では提供されていない機能のようでした:
Ignitiondeck does not redirect me to Purchase Page


というわけで、まだ IDCF のフル機能を試せたわけではないのですが、ここまでは超簡単に作れてしまったことも事実。便利なプラグインをまた1つ発見してしまった。。


以前に「ノーツデータベースをまるごと IBM Watson に学習させて、問い合わせを行うサンプルアプリ」を作って紹介しました。なかなかに反響があり、タダで配布しなければよかった、と・・・調子に乗って同様のワードプレス環境向けサンプルを作ってみました。

ワードプレスは世界中で使われているオープンソースの CMS(コンテンツ管理システム)です。ちょっとデータが古いのですが、2014 年時点での 1000万サイトを対象にした調査によると CMS としてのシェアは約60%で、何よりも驚くのは全ウェブページ中の 26.6% がワードプレスを使って作られている、ということです(もう少し新しい情報持ってる人がいたら教えてください):
https://w3techs.com/technologies/overview/content_management/all

2016081201


と、それだけ利用者の多いワードプレスのデータをコグニティブエンジンである IBM Watson に学習させて、かつその学習データを使った問い合わせまでを実現できるようなプラグインを開発しました。 ぶっちゃけ、まだ「動作確認レベル」の段階ですが、このタイミングで一度公開して、多くの人に使ってみていただこうと思っています。


このプラグインを使うには、大きく2つの前提条件が必要です:
1. IBM Bluemix 環境
2. データの入ったワードプレス環境


まず 1. IBM Bluemix 環境です。IBM Bluemix にサインアップし、有効なアカウントを所有している必要があります。IBM Bluemix はアカウント作成から 30 日間は無料で利用することが出来、また有償以降後にもサービスに無料枠が設けられていて、無料または安価に利用することが可能です。

この IBM BLuemix にログインして、Watson の Natural Language Classifier (以下 NLC)サービスを作成します。このサービスを使ってデータの学習および問い合わせを行います:
2016081202


ちなみに NLC サービスの 2016/Aug/12 時点での料金は以下の様になっています。サービスインスタンスを1つだけ作成し、一ヶ月の中で学習機能を4回、問い合わせ機能を 1000 回以内使うぶんには(有償契約移行後であっても)無料枠に収まるので料金はかかりません。これらを越えて利用した場合の料金の目安にしてください:
2016081204


作成したサービスの「サービス資格情報」を確認し、このサービスを利用するためのユーザー名(username)とパスワード(password)を確認します。これらの情報は後で利用するので、このページを残しておくかメモするなりして入力できる状態にしておいてください:
2016081203


次に 2. データの入ったワードプレス環境ですが、ワードプレスの中にある文書とカテゴリを使って学習させるため、それなりの学習データを用意しようとすると、それなりの文書量が必要になります。またそのワードプレス環境にプラグインをインストールする等、管理者アカウントでログインできる権限も必要になります。


実際にプラグインを導入する手順を紹介します。プラグインは GitHub 上に用意しました:
https://github.com/dotnsf/wordpress_watson_nlc

2016081301


上記ページの "clone or download" と書かれた緑のボタンをクリックし、メニューから "Download ZIP" を選択してプラグインの ZIP ファイル(wordpress_watson_nlc-master.zip)をダウンロードします:
2016081302


ダウンロードした ZIP ファイル(wordpress_watson_nlc-master.zip)は、ワードプレスの管理画面の プラグイン - 新規追加 から「プラグインのアップロード」をクリックしてインストールできます:
2016081303


追加するプラグインファイルを指定する画面が表示されたら、ダウンロードした ZIP ファイル(wordpress_watson_nlc-master.zip)を指定して「今すぐインストール」ボタンをクリックします:
2016081304


インストールが成功したら「プラグインを有効化」をクリックして、このプラグインを有効な状態にします:
2016081305


プラグインが有効になると管理メニューの中に「NLC 設定」という項目が追加されます。このページをクリックして表示し、Username と Password に上記の NLC サービス設定時のサービス資格情報ページで取得したユーザー ID とパスワードを入力し、「変更を保存」ボタンをクリックします:
2016081306


Username と Password が設定されました。これで NLC プラグインのインストールと設定が完了です:
2016081307


では実際にこのプラグインを使ってみましょう。このプラグインで出来ることは2つあります:
(1) この(プラグインを導入した)ワードプレス環境内に格納されたデータを IBM Watson に学習させる
(2) (1) で用意した学習データを使って、問い合わせを行い、その返答内容を確認する


それぞれ順に説明します。(1) の学習機能ですが、ワードプレスに格納された投稿データの本文及びタイトルとカテゴリーの情報をもとに学習します。例えば以下の様な内容の投稿データがあったと仮定します:
 
タイトルBLUEMIX 上の SPARK を利用して、ブラウザー内で気象データを分析する
本文Apache Spark は、まったく新しい機能の数々をデータ・サイエンティスト、ビジネス・アナリスト、アプリケーション開発者に初めて利用できるようにする、次世代の分散データ処理エンジンです。Analytics for Apache Spark は IBM Bluemix に用意されている一般的なツールと連動することから、この Analytics for Apache Spark を使用することで、瞬く間にこの Apache Spark の能力をフル活用できるようになります。このチュートリアルでは、Spark API を使用する IPython Notebook を利用して、実際の気象に関するロー・データを分析する方法を紹介します。この例をベースとして使用すれば、Bluemix 上の他のアナリティクスも簡単に利用することができます。
カテゴリーcloud


Watson は初期状態では何も学習していません。そこにこの投稿データのカテゴリーである cloud について学習させたいとします。初期状態では cloud が何なのかを理解していませんが、cloud の例としてこのデータのタイトルと本文の内容を与えて「これが cloud の例だ」という形で学習させます。

これだけですとまだ1データだけですが、実際には cloud カテゴリーに属している投稿データ(のタイトルと本文の内容)を全て「cloud の例」として与えます。すると Watson は与えられた全データから cloud というものによく出てくる単語や言い回しの傾向などを自分で見つけて、「cloud にはどういった特徴があるか」を学習します。

対象のワードプレスデータには他にも色々なカテゴリーのデータが存在していることを想定しています。そして全てのカテゴリーと、そのカテゴリーに属している全レコードを使って、それぞれのカテゴリー内容を学習させます。例えばデータベース内に6つのカテゴリーが設定されている場合は6つのカテゴリーを学習させることになります。

その学習を実行するにはプラグインページの「学習」ボタンをクリックします:
2016081301


このデータベース内の情報を使って学習データを更新する、という確認メッセージが表示されます。更新するとこれまでの学習データが存在している場合も一旦削除されて、新たに現在の全投稿データを使った学習が行われます。「OK」をクリックすると続行します:
2016081302


学習処理が成功すると「データは学習中です」というメッセージが表示されます。これでデータは学習状態になりました。この直後はまだ学習中で問い合わせができない状態になりますが、しばらくすると (2) の問い合わせが可能になります:
2016081303


この学習によって、ワードプレス内に用意された各カテゴリーのキーワードを、そのカテゴリーに紐付けられた投稿データ(のタイトルと本文の内容)を基に学習します。そして学習後の問い合わせでは、与えたテキストの内容が各カテゴリーのどの内容にどの程度近いのか、という分類結果を返してくれるようになります。


では (2) の学習データに対する問い合わせ処理を紹介します。管理画面の NLC 設定ページから Query と書かれたテキストフィールドに何かテキストを入力します。ここで入力する内容は上記で学習させたカテゴリーのいずれかに関する内容となるようにしてみてください。以下の例では「Bluemix は IBM の PaaS プラットフォームです」と入力しました。この内容を Watson に問い合わせてみます。「問い合わせ」ボタンをクリックしてください:
2016081301


先ほど実行した学習処理がまだ完了していない場合、"Training" と表示されます。この場合はもうしばらく(15分~1時間程度)お待ちいただいた上で再度実行してみてください:
2016081302


Watson の学習が完了していれば問い合わせに対する回答とその confidence (自信度)が表形式で以下のように表示されます(この例文に対しては "cloud" と返してほしかったけど、このワードプレス内のデータによると "web" なのだそうだ。まあ間違いではないけど・・・):
2016081401


問い合わせに使った「Bluemix は IBM の PaaS プラットフォームです」という文章には "Web" や "Cloud" という直接的なキーワードは含まれていません。にも関わらず、(学習させたデータを元に)この内容が "Web" や "Cloud" に関係している可能性が高い、と判断できたことになります。


以上がこのプラグインが実装している機能の紹介です。注意事項が2点あります:

このプラグイン内の実装では複数のワードプレスデータには対応していません。同じ Username と Password の組では1つの(最新の)学習データしか持てません。複数のデータを同時に学習させる場合は複数の NLC サービスインスタンスを作成し、それぞれ Username と Password を取得して学習させる必要があります(無料枠内ではなくなります)。

もう1点。この NLC プラグインが不要になった場合は管理画面の「インストール済みプラグイン」の一覧から "Watson NLC" プラグインを探して、停止してください(今後も不要であればプラグインを削除してください)。
2016081403


と、こんなことができるサンプルプラグインです。ワードプレス環境をお持ちで、投稿データにある程度のカテゴリー分類ができている方は是非その環境で試してみていただきたいです。


なお、このプラグインの中で実装している機能は全てここで紹介されている NLC API を使って実装しています。この API を使うと学習させたデータを使った別のカスタマイズを行ったり、(ワードプレス以外の)別のアプリケーションから呼び出したりすることも可能です。興味あるデベロッパーの方は参照して、併せてチャレンジしてみてください:
Natural Language Classifier - API


このページのトップヘ