OpenAIのAPIをdtn.jpのサイト検索に実装した際、「ディレクトリ型検索エンジンとは?」と話し言葉っぽく検索をしても、登録サイトが一つもヒットしないことに気がつきました。

そこで、登録サイトが少しでも多く検索結果にヒットするように、日本語形態素解析で自然文からキーワードを抽出することを思いつきまして、Yahooの日本語形態素解析APIを使ってみたと先日の記事でご紹介していました。

この記事では、そのYahoo日本語形態素解析APIをPHPで使う方法を中心に、検索プログラムを修正した流れについてご紹介しようと思います。

自然文(話し言葉)による検索の問題点

これまで、dtn.jpの検索プログラムでは、検索されたワードをそのまま使って「サイトタイトル」「サイト説明文」などに部分一致検索をしていました。

ディレクトリ型検索エンジン」と検索をすれば、「ディレクトリ型検索エンジンdtn」や「SEO対策ディレクトリ型検索エンジンBroval」、サイト説明文に「ディレクト型検索エンジン」の単語がある「有名サイトのリンク集 MS-LP」といった登録サイトさんがヒットしてくれますが、例えば、「ディレクトリ型検索エンジンとは?」と検索をされてしまうと、そんなサイト名・サイト説明文を持つサイトが一つも登録されていないため、何もサイトがヒットしなくなってしまいます。

SQLの部分一致検索は↓のような感じです。

SELECT * FROM 登録サイト WHERE サイトタイトル LIKE "%ディレクトリ型検索エンジンとは%";

ディレクトリ型検索エンジン とは」のように、スペースを挟んでもらえればOR検索をするので、これらのサイトをヒットさせることもできるのですが、話し言葉検索でそのようなことをするはずもないので、ヒットさせるには何かしらの対応が必要になります。

自然文検索でもGoogleなら問題にならない

Googleやbingのように、WEBから恐ろしく膨大な量の情報をページ単位で収集していて、それを検索対象にするのであれば、「ディレクトリ型検索エンジンとは」のキーワードにヒットするページを抽出する方が逆に良い結果が得られるでしょうが、こちらは登録8000サイトの「サイトタイトル」「サイト説明文」しか検索対象データがありませんので、自然文での検索で登録サイトをヒットさせるのはほぼ不可能な感じです。

自然文検索でも登録サイトをヒットさせたい

とはいえ、せっかく検索プログラムにOpenAIのAPIを組み込み、「AI検索」をしたらレスポンスが返るようにしてみたので、自然文検索をされた時にも、なんとかキーワードだけをうまく抽出して、登録サイトが少しでもヒットするようしてみたくなりました。

そこで、検索された自然文(話し言葉)からキーワードをうまく抜き出して「自然文検索」→「キーワード検索」ができるよう、文章の形態素解析をしてみることにしました。

形態素とは何か

文章を言語的に意味を持つ最小単位に分け、それぞれの品詞を判別することを形態素解析といいます。文や文章を構成する最小単位となる語または語句のことを形態素といい、日本語の場合には名詞や動詞、形容詞や形容動詞、助詞や副詞や接続詞などを形態素ということができます。なんとなく学校で習った気がしますね。

形態素解析をする方法とは

文章の形態素解析をするには、膨大な辞書データを使って、文章を単語解析をすることが必要です。もちろん、そんな辞書データを個人で持っているはずもないので、ひとまず「日本語 形態素解析 API」で何か使えそうなAPIが何かないかを調べてみました。すると、すぐに見つかりました。

日本語 形態素解析 APIとGoogleで調べてみた結果

Yahooデベロッパーネットワーク」、「gooラボ」といった大手のAPIに形態素解析APIが用意されています。全く縁がない世界でしたが、ある程度以上のシステム開発をする方にとっては必須の機能ということのようです。

そこで、毎度おなじみのYahoo APIで試してみることにしました。

Yahoo日本語形態素解析API

日本語形態素解析(V2)」のページを見るとサンプルのレスポンスデータが置かれています。

↓は「美しい水車小屋の娘」という文章を形態素に分けた結果のようですが、しっかりと、「形容詞」や「名詞」といった品詞情報をつけて単語を返してくれていました。シンプル・分かりやすいレスポンスデータで、さすがはYahooですね。

{
  "id": "1234-1",
  "jsonrpc": "2.0",
  "result": {
    "tokens": [
      [
        "美しい",
        "うつくしい",
        "美しい",
        "形容詞",
        "*",
        "イ形容詞イ段",
        "基本形"
      ],
      [
        "水車",
        "すいしゃ",
        "水車",
        "名詞",
        "普通名詞",
        "*",
        "*"
      ],
      [
        "小屋",
        "こや",
        "小屋",
        "名詞",
        "普通名詞",
        "*",
        "*"
      ],
      [
        "の",
        "の",
        "の",
        "助詞",
        "接続助詞",
        "*",
        "*"
      ],
      [
        "娘",
        "むすめ",
        "娘",
        "名詞",
        "普通名詞",
        "*",
        "*"
      ]
    ]
  } 
}

形態素解析の結果から名詞だけ抜き出す

このレスポンスデータから、品詞が「名詞」のものだけ抜き出して検索キーワードとして使えば、やりたかった「自然文検索」→「キーワード検索」をうまくやることができそうです。先ほどのレスポンスデータであれば、「水車 小屋 娘」だけを抜き出してOR検索にもっていくという感じです。

サンプルプログラムを確認する

日本語形態素解析(V2)」のマニュアルを確認してみると、リクエストURLの投げ方やパラメータなどの説明がシンプルに書かれていました。

Yahoo日本語形態素解析APIの説明

※印の注意書きをみると、jsonをPOSTして送信することリクエストにアプリケーションIDの設定も必要なので、詳細はサンプルコードを見てといったことが書かれています。

※GETリクエストには対応していません。
※アプリケーションIDをリクエストに付与する必要があります。詳細はサンプルコードをご覧ください。

https://developer.yahoo.co.jp/webapi/jlp/ma/v2/parse.html の説明文

Yahooのサンプルコード(python)

サンプルコードとしてpythonが置いてありました。リクエストヘッダに「Yahoo AppID: {}」といった形でAppIDを組み込んで投げる必要がありそうです。

import json
from urllib import request

APPID = "<あなたのアプリケーションID>"  # <-- ここにあなたのアプリケーションIDを設定してください。
URL = "https://jlp.yahooapis.jp/MAService/V2/parse"


def post(query):
    headers = {
        "Content-Type": "application/json",
        "User-Agent": "Yahoo AppID: {}".format(APPID),
    }
    param_dic = {
      "id": "1234-1",
      "jsonrpc": "2.0",
      "method": "jlp.maservice.parse",
      "params": {
        "q": query
      }
    }
    params = json.dumps(param_dic).encode()
    req = request.Request(URL, params, headers)
    with request.urlopen(req) as res:
        body = res.read()
    return body.decode()


response = post("美しい水車小屋の娘")
print(response)

curlを使ってJSON形式のデータをPOST

サンプルコードでは、PythonのRequestsライブラリを使ってJSONをPOSTしてありましたが、PHPでもcurlを使えばJSONのPOSTが簡単にできますので、使いなればcurlでやってみることにします。

curlの使い方が分からないという方は、以前の記事などをご参照下さい。

サンプルPHPプログラム

$APPID = "<あなたのアプリケーションID>";
$URL = "https://jlp.yahooapis.jp/MAService/V2/parse";
$text = "自然文";

$header = array(
 'User-Agent: Yahoo AppID: '.$APPID,
 'Content-type: application/json'
);

$params = json_encode(array(
 'id'		=>  '1111', //任意の値
 'jsonrpc'   =>  '2.0', //値は「2.0」
 'method'    =>  'jlp.maservice.parse', //値は「jlp.maservice.parse」
 'params'    =>  array('q'=> $text) //解析対象のテキスト文章
));

$curl = curl_init($URL);
$options = array(
 CURLOPT_POST => true,
 CURLOPT_HTTPHEADER => $header,
 CURLOPT_POSTFIELDS => $params,
 CURLOPT_RETURNTRANSFER => true,
);

curl_setopt_array($curl, $options);
if($Buff = curl_exec($curl)){
 //$BuffにJSONレスポンスデータが入るので、デコードして下さい。
}

こんな感じでcurlから自然文を投げてあげれば、JSONの解析データをとることができました。JSONをデコードすれば、単語と品詞をセットで集めることができるので、その中から【名詞】のキーワードだけで登録サイト検索をしてあげれば完成です。

おわりに

OpenAIのAPIから始まって、Yahoo日本語形態素解析APIを使った形態素解析までチャレンジすることになりました。

OpenAI APIのレスポンスが早ければ、質問を投げるついでに、回答文の中に「名詞」があったら【】を付けて返してねといった感じで質問をすれば、わざわざ日本語形態素解析APIを使わなくてもよいかもしれません。

実際にやってみたら、↓のような感じで名詞のものに【】を付けてもらうこともできました。全部ではないですけど。。。

ディレクトリ型検索エンジンとは何かを教えてください。回答文の中に名詞があった場合、その単語には【】を付けて返して下さい。

【ディレクトリ型検索エンジン】とは、ウェブサイトを【カテゴリ】に分けて検索することができる検索エンジンのことです。これにより、特定の【カテゴリ】に属するサイトを検索することができます。

OpenAIに質問してみた結果

まだまだAPIのレスポンスも回答精度も微妙なので無理ですが、いずれはAIのAPIが一つあれば、なんでも事足りるといった時代がくるのかもしれませんね。