この記事は GMOアドマーケティングAdvent Calendar 2020 20日目の記事です。
こんにちは、GMOアドマーケティングのあおんたです。
自社メディアめるもでは、記事のキーワードに応じて、自動でタグ付けを行っています。
しかし正規表現による部分一致でタグづけを行っているため、精度がいまいち・・・。
形態素解析を導入したいのですが、ライブラリ導入して、設定してテストして、、の時間がない。
そこで、さくっとGoogle Natural LanguageAPIを利用して、記事中のキーワード抽出を行い、精度を向上させます。
FuelPHPを利用して、最新のGoogle Natural Languageにつないでみます。
Google Natural Language とは
- 特定の文章のキーワードを抽出する
- その文章がどんなカテゴリに当たるか解析をする
- その文章のポジティブ度、ネガティブ度といった感情分析
ができるツールです。
今回は1.のキーワード抽出を利用します。
工夫したところ
Google謹製のAPIクライアントライブラリは利用せず、さくっとcurlで叩いて結果を取得しましょう。
しかし、素phpのcurlライブラリは、エラーハンドリングのために何行もコードを書かなければいけません。
ここはFuelPHPのライブラリを利用して、めんどくさいエラーハンドリングはフレームワークに任せましょう。
正しい怠惰は正義です(今考えた)。
準備
GCPのサービスアカウントに対してNatural Language APIの有効化
公式ドキュメントを参考にして、利用したいプロジェクトのサービスアカウント に対して、Natural Language APIを有効にします。
gcloudコマンドも必要になるので、導入していない場合は導入してください。
curlでつながるか検証する
開発が進んでから泣きを見る前に、curlコマンドを叩いて、ネットワーク的につながるか、レスポンスはどれくらいで返ってくるか、確認しましょう。
あ、料金の見積もりも忘れずに。 😉
公式ドキュメントの「コマンドライン」というタブにサンプルコードが載っています。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
$ export GOOGLE_APPLICATION_CREDENTIALS="サービスアカウント 鍵のパス" curl -X POST \ -H "Authorization: Bearer "$(gcloud auth application-default print-access-token) \ -H "Content-Type: application/json; charset=utf-8" \ --data "{ \ 'document':{ \ 'type':'PLAIN_TEXT', \ 'content':'Michelangelo Caravaggio, Italian painter, is known for \ \'The Calling of Saint Matthew\'.' }, 'encodingType':'UTF8' \ }" "https://language.googleapis.com/v1/documents:analyzeEntities" |
よくあるミス
こんなエラーが出た場合、
1 2 3 4 5 6 7 |
{ "error": { "code": 403, "message": "Request had insufficient authentication scopes.", "status": "PERMISSION_DENIED" } } |
下記を実行したターミナルとは別ウィンドウで実行していませんか?
1 |
export GOOGLE_APPLICATION_CREDENTIALS="サービスアカウント 鍵のパス" |
別シェルとなるので、都度exportして環境変数を設定してください。cronで実行する時も別シェルとなるので、cron中などで設定してくださいね。
下記のようなリクエストが返ってくれば成功です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
{ "entities": [ { "name": "Michelangelo Caravaggio", "type": "PERSON", "metadata": { "mid": "/m/020bg", "wikipedia_url": "https://en.wikipedia.org/wiki/Caravaggio" }, "salience": 0.82904786, "mentions": [ { "text": { "content": "Michelangelo Caravaggio", "beginOffset": 0 }, "type": "PROPER" }, { "text": { "content": "painter", "beginOffset": 33 }, "type": "COMMON" } ] }, { "name": "Italian", "type": "LOCATION", "metadata": {}, "salience": 0.13981608, "mentions": [ { "text": { "content": "Italian", "beginOffset": 25 }, "type": "PROPER" } ] }, { "name": "The Calling of Saint Matthew", "type": "EVENT", "metadata": { "mid": "/m/085_p7", "wikipedia_url": "https://en.wikipedia.org/wiki/The_Calling_of_St_Matthew_(Caravaggio)" }, "salience": 0.031136045, "mentions": [ { "text": { "content": "The Calling of Saint Matthew", "beginOffset": 70 }, "type": "PROPER" } ] } ], "language": "en" } |
FuelPHPで実装
curlコマンドを利用してリクエストできることが確認できたので、いよいよFuelPHP経由でリクエストを投げる実装をしていきます。
こちらは記事取り込みバッチの中で実装しています。
ネットワーク起因など何かしらの理由で接続に失敗しても、記事の取り込み自体は継続したいので、例外が発生してもスローせずログだけ出力します。
(スローするとバッチの実行そのものが終了してしまうため)
素phpのcurlライブラリだと、httpステータスコードをみたり、エラーかどうかのフラグを見たりしないといけないのでかなり楽になりました。
(その場合の実装方法はこちらのページが参考になります)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
/** * @param $article 記事情報 * @return array */ public function fetch_natural_language_tags($article) { try { $nl_tag_words = array(); $cmd = 'gcloud auth application-default print-access-token'; exec($cmd, $output); $token = \Arr::get($output, 0); $url = 'https://language.googleapis.com/v1/documents:analyzeEntities'; $curl = \Request::forge($url, 'curl'); $curl->set_method('post'); $curl->set_header('Content-Type', 'application/json; charset=utf-8'); $curl->set_header('Authorization', "Bearer $token"); $curl->set_options(array( CURLOPT_HEADER => true, CURLOPT_FOLLOWLOCATION => true, CURLOPT_FRESH_CONNECT => true, CURLOPT_SSL_VERIFYHOST => false, CURLOPT_MAXREDIRS => 10, CURLOPT_CONNECTTIMEOUT => 10, ) ); $payload = array( 'document' => array ( 'type' => 'PLAIN_TEXT', 'content' => \Arr::get($article, 'article_body'), ), 'encodingType' => 'UTF8' ); $json = \Format::forge($payload)->to_json(); $curl->set_params($json); $curl->set_auto_format(true); $curl->execute(); $json = $curl->response(); $ret = json_decode($json,true); $nl_tag_words = array_column(\Arr::get($ret, 'entities'), 'name'); return $nl_tag_words; } catch (\Exception $e) { // タグ付に失敗しても記事の取り込みは継続する。 \Log::error($e); return $nl_tag_words; } } |
まとめ
今回はFuelPHPのcurlライブラリ経由で、Natural Language APIにリクエストを投げる方法を紹介しました。いかがだったでしょうか。
明日は、ytpcasさんによる「UiPathでSalesforceの特定の項目を更新する。」です。
引き続き、GMOアドマーケティングAdvent Calendar 2020をお楽しみください!
■エンジニア採用ページ ~福利厚生や各種制度のご案内はこちら~
https://www.gmo-ap.jp/engineer/
■noteページ ~ブログや採用、イベント情報を公開中!~
https://note.gmo-ap.jp/
マイブームは、ペーパードライバー卒業・天体観測・アマチュア無線・BCL受信・カセットテープデッキのメンテ修理・登山とか。
写真は飼っている文鳥のおつゆちゃん。