搜索操作
让我们来谈谈PHP客户端中对 elasticsearch 的搜索操作。
客户端允许你通过REST API访问所有的查询和公开的参数,来看一些例子,你就可以熟悉它的语法。
匹配查询
这里是一个标准的匹配查询的curl:
curl -XGET 'localhost:9200/my_index/my_type/_search' -d '{
"query" : {
"match" : {
"testField" : "abc"
}
}
}'
这里是在客户端中=同样查询结构的查询:
$params['index'] = 'my_index';
$params['type'] = 'my_type';
$params['body']['query']['match']['testField'] = 'abc';
$results = $client->search($params);
使用原始JSON
正如你看到的JSON和查询之间的转换是非常简单的。你可以直接序列化JSON到body中,或者甚至提供原始的JSON字符串。客户端会处理的很好:
$json = '{
"query" : {
"match" : {
"testField" : "abc"
}
}
}';
$params['index'] = 'my_index';
$params['type'] = 'my_type';
$params['body'] = $json;
$results = $client->search($params);
搜索结果返回的是简单的由elasticsearch响应元素序列化成的数组。与搜索结果工作就像与迭代数组一样简单:
$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" : {
"anotherTestField" : "xyz"
}
}
}
}
}'
像这样的结构(注意中括号的位置)
$params['index'] = 'my_index';
$params['type'] = 'my_type';
$params['body']['query']['bool']['must'] = array(
array('match' => array('testField' => 'abc')),
array('match' => array('anotherTestField' => 'xyz')),
);
$results = $client->search($params);
一个更复杂的例子
让我们来构造一个稍微复杂的例子:一个过滤的查询包含一个过滤器和一个查询。这在elasticsearch查询中是非常常见的活动,所以,这将是一个好的演示。
curl版本的查询:
curl -XGET 'localhost:9200/my_index/my_type/_search' -d '{
"query" : {
"filtered" : {
"filter" : {
"term" : {
"my_field" : "abc"
}
},
"query" : {
"match" : {
"my_other_field" : "xyz"
}
}
}
}
}'
PHP版本的查询:
$params['index'] = 'my_index';
$params['type'] = 'my_type';
$filter = array();
$filter['term']['my_field'] = 'abc';
$query = array();
$query['match']['my_other_field'] = 'xyz';
$params['body']['query']['filtered'] = array(
"filter" => $filter,
"query" => $query
);
$results = $client->search($params);
为了清晰和可读性,过滤器和查询部分作为变量被单独分配并且之后组合在一起。这通常对应用程序来说是一个好的设计模式,因为它可以让你对待你的查询和过滤器想构建块一样,可以通过你的应用程序传递。
当然,在最后,他被构建在一个简单的数组中。你可以轻松构建整个数组在一个定义的嵌套数组块中,或者一行一行的构建。
所有客户端需要一个关联数组,并且结构要和JSON查询结构匹配。
Function_Score 查询
有一点需要特别注意关于function_score 查询。由于PHP处理JSON编码,一切都被转换成了数组的这种活那种形式。这通常不是问题,因为Elasticsearch API中大多地方接受数组或互换空对象。
然而,function_score 稍有不同,需要区分空数组和空对象,例如,考虑如下查询:
{
"query":{
"function_score":{
"functions":[
{
"random_score":{}
}
],
"boost_mode":"replace",
"query":{
"match_all":{}
}
}
}
}
function_score定义一个数组对象,random_score 用空对象作为值。
PHP的json_encode会转换查询到这种形式:
{
"query":{
"function_score":{
"functions":[
{
"random_score":[]
}
],
"boost_mode":"replace",
"query":{
"match_all":[]
}
}
}
}
这样会导致一个解析异常。我们需要做的是告诉PHP random_score 包含一个空对象,不是一个数组。要做到这样,我们需要需要指定一个显式空对象:
$params['body'] = array(
'query' => array(
'function_score' => array(
'functions' => array(
array("random_score" => (object) array())
),
'query' => array('match_all' => array())
)
)
);
$results = $client->search($params);
现在,JSON会被正常编码,不再会出现解析异常。
扫描/滚动
Elasticsearch的扫描/滚动功能类似于搜索,但在许多方面不同。它的工作方式是使用scan中的search_type执行一个搜索查询。这将启动一个扫描窗口并在扫面时保持打开。这允许真正的一致的分页。
一旦扫描窗口打开,你可能开始在窗口上滚动。这返回的结果要匹配你的查询,但顺序是随机的。这种随机的排序对性能来说是很重要的。深分页时昂贵的,当你需要通过碎片去维护一个分类的一致的排序。
有话要说