スポンサーリンク

curl_multiでYAHOOキーフレーズ抽出APIを並列呼び出し

WEBアプリ
スポンサーリンク

並列処理で高速化

つい書。の中で、複数のツイートからそれぞれキーフレーズを抽出するために、YAHOOキーフレーズ抽出APIを複数回呼び出しています。並列呼び出しにすることで処理時間が短縮されたので、その実装方法をメモっておきます。
皆様の参考になれば私もうれしいです。

並列にする前の処理プログラム。

//$iCountはtwitterで取ってきたつぶやきの数。
$output = "xml"; 
for($iTweet = 10; $iTweet<$iCount; $iTweet++){
  $word = $oObj[$iTweet]->{'text'};
  $request  = "http://jlp.yahooapis.jp/KeyphraseService/V1/extract?";
  $request .= "appid=".$id."&sentence=".urlencode($word)."&output=".$output;
  $responsexml = simplexml_load_file($request);
  $result_num = count($responsexml->Result);
  if($result_num > 0){
    $result = $responsexml->Result[0];
  }
}

並列処理にしたプログラム。

$iCount = sizeof($oObj);
	$mh = curl_multi_init();
	$url = array();
	for($iTweet = 10; $iTweet<$iCount; $iTweet++){
		$word = $oObj[$iTweet]->{'text'};
	        //URLの組み立て
		array_push($url, "http://jlp.yahooapis.jp/KeyphraseService/V1/extract?appid=" . $id . "&sentence=" . urlencode($word));
	}//end for
	foreach ($url as $u) {
		$ch = curl_init();
		curl_setopt_array($ch, array(
		CURLOPT_URL            => $u,
		CURLOPT_RETURNTRANSFER => true,
		CURLOPT_TIMEOUT        => $TIMEOUT,
		CURLOPT_CONNECTTIMEOUT => $TIMEOUT,
		));
		curl_multi_add_handle($mh, $ch);
	}
	do {
		$stat = curl_multi_exec($mh, $running); //multiリクエストスタート
	} while ($stat === CURLM_CALL_MULTI_PERFORM);
	if ( ! $running || $stat !== CURLM_OK) {
		throw new RuntimeException('リクエストが開始出来なかった。マルチリクエスト内のどれか、URLの設定がおかしいのでは?');
	}
	$Keyword=array();
	do switch (curl_multi_select($mh, $TIMEOUT)) { //イベントが発生するまでブロック
		// 最悪$TIMEOUT秒待ち続ける。
		case -1: //selectに失敗。ありうるらしい。 https://bugs.php.net/bug.php?id=61141
			usleep(10); //ちょっと待ってからretry。ここも別の処理を挟んでもよい。
			do {
				$stat = curl_multi_exec($mh, $running);
			} while ($stat === CURLM_CALL_MULTI_PERFORM);
			continue 2;
		case 0:  //タイムアウト -> 必要に応じてエラー処理に入るべきかも。
			continue 2; //ここではcontinueでリトライします。
		default: //どれかが成功 or 失敗した
			do {
				$stat = curl_multi_exec($mh, $running); //ステータスを更新
			} while ($stat === CURLM_CALL_MULTI_PERFORM);
			do if ($raised = curl_multi_info_read($mh, $remains)) {
				//変化のあったcurlハンドラを取得する
				$info = curl_getinfo($raised['handle']);
				//echo "{$info['url']}: {$info['http_code']}\n";
				$response = curl_multi_getcontent($raised['handle']);
				if ($response === false) {
					//エラー。404などが返ってきている
				} else {
					//正常にレスポンス取得
					//戻り値(オブジェクト)からループでデータを取得する
					$responsexml = simplexml_load_string($response);
					$result_num = count($responsexml->Result);
					if($result_num > 0){
						$result = $responsexml->Result[0];
						array_push($Keyword,$result->Keyphrase);
					}
				}
				curl_multi_remove_handle($mh, $raised['handle']);
				curl_close($raised['handle']);
			} while ($remains);
			//select前に全ての処理が終わっていたりすると
			//複数の結果が入っていることがあるのでループが必要
		} while ($running);
		curl_multi_close($mh);
	}

結果

10回呼び出した結果ですが、
並列処理前:0.13秒
並列処理後:0.037秒
とかなり早くなります。

ちなみに、つい書。の処理時間内訳は、
0.842秒 twitter
0.037秒 yahoo
3.679秒 amazon

って!一番時間かかってないところを攻めてどうする!!

AMAZONを時間短縮する方法は非常に悩みました。これは長くなりますからまたの機会に書くことにします。

WEBアプリ
スポンサーリンク
スポンサーリンク
良いなと思ったら、シェアしてください
このブログをフォローする
Findelight

コメント