1[[search_operations]]
2=== Search operations
3
4Well...it isn't called {es} for nothing! Let's talk about search operations in
5the client.
6
7The client gives you full access to every query and parameter exposed by the
8REST API, following the naming scheme as much as possible. Let's look at a few
9examples so you can become familiar with the syntax.
10
11[discrete]
12==== Match query
13
14Here is a standard curl for a match query:
15
16[source,shell]
17----
18curl -XGET 'localhost:9200/my_index/_search' -d '{
19    "query" : {
20        "match" : {
21            "testField" : "abc"
22        }
23    }
24}'
25----
26{zwsp} +
27
28
29And here is the same query constructed in the client:
30
31[source,php]
32----
33$params = [
34    'index' => 'my_index',
35    'body'  => [
36        'query' => [
37            'match' => [
38                'testField' => 'abc'
39            ]
40        ]
41    ]
42];
43
44$results = $client->search($params);
45----
46{zwsp} +
47
48
49Notice how the structure and layout of the PHP array is identical to that of the
50JSON request body. This makes it very simple to convert JSON examples into PHP.
51A quick method to check your PHP array (for more complex examples) is to encode
52it back to JSON and check it:
53
54[source,php]
55----
56$params = [
57    'index' => 'my_index',
58    'body'  => [
59        'query' => [
60            'match' => [
61                'testField' => 'abc'
62            ]
63        ]
64    ]
65];
66
67print_r(json_encode($params['body']));
68
69
70{"query":{"match":{"testField":"abc"}}}
71----
72{zwsp} +
73
74
75.Using Raw JSON
76****
77Sometimes it is convenient to use raw JSON for testing purposes, or when
78migrating from a different system. You can use raw JSON as a string in the body,
79and the client detects this automatically:
80
81[source,php]
82----
83$json = '{
84    "query" : {
85        "match" : {
86            "testField" : "abc"
87        }
88    }
89}';
90
91$params = [
92    'index' => 'my_index',
93    'body'  => $json
94];
95
96$results = $client->search($params);
97----
98****
99{zwsp} +
100
101
102Search results follow the same format as {es} search response, the only
103difference is that the JSON response is serialized back into PHP arrays. Working
104with the search results is as simple as iterating over the array values:
105
106[source,php]
107----
108$params = [
109    'index' => 'my_index',
110    'body'  => [
111        'query' => [
112            'match' => [
113                'testField' => 'abc'
114            ]
115        ]
116    ]
117];
118
119$results = $client->search($params);
120
121$milliseconds = $results['took'];
122$maxScore     = $results['hits']['max_score'];
123
124$score = $results['hits']['hits'][0]['_score'];
125$doc   = $results['hits']['hits'][0]['_source'];
126----
127{zwsp} +
128
129[discrete]
130==== Bool Queries
131
132Bool queries can be easily constructed using the client. For example, this
133query:
134
135[source,shell]
136----
137curl -XGET 'localhost:9200/my_index/_search' -d '{
138    "query" : {
139        "bool" : {
140            "must": [
141                {
142                    "match" : { "testField" : "abc" }
143                },
144                {
145                    "match" : { "testField2" : "xyz" }
146                }
147            ]
148        }
149    }
150}'
151----
152{zwsp} +
153
154
155Would be structured like this (note the position of the square brackets):
156
157[source,php]
158----
159$params = [
160    'index' => 'my_index',
161    'body'  => [
162        'query' => [
163            'bool' => [
164                'must' => [
165                    [ 'match' => [ 'testField' => 'abc' ] ],
166                    [ 'match' => [ 'testField2' => 'xyz' ] ],
167                ]
168            ]
169        ]
170    ]
171];
172
173$results = $client->search($params);
174----
175{zwsp} +
176
177
178Notice that the `must` clause accepts an array of arrays. This is serialized
179into an array of JSON objects internally, so the final resulting output is
180identical to the curl example. For more details about arrays and objects in PHP,
181see <<php_json_objects, Dealing with JSON Arrays and Objects in PHP>>.
182
183[discrete]
184==== A more complicated example
185
186Let's construct a slightly more complicated example: a boolean query that
187contains both a filter and a query. This is a very common activity in {es}
188queries, so it will be a good demonstration.
189
190The curl version of the query:
191
192[source,shell]
193----
194curl -XGET 'localhost:9200/my_index/_search' -d '{
195    "query" : {
196        "bool" : {
197            "filter" : {
198                "term" : { "my_field" : "abc" }
199            },
200            "should" : {
201                "match" : { "my_other_field" : "xyz" }
202            }
203        }
204    }
205}'
206----
207{zwsp} +
208
209
210And in PHP:
211
212[source,php]
213----
214$params = [
215    'index' => 'my_index',
216    'body'  => [
217        'query' => [
218            'bool' => [
219                'filter' => [
220                    'term' => [ 'my_field' => 'abc' ]
221                ],
222                'should' => [
223                    'match' => [ 'my_other_field' => 'xyz' ]
224                ]
225            ]
226        ]
227    ]
228];
229
230
231$results = $client->search($params);
232----
233{zwsp} +
234
235
236[discrete]
237==== Scrolling
238
239The scrolling functionality of {es} is used to paginate over many documents in a
240bulk manner, such as exporting all the documents belonging to a single user. It
241is more efficient than regular search because it doesn't need to maintain an
242expensive priority queue ordering the documents.
243
244Scrolling works by maintaining a "point in time" snapshot of the index which is
245then used to page over. This window allows consistent paging even if there is
246background indexing/updating/deleting. First, you execute a search request with
247`scroll` enabled. This returns a "page" of documents, and a `scroll_id` which is
248used to continue paginating through the hits.
249
250More details about scrolling can be found in the
251{ref-7x}/search-request-body.html#request-body-search-scroll[reference documentation].
252
253This is an example which can be used as a template for more advanced operations:
254
255[source,php]
256----
257$client = ClientBuilder::create()->build();
258$params = [
259    'scroll' => '30s',          // how long between scroll requests. should be small!
260    'size'   => 50,             // how many results *per shard* you want back
261    'index'  => 'my_index',
262    'body'   => [
263        'query' => [
264            'match_all' => new \stdClass()
265        ]
266    ]
267];
268
269// Execute the search
270// The response will contain the first batch of documents
271// and a scroll_id
272$response = $client->search($params);
273
274// Now we loop until the scroll "cursors" are exhausted
275while (isset($response['hits']['hits']) && count($response['hits']['hits']) > 0) {
276
277    // **
278    // Do your work here, on the $response['hits']['hits'] array
279    // **
280
281    // When done, get the new scroll_id
282    // You must always refresh your _scroll_id!  It can change sometimes
283    $scroll_id = $response['_scroll_id'];
284
285    // Execute a Scroll request and repeat
286    $response = $client->scroll([
287        'body' => [
288            'scroll_id' => $scroll_id,  //...using our previously obtained _scroll_id
289            'scroll'    => '30s'        // and the same timeout window
290        ]
291    ]);
292}
293----
294