执行搜索 6.0 6.0

搜索操作

嗯…​这个项目如果没有什么特别之处就不叫 elasticsearch 了! 我们来聊聊客户端中的搜索操作。

在命名方案规范的前提下,客户端拥有一切的查询权限,也拥有获取 REST API 公开的一切参数的权限。现在来看看一些示例,以便您能熟悉语法

Match 查询

以下是 Match 查询的标准 curl 格式:

  1. curl -XGET 'localhost:9200/my_index/my_type/_search' -d '{
  2. "query" : {
  3. "match" : {
  4. "testField" : "abc"
  5. }
  6. }
  7. }'

这是客户端构建的相同查询:

  1. $params = [
  2. 'index' => 'my_index',
  3. 'type' => 'my_type',
  4. 'body' => [
  5. 'query' => [
  6. 'match' => [
  7. 'testField' => 'abc'
  8. ]
  9. ]
  10. ]
  11. ];
  12. $results = $client->search($params);

注意 PHP 数组的结构和布局如何与 JSON 结构体的格式相对应的。 这种使得将 JSON 示例转换为 PHP 变得非常简单。 一个快速检测 PHP 数组是否为预期结果的方法,就是 encode 为 JSON 格式,然后进行检查:

  1. $params = [
  2. 'index' => 'my_index',
  3. 'type' => 'my_type',
  4. 'body' => [
  5. 'query' => [
  6. 'match' => [
  7. 'testField' => 'abc'
  8. ]
  9. ]
  10. ]
  11. ];
  12. print_r(json_encode($params['body']));
  13. {"query":{"match":{"testField":"abc"}}}

使用原生 JSON

有时使用原生 JSON 来进行测试十分方便, 或者从其他系统迁移也同样方便。 您可以在 body 中用原生 JSON 字符串,这样客户端将会自动进行检查:

  1. $json = '{
  2. "query" : {
  3. "match" : {
  4. "testField" : "abc"
  5. }
  6. }
  7. }';
  8. $params = [
  9. 'index' => 'my_index',
  10. 'type' => 'my_type',
  11. 'body' => $json
  12. ];
  13. $results = $client->search($params);

搜索结果与 Elasticsearch 的响应结果一致,唯一不同的是 JSON 格式会转换成 PHP 数组。处理这些数据与数组迭代一样简单:

  1. $params = [
  2. 'index' => 'my_index',
  3. 'type' => 'my_type',
  4. 'body' => [
  5. 'query' => [
  6. 'match' => [
  7. 'testField' => 'abc'
  8. ]
  9. ]
  10. ]
  11. ];
  12. $results = $client->search($params);
  13. $milliseconds = $results['took'];
  14. $maxScore = $results['hits']['max_score'];
  15. $score = $results['hits']['hits'][0]['_score'];
  16. $doc = $results['hits']['hits'][0]['_source'];

Bool 查询

利用客户端可以轻松构建 Bool 查询。例如如下查询:

  1. curl -XGET 'localhost:9200/my_index/my_type/_search' -d '{
  2. "query" : {
  3. "bool" : {
  4. "must": [
  5. {
  6. "match" : { "testField" : "abc" }
  7. },
  8. {
  9. "match" : { "testField2" : "xyz" }
  10. }
  11. ]
  12. }
  13. }
  14. }'

将会构建为如下的样子 (注意方括号位置):

  1. $params = [
  2. 'index' => 'my_index',
  3. 'type' => 'my_type',
  4. 'body' => [
  5. 'query' => [
  6. 'bool' => [
  7. 'must' => [
  8. [ 'match' => [ 'testField' => 'abc' ] ],
  9. [ 'match' => [ 'testField2' => 'xyz' ] ],
  10. ]
  11. ]
  12. ]
  13. ]
  14. ];
  15. $results = $client->search($params);

注意, must 语句接收的是数组。这里会转换为 JSON 数组,所以最后的响应结果与 curl 格式的响应结果一致。想了解 PHP 中数组和对象的转换, 查看 用 PHP 处理 JSON 对象和数组.

更复杂的示例

让我们构造一个稍微复杂的例子: 一个 bool 查询包含一个 filter 过滤器和一个普通查询。 在 elasticsearch 的查询中非常普遍,因此它将是一个很好的演示。

curl 格式的查询:

  1. curl -XGET 'localhost:9200/my_index/my_type/_search' -d '{
  2. "query" : {
  3. "bool" : {
  4. "filter" : {
  5. "term" : { "my_field" : "abc" }
  6. },
  7. "should" : {
  8. "match" : { "my_other_field" : "xyz" }
  9. }
  10. }
  11. }
  12. }'

在 PHP 中:

  1. $params = [
  2. 'index' => 'my_index',
  3. 'type' => 'my_type',
  4. 'body' => [
  5. 'query' => [
  6. 'bool' => [
  7. 'filter' => [
  8. 'term' => [ 'my_field' => 'abc' ]
  9. ],
  10. 'should' => [
  11. 'match' => [ 'my_other_field' => 'xyz' ]
  12. ]
  13. ]
  14. ]
  15. ]
  16. ];
  17. $results = $client->search($params);

Scrolling(游标)查询

在用批量读取数据时,经常要用 Scrolling 功能对文档进行分页处理,如输出一个用户的所有文档。Scrolling 要比常规的搜索更加高效,因为这里不需要对文档执行性能消耗较大的排序操作。

Scrolling 会保留某个时间点的索引快照数据,然后用快照数据进行分页。即使后台正在执行索引文档、更新文档和删除文档,游标查询窗口仍然可以持续正常分页。如何使用呢?首先,你要在发送搜索请求时增加 Scroll 参数。然后就会返回一个文档『页数』信息,还有一个用来获取 Hits 分页数据的 scroll_id

更多详情请查看 官方文档里的说明

以下代码更为深入操作的示例:

  1. $client = ClientBuilder::create()->build();
  2. $params = [
  3. "scroll" => "30s", // 设置游标查询过期时间,不应该太长
  4. "size" => 50, // 返回多少数量的文档,作用于单个分片
  5. "index" => "my_index",
  6. "body" => [
  7. "query" => [
  8. "match_all" => new \stdClass()
  9. ]
  10. ]
  11. ];
  12. // 执行搜索
  13. // 将会返回第一批数据,和一个 scroll_id
  14. $response = $client->search($params);
  15. // 将所有数据循环出来
  16. while (isset($response['hits']['hits']) && count($response['hits']['hits']) > 0) {
  17. // **
  18. // 这里可以写你的逻辑,结果在 $response['hits']['hits'] 数组上
  19. // **
  20. // 完成后,获取新的 scroll_id
  21. // 刷新下你的 _scroll_id
  22. $scroll_id = $response['_scroll_id'];
  23. // 执行下一个游标请求
  24. $response = $client->scroll([
  25. "scroll_id" => $scroll_id, // 使用上个请求获取到的 _scroll_id
  26. "scroll" => "30s" // 时间窗口保持一致
  27. ]
  28. );
  29. }