
PHPでElasticsSearchを扱うライブラリ
本当はサクッとrubyで実装したかったけど、ElasticSearchと連携させたいサービスがPHPだったので、探してみた所、良さげなライブラリ発見! ドキュメントがあまりないので、基本ソース追いながらになるけど、けっこう使い易いので紹介。
ググってもほとんど引っ掛からないけど、あまり使われていないのかな。
インストール
おなじみcomposerで簡単にインストールできます。
1 2 3 4 5 |
{ "require": { "ruflin/Elastica": "1.3.0.0" } } |
下記のコマンド実行してElasticaインストール終了〜。
1 |
[]$ php composer.phar install |
Elatica 使用方法 (サンプルコード)
いくつかコード例を記述。
サンプルコード1) Logstashのデータを取得したい
Logstashの取得する場合のシンプルなコード。簡単に叩くことができます。バックスラッシュの記述がどうも慣れないですが・・。
1 2 3 4 5 6 7 8 9 |
$client = new \Elastica\Client(array( 'host' => 'localhost', 'port' => 9200 )); $index = $client->getIndex('logstash-2014.03.20'); $elasticaQuery = array(); $elasticaResultSet = $index->search($elasticaQuery); $response = $elasticaResultSet->getResponse(); $data = $response->getData(); |
サンプルコード2) フィルタを入れて検索したい
必要なフィルタを追加したBoolAndクラスをQueryクラスにaddするという流れ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
$client = new \Elastica\Client(array( 'host' => 'localhost', 'port' => 9200 )); $termFilter = new \Elastica\Filter\Term(); $termFilter->setTerm('name', 'kuman_r'); $andFilter = new \Elastica\Filter\BoolAnd(); $andFilter->addFilter($termFilter); $queryFilter = new \Elastica\Query\Filtered(null, $andFilter); $query = new \Elastica\Query(); $query->setQuery($queryFilter); $index = $client->getIndex('users'); $result = $index->search($query); $response = $result->getResponse(); |
サンプルコード3) ファセットを追加したい。
ファセットも簡単に追加できます。追加ファセットクラスを生成してaddFacetするだけです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
$client = new \Elastica\Client(array( 'host' => 'localhost', 'port' => 9200 )); $facetTerms = new \Elastica\Facet\Terms('My Terms'); $facetTerms->setFields(array('age')); $facetTerms->setSize(30); $facetTerms->setOrder("count"); $query = new \Elastica\Query(); $query->addFacet($facetTerms); $index = $client->getIndex('users'); $result = $index->search($query); $response = $result->getResponse(); |
サンプルコード4) ファセットにフィルターを追加したい。
サンプルコード2と3の組み合わせ。Elasticaを使えばけっこう直感的に書けてしまいます。
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 |
$client = new \Elastica\Client(array( 'host' => 'localhost', 'port' => 9200 )); // ファセット用のフィルター $range = new \Elastica\Query\Range(); $range->addField("year", array("from" => "2010", "to" => "2013")); $filterQuery = new \Elastica\Filter\Query(); $filterQuery->setQuery($range); $facetFilter = new \Elastica\Filter\BoolAnd(); $facetFilter->addFilter($filterQuery); // ファセット $facetTerms = new \Elastica\Facet\Terms('My Facets With Filter'); $facetTerms->setFields(array('name')); $facetTerms->setSize(5); $facetTerms->setOrder("count"); $facetTerms->setFilter($facetFilter); $query = new \Elastica\Query(); $query->addFacet($facetTerms); $index = $client->getIndex('users'); $result = $index->search($query); $response = $result->getResponse(); |
レスポンスフォーマット
レスポンスのフォーマット例です。リクエストによって多少中身は変わると思いますが、参考までに。
尚、_sourceの部分にデータが入ってきますが省略してます。
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 |
object(Elastica\Response)#39 (6) { ["_queryTime":protected]=> float(0.0040650367736816) ["_responseString":protected]=> string(4491) "*********************" ["_error":protected]=> bool(false) ["_transferInfo":protected]=> array(22) { ["url"]=> string(43) "http://localhost:9200/users/_search" ["content_type"]=> string(31) "application/json; charset=UTF-8" ["http_code"]=> int(200) ["header_size"]=> int(88) ["request_size"]=> int(271) ["filetime"]=> int(-1) ["ssl_verify_result"]=> int(0) ["redirect_count"]=> int(0) ["total_time"]=> float(0.004035) ["namelookup_time"]=> float(0.000111) ["connect_time"]=> float(0.000562) ["pretransfer_time"]=> float(0.00057) ["size_upload"]=> float(127) ["size_download"]=> float(4491) ["speed_download"]=> float(1113011) ["speed_upload"]=> float(31474) ["download_content_length"]=> float(4491) ["upload_content_length"]=> float(0) ["starttransfer_time"]=> float(0.00395) ["redirect_time"]=> float(0) ["certinfo"]=> array(0) { } ["request_header"]=> string(144) "GET /users/_search HTTP/1.1 Host: localhost:9200 Accept: */* Content-Length: 127 Content-Type: application/x-www-form-urlencoded" } ["_response":protected]=> array(5) { ["took"]=> int(2) ["timed_out"]=> bool(false) ["_shards"]=> array(3) { ["total"]=> int(5) ["successful"]=> int(5) ["failed"]=> int(0) } ["hits"]=> array(3) { ["total"]=> int(42527) ["max_score"]=> float(1) ["hits"]=> array(1) { [0]=> array(5) { } } ["_index"]=> string(9) "users" ["_type"]=> string(7) "history" ["_id"]=> string(22) "******************" ["_score"]=> float(1) ["_source"]=> array(71) { /* 省略 */ } ["_status":protected]=> int(200) } |
その他、Elasticaの設定
クエリタイム取得
デバックモードをオンにするとレスポンスにクエリタイムを追加してくれます。
1 2 3 4 5 |
define("DEBUG", true); $response = $elasticaResultSet->getResponse(); print "- Query Time : " . $response->getQueryTime() . "\r\n"; - Query Time : 0.010284900665283 |
ログ出力
Elasticaのログを出力用には、Elastica::Logクラスが用意されています。
1 2 |
$log = new \Elastica\Log('app/tmp/logs/elastica.log'); $client->setLogger($log); |
CakePHPのスクリプトで記述したい場合
CakePHPでElastia。まんまです。
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 |
app/Console/Command/ElasticSearchShell.php <?php /** * ElasticSearchShell file */ require_once APP_DIR . '/../vendors/autoload.php'; App::uses('Shell', 'Console'); App::uses('CakeLog', 'Log'); /** * ElasticSearch Shell */ class ElasticSearchShell extends Shell { /** * startup * * @access public * @return void */ public function startup() { } /** * 商品負荷情報を生成 * * @access public * @return void */ public function main() { $elasticaClient = new \Elastica\Client(); /* クエリ記述 */ } } |
1 |
[]$ ./app/Console/cake ElasticSearch |
エラー対応
リクエストエラー
これ別にElastica関係なく、ネットワーク環境に依存したエラーですが・・一応。
最初、なぜかElastiaでElasticsearchを叩けないと思ったらプロキシに捕まっていて、プロキシ無効にしたら無事叩けましたというお話です・・。
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 |
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <HTML><HEAD> <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=EUC-JP"> <TITLE>エラー: リクエストされた URL は取得できませんでした</TITLE> <STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}PRE{font-family:sans-serif}--></STYLE> </HEAD><BODY> <H1>エラー</H1> <H2>リクエストされた URL は取得できませんでした</H2> <HR noshade size="1px"> <P> 以下の URL を取得した際に: <A HREF="http://localhost:9200/members/_search">http://localhost:9200/_search</A> <P> 次のエラーが発生しました: <UL> <LI> <STRONG> 不正なリクエストです. </STRONG> </UL> <P> HTTP によるリクエストが不正です.可能性のある問題は以下の通りです: <UL> <LI>リクエスト方法が指定されていないか,あるいは不明です. <LI>URL がありません. <LI>HTTP 識別文字列がありません (HTTP/1.0). <LI>リクエストが長すぎます. <LI>POST/PUT リクエストにおいて Content-Length がありません. <LI>ホスト名に不正な文字が使われています: アンダースコアは使えません. </UL> </P> <BR clear="all"> <HR noshade size="1px"> <ADDRESS> Generated Tue, 02 Jun 2014 00:00:00 GMT by proxy.****.*** (squid/2.5.STABLE7) </ADDRESS> </BODY></HTML> |
環境変数http_proxyを無効にしたら無事叩けました。
1 2 3 |
public function startup() { putenv("http_proxy="); } |
Elastica関連サイト
- Elastica http://elastica.io/
- Elastica Giuhub https://github.com/ruflin/Elastica