gooラボ 形態素解析APIを試してみる

これはPowerShell Advent Calendar 2014 : ATND 13日目の記事です。

PowerShellREST API

近年、RESTfullなAPIで提供されるWebサービスが非常に増えているように感じます。

そんな中、ちょっと気になるAPIがあったら、気軽に試したりしたいですよね。

PowerShellを使えば、お手軽にREST API がお試しできますよ!」

という事で、最近見かけた、gooラボ形態素解析APIを試してみたいと思います。

NTTレゾナント、gooで開発・蓄積した「日本語解析API」を公開、ビッグデータ解析機能なども提供予定:CodeZine

と、4種類のAPIが提供されています。
この中から今回は形態素解析APIを使います。
上の記事の内容を見る限りですと、文を語句に分割するだけ?のように思えますが、「PowerShell, 名詞, パワーシェル」の様に、分割した「語句」の「品詞(形態素)」と「読み」を付けて返してくれます。

形態素解析API:日本語文字列を語句に分割する技術 - gooラボ

Invoke-RestMethod でPOST

ではAPIを早速試してみます。APIの説明には

  • リクエスト先URL
    https://labs.goo.ne.jp/api/morph
  • リクエストパラメータ
    application/x-www-form-urlencoded、application/json形式でのPOSTを受け付けます。

とあります。
Invoke-RestMethodコマンドレットで試してみます。今回はapplication/jsonでPOSTします。

リクエストパラメータ

  • app_id アプリケーションID。
    必須項目。 こちら(https://labs.goo.ne.jp/apiusage/)で取得した、アプリケーションIDを設定します。(IDの取得にはGitHubアカウントが必要になります。)
  • request_id リクエストID。
    省略時は”labs.goo.ne.jp[タブ文字]リクエスト受付時刻[タブ文字]連番”となります。
  • sentence 解析対象テキスト。
    必須項目。
  • info_filter 形態素情報フィルタ。
    form(表記)、pos(形態素)、read(読み)のうち、出力する情報を文字列で指定します。
  • pos_filter 形態素品詞フィルタ。
    出力対象とする品詞を”|”で区切って指定します。

リクエストパラメータは、HashTebleで作成し、Invoke-RestMethodBodyパラメータに指定します。
今回は、とりあえず必須項目のapp_idsentence のみを使用します。

PS C:\> $text = "Windows PowerShell は、マイクロソフトが開発した拡張可能なコマンドラインインターフェース (CLI) シェルおよびスクリプト言語である。" + `
"オブジェクト指向に基づいて設計されており、.NET Framework 2.0 を基盤としている。"

PS C:\> $res = Invoke-RestMethod -Method Post `
  -Uri https://labs.goo.ne.jp/api/morph `
  -Body @{ 
    app_id = "your application id";
    sentence = $text; 
  }

レスポンスの取得

レスポンスパラメータは、以下の通りです。

  • request_id リクエストID。
    リクエストと同じ値となります。
  • info_filter 形態素情報フィルタ。
    入力と同じ値となります。
  • pos_filter 形態素品詞フィルタ。
    入力と同じ値となります。
  • word_list 形態素リスト。
    形態素リストは文ごとに分かれた文単位形態素リストの配列となります。
    文単位形態素リストは形態素情報の配列で、形態素情報には表記・形態素・読みのうち形態素情報フィルタで指定された要素が含まれます。
    例:
    • 態素リスト: [[[“文”],[“1つ”],[“。”]],[[“文”],[“2つ”],[“。”]]]
    • 文単位形態素リスト: [[“文”],[“1つ”],[“。”]]
    • 形態素情報: [“文”]

Invoke-RestMethod では、JSONで帰ってきたレスポンスパラメータをPSObjectにデシリアライズして返してくれます。大変便利ですね。

PS:\> $res

request_id                              word_list                              
----------                              ---------                              
labs.goo.ne.jp    1418127883    0       {System.Object[] System.Object[] Sys...

解析結果の本体は、word_listにあります。展開してみましょう。

PS C:\> $res.word_list |%{$_}

Windows
åè©
ã¦ã£ã³ãã¼ãº
 
空ç½
ï¼
Power
åè©
ãã¯ã¼
Shell
åè©
ã·ã§ã«

...

ん!? 文字化けしちゃってますね

レスポンスのエンコーディングについて

Invoke-RestMethod コマンドレットは、レスポンスヘッダ(Content-Type ;charset?) を見てエンコーディングしてくれるようなのですが、 このAPIのレスポンスヘッダにはcharsetの指定が無いようなのです。
その場合ってどうなるの?

以下にその答えがありました。
https://social.technet.microsoft.com/Forums/windowsserver/en-US/d795e7d2-dcf1-4323-8e06-8f06ce31a897/bug-invokerestmethod-and-utf8-data?forum=winserverpowershell

どうやらcahrsetの指定がない場合は ISO-8859-1エンコーディングされるらしい。

確認してみましょう。生のレスポンスが必要なのでInvoke-RestMethodではなく、Invoke-WebRequest コマンドの方を使います。
レスポンスの Contentに格納されている文字列を一旦Byte列に戻してからUtf-8エンコーディングし直してみます。

PS C:\> $res = Invoke-WebRequest -Method Post `
  -Uri https://labs.goo.ne.jp/api/morph `
  -Body @{ 
    app_id = "your application id";
    sentence = $text; 
  }

PS C:\> $res.Content

{"request_id":"labs.goo.ne.jp\t1418129359\t0","word_list":[[["Windows","åè©"
,"ã¦ã£ã³ãã¼ãº"],[" ","空ç½","ï¼"],["Power","åè©","ãã¯ã¼"],["Sh
ell","åè©","ã·ã§ã«"],[" ","空ç½","ï¼"],["ã¯","é£ç¨å©è©","ã"],["
...

PS C:\> [System.Text.Encoding]::Utf8.GetString( `
  [System.Text.Encoding]::GetEncoding("ISO-8859-1").GetBytes($res.Content))

{"request_id":"labs.goo.ne.jp\t1418129359\t0","word_list":[[["Windows","名詞","ウィ
ンドーズ"],[" ","空白","$"],["Power","名詞","パワー"],["Shell","名詞","シェル"],[" ","空白","$"],
["は","連用助詞","ハ"],["、","読点","$"],["マイクロソフト","名詞","マイクロソフト"],["が","格助詞","ガ"],["開発
...

おおー、ちゃんと読めるようになりました!

なお、レスポンスのクラスにはRawContentStream というプロパティがあり、ここからエンコード前のByte配列が取れるので、 こちらを使った方が1手間減って良いかもしれません。

PS C:\>$data = [System.Text.Encoding]::Utf8.GetString($res.RawContentStream.GetBuffer()))

データをもう少し扱いやすくする

解析結果の本体が格納された word_list は配列が入れ子になっていて扱いづらいので、少し手を加えます。

# 以下のように入れ子になっているのを
単語(n) = [form(表記), pos(形態素), read(読み)]
文(n) = [単語(1), 単語(2), 単語(3),...]
word_list = [文(1), 文(2), 文(3),...]

# 以下のように平坦化します
word_list = [@{SentenceNum(文番号), Form(表記), Pos(形態素), Read(読み)},
 @{SentenceNum(文番号), Form(表記), Pos(形態素), Read(読み)},
 @{SentenceNum(文番号), Form(表記), Pos(形態素), Read(読み)},
 @{SentenceNum(文番号), Form(表記), Pos(形態素), Read(読み)},...]
PS C:\> $obj = $data | ConvertFrom-Json | %{$_.word_list} | % -Begin{ $n=0 } {  
  $_ | % { [PSCustomObject]@{ SentenceNum=$n; Form=$_[0]; Pos=$_[1]; Read=$_[2] } }; $n++;
}

PS C:\> $obj

 SentenceNum Form                Pos                 Read               
 ----------- ----                ---                 ----               
           0 Windows             名詞                  ウィンドーズ             
           0                     空白                  $                  
           0 Power               名詞                  パワー                
           0 Shell               名詞                  シェル                
           0                     空白                  $                  
           0 は                   連用助詞                ハ                  
           0 、                   読点                  $                  
           0 マイクロソフト             名詞                  マイクロソフト            
           0 が                   格助詞                 ガ                  
           0 開発                  名詞                  カイハツ               
           0 し                   動詞活用語尾              シ                  
           0 た                   動詞接尾辞               タ                  
           0 拡張                  名詞                  カクチョウ              
           0 可能                  名詞                  カノウ                
           0 な                   判定詞                 ナ                  
           0 コマンド                名詞                  コマンド               
           0 ライン                 名詞                  ライン                
           0 インターフェース            名詞                  インターフェース           
           0                     空白                  $                  
           1 (                   括弧                  $                  
           1 CLI                 Alphabet            シーエルアイ             
           1 )                   括弧                  $                  
           1                     空白                  $                  
           2 シェル                 名詞                  シェル                
           2 および                 連体詞                 オヨビ                
           2 スクリプト               名詞                  スクリプト              
           2 言語                  名詞                  ゲンゴ                
           2 で                   判定詞                 デ                  
           2 あ                   動詞語幹                ア                  
           2 る                   動詞接尾辞               ル                  
           2 。                   句点                  $                  

これで大分扱いやすくなったと思います。
後の集計などは、PowerShellならお手の物ですよね。

名詞のみを抽出する

PS C:\> $obj | where {$_.Pos -eq "名詞"} | %{$_.Form}
Windows
Power
Shell
マイクロソフト
開発
拡張
可能
コマンド
ライン
インターフェース
シェル
スクリプト
言語
オブジェクト
指向
設計
NET
Framework
基盤

形態素(品詞)のランキング

$obj | Group-Object Pos | Sort-Object count -Descending

Count Name        Group                                                       
----- ----        -----
   19 名詞        {@{SentenceNum=0; Form=Windows; Pos=名詞; Read=ウィンドーズ}, @{SentenceNum=0; Form=Power; Pos=名詞; Read=パワー}, @{SentenceNum=0; Form=Shell; Pos=名詞; Read=シェル}, @{SentenceNum=0; Form=マイク...
    7 空白        {@{SentenceNum=0; Form= ; Pos=空白; Read=$}, @{SentenceNum=0; Form= ; Pos=空白; Read=$}, @{SentenceNum=0; Form= ; Pos=空白; Read=$}, @{SentenceNum=1; Form= ; Pos=空白; Read=$}...}       
    7 動詞接尾辞   {@{SentenceNum=0; Form=た; Pos=動詞接尾辞; Read=タ}, @{SentenceNum=2; Form=る; Pos=動詞接尾辞; Read=ル}, @{SentenceNum=3; Form=て; Pos=動詞接尾辞; Read=テ}, @{SentenceNum=3; Form=れ; Pos=動詞接尾辞; Rea...
    4 格助詞      {@{SentenceNum=0; Form=が; Pos=格助詞; Read=ガ}, @{SentenceNum=3; Form=に; Pos=格助詞; Read=ニ}, @{SentenceNum=3; Form=を; Pos=格助詞; Read=ヲ}, @{SentenceNum=3; Form=として; Pos=格助詞; Read=トシテ}}  
    4 動詞語幹    {@{SentenceNum=2; Form=あ; Pos=動詞語幹; Read=ア}, @{SentenceNum=3; Form=基づ; Pos=動詞語幹; Read=モトヅ}, @{SentenceNum=3; Form=お; Pos=動詞語幹; Read=オ}, @{SentenceNum=3; Form=い; Pos=動詞語幹; Read...
    3 動詞活用語尾 {@{SentenceNum=0; Form=し; Pos=動詞活用語尾; Read=シ}, @{SentenceNum=3; Form=い; Pos=動詞活用語尾; Read=イ}, @{SentenceNum=3; Form=さ; Pos=動詞活用語尾; Read=サ}}                                        
    3 句点        {@{SentenceNum=2; Form=。; Pos=句点; Read=$}, @{SentenceNum=3; Form=.; Pos=句点; Read=$}, @{SentenceNum=3; Form=。; Pos=句点; Read=$}}                                                    
    2 読点        {@{SentenceNum=0; Form=、; Pos=読点; Read=$}, @{SentenceNum=3; Form=、; Pos=読点; Read=$}}                                                                                              
    2 判定詞      {@{SentenceNum=0; Form=な; Pos=判定詞; Read=ナ}, @{SentenceNum=2; Form=で; Pos=判定詞; Read=デ}}                                                                                           
    2 括弧        {@{SentenceNum=1; Form=(; Pos=括弧; Read=$}, @{SentenceNum=1; Form=); Pos=括弧; Read=$}}                                                                                              
    1 連用助詞     {@{SentenceNum=0; Form=は; Pos=連用助詞; Read=ハ}}                                                                                                                                      
    1 Alphabet   {@{SentenceNum=1; Form=CLI; Pos=Alphabet; Read=シーエルアイ}}                                                                                                                           
    1 連体詞      {@{SentenceNum=2; Form=および; Pos=連体詞; Read=オヨビ}}                                                                                                                                   
    1 Number     {@{SentenceNum=3; Form=2.0; Pos=Number; Read=ニテンゼロ}}       

まとめ

(レスポンスのエンコーディングのところは予定外でしたが、) Invoke-RestMethodあるいはInvoke-WebRequest コマンドレット1つでWeb APIを試すことが出来ました。

返却されるJSON(やXML)のデータも直ぐにオブジェクトとして扱うことが出来るのも良いですね。

皆さんも、気になるWeb API がありましたら、PowerShellでお試ししてみましょう!