一,索引管理
1,創建索引
$client = ClientBuilder::create()->build();
$param = [
"index"=>'my_index'
];
$response = $client->indices()->create($param);
你也可以再一個創建索引api中指定任何參數。所有得參數通常會注入請求體中得body參數下:
$hosts = [ '192.168.1.1:9200', // IP + Port '192.168.1.2', // Just IP 'mydomain.server.com:9201', // Domain + Port 'mydomain2.server.com', // Just Domain 'https://localhost', // SSL to localhost 'https://192.168.1.3:9200' // SSL to IP + Port ];
$client = ClientBuilder::create()
->setHost($host)// 指定主機域名
->setRetries(2) // 設置重連次數
->build();
$params = [
"index"=>'my_index',
"body"=>[
"settings"=>[
"number_of_shards"=>3,
"number_of_replicas"=>2
],
"mappings"=>[
"my_type"=>[
"_source"=>[
"enabled"=>true
],
"properties"=>[
"first_name"=>[
"type"=>"string"
"analyzer"=>"standard"
] ,
"age"=>[
"type"=>"integer"
]
]
]
]
]
];
$response = $client->indices()->create($params);
2,刪除一個索引
$client = ClientBuilder::create()->build();
$params = ['index'=>'my_index'];
$response = $client->indice()->delete($params);
3,Put Settings APi
Put Setting APi允許你更改索引的配置參數
$params = [
"index"=>'my_index',
"body"=>[
"settings"=>[
"number_of_replicas"=>0,
"refresh_interval"=>-1
]
]
];
$response = $client->indices()->putSettings($params);
Get Settings APi
Get Settings API可以讓你知道一個或多個索引的當前配置參數:
$params = ["index"=>"my_index"];
$response = $client->indices()->getSettings($params);
$params = [
"index"=>["my_index","my_index2"]
];
Put Mappings Api
Put Mappings Api允許你更改或增加一個索引的映射。
$param = [
"index"=>"my_index",
"type"=>"my_type2",
"body"=>[
"my_type2"=>[
"_source"=>[
"enabled"=>true
],
"properties"=>[
"first_name"=>[
"type"=>'string',
"analyzer"=>"standard"
],
"age"=>[
"type"=>"integer"
]
]
]
]
];
$client->indices()->putMapping($param);//Put Mappings API允許增加或增加一個索引的映射
Get Mappings API 返回索引和類型的映射細節。你可以指定一些索引和類型,取決於你希望索引什么映射。
$response = $client->indices()->getMapping();//獲取所有映射
$params = ["index"=>"my_index"];
$response = $client->indices()->getMapping($params);//獲取指定索引的映射
$params = [
"index"=>'my_index',
"type"=>"my_type"
];
$response = $client->indices()->getMapping($params);//獲取指定索引指定type下的映射
$params = [
"index"=>["my_index",'my_index2']
];
$response = $client->indices()->getMapping($params);//獲取多個索引的映射
二,索引文檔
1,單一文檔
當索引一個文檔時,你可以提供一個ID或者讓Elasticsearch自動生成
提供ID值:
$params = [
"index"=>'my_index',
"type"=>'my_type',
"id"=>'my_id',
"body"=>["testField"=>'abc']
];
$response = $client->index($params);
不提供ID值
$params = [
"index"=>'my_index',
"type"=>"my_type",
"body"=>['testField'=>['abc']]
];
$response = $client->index($params);
如果你需要設置其他的參數,如routing的值,你可以指定這些參數到index,type等參數后。例如,索引一個新的文檔時設置rounting值和timestamp值:
//如果需要蛇者其他的參數,需要指定到index,type之后
$params = [
"index"=>"my_index",
"type"=>"my_type",
"id"=>"my_id",
"routing"=>"company_xyz",
"timestamp"=>strtotime("-1d"),
"body"=>[
"testField"=>"abd"
]
];
$response = $client->index($params);
2,批量(bulk)索引
Elasticsearch也支持批量(bulk)索引對象。bulk API要求提供JSON格式的 action/元數據 鍵值對。再php中構建批量文檔數據也是相似的。你首先要創建一個action數組對象(如index對象),
然后你還要創建一個body對象。而PHP程序則重復上述操作構建文檔數據。
例子:
for($i=0; $i<10; $i++){
$params['body'][] = [
"index"=>[
"_index"=>"my_index",
"_type"=>"my_type"
]
];
$params['body'][] = [
"my_field"=>"my_value",
"second_field"=>"some more values"
];
}
$response = $client->bulk($params);//批量發送
實際上再一次bulk請求中發送數量會比文檔實際數量少。如果時這種情況,你就要設置批量值然后周期性的發送:
//周期性的發送
$params = ["body"=>[]];
for($i=1;$i=123456;$i++){
$params['body'][] = [
"index"=>[
"_index"=>"my_index",
"_type"=>"my_type",
"_id"=>$i
]
];
$params['body'][] = [
"my_field"=>"my_value",
"second_field"=>"some more values"
];
if($i % 1000 ==0){
$response = $client->bulk($params);
$params = ["body"=>[]];
unset($response);
}
}
if(!empty($params['body'])){
$response = $client->bulk($params);
}
三,php處理JSON數組或對象
Elasticsearch JSON API 常見的數據格式
1,空對象
Elasticseach API再幾個地方使用了空對象,這會對PHP造成影響。不像其他的語言,PHP沒有一個簡便的符號來表示空對象,而許多開發者還不知道如何指定一個空對象
{ "query" : { "match" : { "content" : "quick brown fox" } }, "highlight" : { "fields" : { "content" : {} } } }
這個空對象便會引起問題
問題就在於php會自動把 "conteng":{} 轉換為"content":[] ,在Elasticsearch DSL中這樣的數據格式時非法的。我們需要告訴PHP那個空對象就是一個空對象而非空數據。為了在查詢中定義空對象,需要這樣做:
//定義空對象
$params['body'] = array(
"query"=>[
"match"=>[
"content"=>"quick brown fox"
]
],
"highlight"=>array(
"fields"=>[
"content"=>new \stdClass() // 定義空對象
]
)
);
$response = $client->search($params);
通過使用PHP的stdclass對象來代表空對象,現在就可以解析JSON數據了
通過使用一個stdclass對象,我們可以強制json_encode解析為空對象,而不是空數組。然而,這種冗余的寫法是唯一解決PHP空對象的方法
2,對象數組
Elasticsearch DSL的另一種常見的數據格式時對象數組。例如假設在你的查詢中增加排序
{ "query" : { "match" : { "content" : "quick brown fox" } }, "sort" : [ {"time" : {"order" : "desc"}}, {"popularity" : {"order" : "desc"}} ] }
sort內含JSON對象數組
嵌套數組
//對象數組
$params['body'] = [
"query"=>[
"match"=>[
"content"=>"quick brown fox"
]
],
"sort"=>[ // 這里encode 為 "sort":[]
['time'=>['order'=>"desc"]], //這里encode為:{"time":{"order":"desc"}}
["popularity"=>["order"=>"desc"]] //這里encode為 {"popularity":{"order":"desc"}}
]
];
$response = $client->search($params);
3,空對象數組
偶爾DSL需要上述兩種數據格式。score查詢便是一個很好的例子,該查詢有時需要一個對象數組,而有一些對象數組,而有一些對象可能時一個空的JSON對象
請看如下查詢
{ "query":{ "function_score":{ "functions":[ { "random_score":{} } ], "boost_mode":"replace" } } }
我們用下面的PHP代碼來構建這個查詢
//空對象數組
$params['body'] = [
"query"=>[
"function_score"=>[
"functions"=>[//encode為"functions""[]
[//encode為{"random_score":{}}
"random_score"=>new \stdClass()//encode為"random_score":{}
]
]
]
]
];
$result = $client->search($params);
四 搜索操作
1,Match查詢
以下時Match查詢的標准curl格式
curl -XGET 'localhost:9200/my_index/my_type/_search' -d '{ "query" : { "match" : { "testField" : "abc" } } }'
而這里則時客戶端構建的同樣的查詢
//搜索操作
$params = [
"index"=>"my_index",
"type"=>"my_type",
"body"=>[
"query"=>[
"match"=>[
"testField"=>"abc"
]
]
]
];
$result = $client->search($params);
這里要注意PHP數組得結構與層次是怎樣與curl中得JSON請求體格式相對應得。這種方式使得JSON得寫法轉換為PHP得寫法變得十分簡單。一個快速檢測PHP數組是否為預期結果得方法,就是encode為JSON格式,然后進行檢查:
$params = [
"index"=>"my_index",
"type"=>"my_type",
"body"=>[
"query"=>[
"match"=>[
"testField"=>'abc'
]
]
]
];
print_r(json_encode($params['body']));
{"query":{"match":{"testField":"abc"}}}
使用原生JSON
有時使用原生JSON來進行測試會十分方便,或者原生JSON來進行不同系統的移植也同樣方便。你可以在body中用原生JSON字符串,這樣客戶端會自動進行檢查操作:
$json = '{
"query":{
"match":{
"testField":"abc"
}
}
}';
$params = [
"index"=>"my_index",
"type"=>"my_type",
"body"=>$json
];
$results = $client->search($params);
搜索結果與Elasticsearch的響應結果一致,唯一不同的是JSON格式會轉換成PHP數組。處理這些數據與數組迭代一樣簡單:
$params = [
"index"=>"my_index",
"type"=>"my_type",
"body"=>[
"query"=>[
"match"=>[
"testField"=>'abc'
]
]
]
];
$results = $client->search($params);
$milliseconds = $results['took'];
$maxscore = $results['hits']['max_score'];
$score = $results['hits']['hits'][0]['_score'];
$doc = $results['hits']['hits'][0]['_source'];
Bool查詢
利用客戶端可以輕松構建Bool查詢。例如以下查詢
curl -XGET 'localhost:9200/my_index/my_type/_search' -d '{ "query" : { "bool" : { "must": [ { "match" : { "testField" : "abc" } }, { "match" : { "testField2" : "xyz" } } ] } } }'
會構建為這樣了
$params = [
"index"=>"my_index",
"type"=>"my_type",
"body"=>[
"query"=>[
"bool"=>[
"must"=>[
["match"=>["testField"=>"abc"]],
]
]
]
]
];
$results = $client->search($params);
這里注意must語句接收的是數組。這里會轉化為JSON數組,所以最后的響應結果與curl格式的響應結果一致。。
更為復雜的示例
這里構建一個有點復雜的例子:一個bool查詢包含一個filter過濾器和一個普通查詢。這在elasticsearch的查詢中非常普通,所以這個例子會非常有用。
curl格式的查詢:
curl -XGET 'localhost:9200/my_index/my_type/_search' -d '{ "query" : { "bool" : { "filter" : { "term" : { "my_field" : "abc" } }, "should" : { "match" : { "my_other_field" : "xyz" } } } } }'
而在PHP中
Scrolling(游標)查詢
在用bulk時,經常要用scrolling功能對文檔進行分頁處理,如輸出一個用戶的所有文檔。這比常規的搜索要高效,因為這里不需要對文檔執行性能消耗較大的排序操作。
Scrolling會保留某個時間的索引快照數據,然后快照數據,然后用快照數據進行分頁。游標查詢窗口允許持續分頁操作,即使后台正在執行索引文檔、更新文檔和刪除文檔。
首先,你要在發送搜索請求時增加scroll參數。然后就會返回一個文檔頁數信息,還有一個用來獲取hits分頁數據的scroll_id。
以下代碼更為深入的操作的示例:
$params = [
"scroll"=>"30s",//滾動請求的間隔時間
"size"=>50,//每個碎片返回多少個結果
"index"=>"my_index",
"body"=>[
"query"=>[
"match_all"=>new \stdClass()
]
]
];
$response = $client->search($params);
//循環,直到滾動游標用完為止
while(isset($response['hits']['hits']) && count($response['hits']['hits'])>0 ){
$scroll_id = $response['_scroll_id'];//刷新scroll_id
$response = $client->scroll([//執行滾動請求並重復
"scroll_id"=>$scroll_id,
"scroll"=>"30s"
]);
}
5,獲取文檔
Elasticsearch提供實時獲取文檔的方法。這意味着只要文檔被索引且客戶端收到消息確認后,你就可以立即在任何的分片中檢索文檔。Get操作通過index/type/id方式方式請求一個文檔信息:
$params = [
"index"=>'my_index',
"type"=>"my_type",
"id"=>"my_id"
];
$response = $client->get($params);
6,更新文檔
更新文檔操作既可以完全覆蓋現存文檔全部字段,又可以部分更新字段(更改現存字段,或添加新字段)
部分更新
如果你要部分更新文檔(如更改現存字段,或添加新字段),你可以在body參數中指定一個doc參數。這樣doc參數內的字段會與現存字段進行合並
$params = [
"index"=>"my_index",
"type"=>"my_type",
"id"=>"my_id",
"body"=>[
"doc"=>[
"new_field"=>"abc"
]
]
];
//更新 /my_index/my_type/my_id 索引文檔
$response = $client->update($params);
Script更新
有時你要執行一個腳本來進行更新操作,如字段進行自增操作或添加新字段。為了執行一個腳本更新,你要提供腳本命令和一些參數
$params = [
"index"=>"my_index",
"type"=>"my_type",
"id"=>"my_id",
"body"=>[
"script"=>"ctx._source.counter += count",
"params"=>[
"count"=>4
]
]
];
$response = $client->update($params);
Upserts更新
Upserts操作是指“更新或插入”操作會執行script更新,如果文檔不存在(或是你更新的字段不存在),則會插入一個默認值
$params=[
"index"=>"my_index",
"type"=>"my_type",
"id"=>"my_id",
"body"=>[
"script"=>"ct._source.counter += count",
"params"=>[
"count"=>4
],
'upsert'=>[
"counter"=>1
]
]
];
$response = $client->update($params);
六,命名空間
客戶端有許多“命名空間”,通常是一些公開的可管理功能。命名空間對應Elasticsearch中各種可管理的endpoint。下面全部的命名空間:
命名空間 | 功能 |
indices() | 索引數據和顯示索引信息 |
nodes() | 節點數據統計和顯示節點信息 |
cluster | 集群數據統計和顯示集群信息 |
snapshort | 對集群和索引進行拍攝快照或恢復數據 |
cart() | 執行Cat API命令(通常在命令行中使用) |
一些方法在不同的命名空間下均可使用。雖然返回的是同樣的信息但是卻屬於不同的上下文環境。想知道命名空間如何運行,請看_stats的輸出信息
$response = $client->indices()->stats();
$response = $client->nodes()->stats();
$response = $client->cluster()->stats();
上面展示了在三個不同命名空間下都調用了stats()方法,有時這些方法需要參數,這些參數的寫法跟客戶端中其他方法的參數寫法相同。
例如我們可以請求索引或多個索引的統計信息:
$params_1['index'] = "my_index";
$response = $client->indices()->stats($params_1);
$params_2['index'] = ["my_index",'my_index2'];
$response = $client->indices()->stats($params_2);
/在現有索引中添加別名
$params_3['body'] = [
"actions"=>[
[
"add"=>[
"index"=>"my_index",
"alias"=>"myalias"
]
]
]
];
$response = $client->indices()->updateAliases($params_3);
注意上述例子中兩個stats的調用和updateAlias的調用接收不同格式的參數,每個方法的參數格式由響應的API需求來決定。stats API只需要一個index名,而updateAlias則需要一個body,里面還要一個actions參數。
七 按請求配置
1,忽略異常
Elasticsearch-PHP的類庫是會對普通的問題拋出異常的。這些異常跟Elasticsearch返回的HTTP響應碼--對應。例如,獲取一個不存在的文檔拋出MissingDocument404Exception.
異常對於處理一些問題(如找不到文檔,語法錯誤,版本沖突等)十分有用。但是有時候你只是想要處理返回的數據
如果你想忽略異常,你可以配置ignore參數。ignore參數要作為client的參數配置在請求體中。例如下面的實例會忽略MissingDocument404Exception,返回的是Elasticsearch提供的JSON數據
$params = [
"index"=>"test_missing",
"type"=>"test",
"id"=>1,
"client"=>['ignore'=>404]//忽略參數ignore需要作為client的參數配置在請求體中 這里忽略404
];
$client->get($params);
你可以通過數組的方式指定忽略多個HTTP狀態碼:
//忽略多個HTTP狀態碼
$params = [
"index"=>"test_missing",
"type"=>"test",
"id"=>1,
"client"=>["ignore"=>[400,404]] //ignore參數接收數組,BadRequest400Exception和MissingDocument404Exception都會忽略
];
$client->get($params);
注意,返回的數據是字符串格式,而不是JSON數據。而在第一個示例中返回的是JSON數據,客戶端會decode該JSON數據為數組。
一旦客戶端無法得知返回的異常數據格式,客戶端就不會decode返回結果
2,自定義查詢參數
有時候你要自己提供自定義參數,比如第三方插件或代理提供認證token。在Elasticsearch-php的白名單中存儲着所有的查詢參數,這是為了防止你指定一個參數,而Elasticsearch卻不接受。
如果你要自定義參數,你就要忽略這種白名單機制。為了達到這種效果,請增加custom參數:
$params = [
"index"=>"test",
"type"=>"test",
"id"=>1,
"parent"=>'abc',//列入白名單的參數
"client"=>[
"custom"=>[
"customeToken"=>"abc",//用戶定義,沒有勾選
"otherToken"=>123
]
]
];
$exists = $client->exists($params);
if($exists){
echo "存在";
}else{
echo "不存在";
}
返回詳細輸出
客戶端默認只返回響應體數據。如果你需要更多信息(如頭信息,響應狀態碼等),你可以讓客戶端返回更多詳細信息。通過verbose參數可以開啟這個功能。
沒有返回詳細信息,你看到的返回是這樣的:
$params = [
"index"=>"test",
"type"=>"test",
"id"=>1,
"client"=>[
"ignore"=>[400,404]
]
];
$response = $client->get($params);
如果加上參數:
$params = [
"index"=>"my_index",
"type"=>"my_type",
"id"=>"my_id",
"client"=>[
"verbose"=>true
]
];
$response = $client->get($params);
5,curl超時設置
通過timeout和connect_timeout參數可以配置每個請求的curl超時時間。這個配置主要是控制客戶端的超時之間。
connect_time 參數控制在連接階段完成前,curl的等待時間。而timeout參數則控制整個請求完成前,最多等待多長時間。
如果超過超時時間,curl會關閉連接並返回一個致命錯誤,兩個參數都要用 秒 作為參數
注意:客戶端超時並 不 意味着Elasticsearch中止請求。Elasticsearch會繼續執行請求直到請求完成。在慢查詢或是bulk請求下,操作會在后台繼續執行,對客戶端來說這些動作是隱蔽的。
如果客戶端在超市后立即斷開連接,然后又立刻發送另外一個請求。由於客戶端沒有處理服務端回壓的機制,這有可能會造成服務端過載。遇到這種情況,你會發現線程池隊列會慢慢變大,當隊列超出負荷,Elasticsearch會發送
EsRejectedException的異常
//curl超時設置
$params = [
"index"=>"my_index",
"type"=>"my_type",
"id"=>"my_id",
"client"=>[
"timeout"=>10,//控制整個請求完成前,最多等待的時間
"connect_time"=>10//控制在連接階段完成前,curl等待的時間
]
];
$response = $client->get($params);
6,開啟Future模式
客戶端支持異步方式批量發送請求。通過client選項的future參數可以開啟(HTTP handle要支持異步模式)
//開啟future模式
$params = [
"index"=>"my_index",
"type"=>"my_type",
"id"=>"my_id",
"client"=>[
"future"=>"lazy"
]
];
$future = $client->get($params);
$results = $future->wait();//解決函數
future模式有兩個參數可選:true或lazy。關於異步執行方法以及如何處理返回結果的詳情,請到Future模式中查看
7,SSL加密
在創建客戶端時,一般需要指定SSL配置,因為通常所有的請求都需要加密。然而,在每個請求中配置SSL加密也是有可能的。例如,如果你需要在某個特定的請求中使用自簽名整數,你可以通過在client選項中配置verify參數:
$params = [
"index"=>"my_index",
"type"=>"my_type",
"id"=>"my_id",
"client"=>[
'verify'=>'path/to/cacert.pem'//使用自簽名證書
]
];
$result = $client->get($params);