1<img align="right" width="auto" height="auto" src="https://www.elastic.co/static-res/images/elastic-logo-200.png"/>
2
3elasticsearch-php
4=================
5
6[![Build status](https://github.com/elastic/elasticsearch-php/workflows/PHP%20test/badge.svg)](https://github.com/elastic/elasticsearch-php/actions) [![Latest Stable Version](https://poser.pugx.org/elasticsearch/elasticsearch/v/stable)](https://packagist.org/packages/elasticsearch/elasticsearch) [![Total Downloads](https://poser.pugx.org/elasticsearch/elasticsearch/downloads)](https://packagist.org/packages/elasticsearch/elasticsearch)
7
8Official low-level client for Elasticsearch. Its goal is to provide common ground for all Elasticsearch-related code in PHP; because of this it tries to be opinion-free and very extendable.
9
10To maintain consistency across all the low-level clients (Ruby, Python, etc.), clients accept simple associative arrays as parameters.  All parameters, from the URI to the document body, are defined in the associative array.
11
12Starting from version `7.4.0`, all the endpoints (and namespaces) are autogenerated using the [util/GenerateEndpoints.php](https://github.com/elastic/elasticsearch-php/blob/master/util/GenerateEndpoints.php) script. This script reads the [Elasticsearch API specs](https://github.com/elastic/elasticsearch/tree/master/rest-api-spec/src/main/resources/rest-api-spec/api) and generated the PHP classes for all the endpoints.
13
14Starting from version `7.7.0` we included also the [XPack endpoints](https://www.elastic.co/what-is/open-x-pack) of Elasticsearch.
15These APIs are related to:
16
17- [Cross-cluster replication](https://www.elastic.co/guide/en/elasticsearch/reference/current/ccr-apis.html)
18- [Graph explorer](https://www.elastic.co/guide/en/elasticsearch/reference/current/graph-explore-api.html)
19- [Info](https://www.elastic.co/guide/en/elasticsearch/reference/current/info-api.html)
20- [Licensing](https://www.elastic.co/guide/en/elasticsearch/reference/current/licensing-apis.html)
21- [Machine learning anomaly detection](https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-apis.html)
22- [Machine learning data frame analytics](https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-df-analytics-apis.html)
23- [Migration](https://www.elastic.co/guide/en/elasticsearch/reference/current/migration-api.html)
24- [Reload search analyzers](https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-reload-analyzers.html)
25- [Rollup](https://www.elastic.co/guide/en/elasticsearch/reference/current/rollup-apis.html)
26- [Security](https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api.html)
27- [Snapshot lifecycle management](https://www.elastic.co/guide/en/elasticsearch/reference/current/snapshot-lifecycle-management-api.html)
28- [Transform](https://www.elastic.co/guide/en/elasticsearch/reference/current/transform-apis.html)
29- [Usage](https://www.elastic.co/guide/en/elasticsearch/reference/current/usage-api.html)
30- [Watcher](https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api.html)
31
32Table of Contents
33=================
34
35- [elasticsearch-php](#elasticsearch-php)
36  * [Features](#features)
37  * [Version Matrix](#version-matrix)
38  * [Compatibility](#compatibility)
39  * [Documentation](#documentation)
40  * [Installation via Composer](#installation-via-composer)
41  * [PHP Version Requirement](#php-version-requirement)
42  * [Quickstart](#quickstart)
43    + [Index a document](#index-a-document)
44    + [Get a document](#get-a-document)
45    + [Search for a document](#search-for-a-document)
46    + [Delete a document](#delete-a-document)
47    + [Delete an index](#delete-an-index)
48    + [Create an index](#create-an-index)
49- [Unit Testing using Mock a Elastic Client](#unit-testing-using-mock-a-elastic-client)
50- [Contributing](#contributing)
51- [Wrap up](#wrap-up)
52  * [Available Licenses](#available-licenses)
53    + [Contributions](#contributions)
54
55Features
56--------
57
58 - One-to-one mapping with REST API and other language clients
59 - Configurable, automatic discovery of cluster nodes
60 - Persistent, Keep-Alive connections (within the lifetime of the script)
61 - Load balancing (with pluggable selection strategy) across all available nodes. Defaults to round-robin
62 - Pluggable connection pools to offer different connection strategies
63 - Generalized, pluggable architecture - most components can be replaced with your own custom class if specialized behavior is required
64 - Option to use asynchronous future, which enables parallel execution of curl requests to multiple nodes
65
66
67**Note:** [X-Pack](https://www.elastic.co/what-is/open-x-pack) endpoints are included from elasticsearch-php 7.7+.
68
69
70Version Matrix
71--------------
72
73| Elasticsearch-PHP Branch | PHP Version |
74| ----------- | ------------------------ |
75| >= 7.16.0, < 8.0.0  | >= 7.3.0, <= 8.1.99 |
76| >= 7.12.0, < 8.0.0  | >= 7.3.0, <= 8.0.99 |
77| >= 7.11.0, < 8.0.0  | >= 7.1.0, <= 8.0.99 |
78| >= 7.0.0,  < 7.11.0 | >= 7.1.0, < 8.0.0 |
79| 6.x         | >= 7.0.0, < 8.0.0        |
80| 5.x         | >= 5.6.6, < 8.0.0        |
81| 2.x         | >= 5.4.0, < 7.0.0        |
82| 0.4, 1.x    | >= 5.3.9, < 7.0.0        |
83
84 - If you are using Elasticsearch 7.x, you can use Elasticsearch-PHP 7.x branch.
85 - If you are using Elasticsearch 6.x, you can use Elasticsearch-PHP 6.x branch.
86 - If you are using Elasticsearch 5.x, you can use Elasticsearch-PHP 6.x branch.
87 - If you are using Elasticsearch 1.x or 2.x, prefer using the Elasticsearch-PHP 2.0 branch.  The 1.0 branch is compatible however.
88 - If you are using a version older than 1.0, you must install the `0.4` Elasticsearch-PHP branch. Since ES 0.90.x and below is now EOL, the corresponding `0.4` branch will not receive any more development or bugfixes.  Please upgrade.
89 - You should never use Elasticsearch-PHP Master branch, as it tracks Elasticsearch master and may contain incomplete features or breaks in backwards compatibility. Only use ES-PHP master if you are developing against ES master for some reason.
90
91Compatibility
92-------------
93
94Language clients are forward compatible; meaning that clients support communicating
95with greater minor versions of Elasticsearch. Elastic language clients are also backwards
96compatible with lesser supported minor Elasticsearch versions.
97
98Documentation
99--------------
100[Full documentation can be found here.](https://www.elastic.co/guide/en/elasticsearch/client/php-api/current/index.html)  Docs are stored within the repo under /docs/, so if you see a typo or problem, please submit a PR to fix it!
101
102We also provide a code examples generator for PHP using the `util/GenerateDocExamples.php` script. This command parses the `util/alternative_report.spec.json` file produced from this [JSON specification](https://raw.githubusercontent.com/elastic/built-docs/master/raw/en/elasticsearch/reference/master/alternatives_report.json) and it generates the PHP examples for each digest value.
103The examples are stored in asciidoc format under `docs/examples` folder.
104
105Installation via Composer
106-------------------------
107The recommended method to install _Elasticsearch-PHP_ is through [Composer](http://getcomposer.org).
108
1091. Add `elasticsearch/elasticsearch` as a dependency in your project's `composer.json` file (change version to suit your version of Elasticsearch, for instance for ES 7.0):
110
111    ```json
112        {
113            "require": {
114                "elasticsearch/elasticsearch": "^7.0"
115            }
116        }
117    ```
118
1192. Download and install Composer:
120
121    ```bash
122        curl -s http://getcomposer.org/installer | php
123    ```
124
1253. Install your dependencies:
126
127    ```bash
128        php composer.phar install
129    ```
130
1314. Require Composer's autoloader
132
133    Composer also prepares an autoload file that's capable of autoloading all the classes in any of the libraries that it downloads. To use it, just add the following line to your code's bootstrap process:
134
135    ```php
136        <?php
137
138        use Elasticsearch\ClientBuilder;
139
140        require 'vendor/autoload.php';
141
142        $client = ClientBuilder::create()->build();
143    ```
144
145You can find out more on how to install Composer, configure autoloading, and other best-practices for defining dependencies at [getcomposer.org](http://getcomposer.org).
146
147PHP Version Requirement
148----
149Version 7.0 of this library requires at least PHP version 7.1. In addition, it requires the native JSON
150extension to be version 1.3.7 or higher.
151
152| Elasticsearch-PHP Branch | PHP Version |
153| ----------- | ------------------------ |
154| 7.0         | >= 7.1.0                 |
155| 6.0         | >= 7.0.0                 |
156| 5.0         | >= 5.6.6                 |
157| 2.0         | >= 5.4.0                 |
158| 0.4, 1.0    | >= 5.3.9                 |
159
160
161Quickstart
162----
163
164
165### Index a document
166
167In elasticsearch-php, almost everything is configured by associative arrays. The REST endpoint, document and optional parameters - everything is an associative array.
168
169To index a document, we need to specify three pieces of information: index, id and a document body. This is done by
170constructing an associative array of key:value pairs.  The request body is itself an associative array with key:value pairs
171corresponding to the data in your document:
172
173```php
174$params = [
175    'index' => 'my_index',
176    'id'    => 'my_id',
177    'body'  => ['testField' => 'abc']
178];
179
180$response = $client->index($params);
181print_r($response);
182```
183
184The response that you get back indicates the document was created in the index that you specified.  The response is an
185associative array containing a decoded version of the JSON that Elasticsearch returns:
186
187```php
188Array
189(
190    [_index] => my_index
191    [_type] => _doc
192    [_id] => my_id
193    [_version] => 1
194    [result] => created
195    [_shards] => Array
196        (
197            [total] => 1
198            [successful] => 1
199            [failed] => 0
200        )
201
202    [_seq_no] => 0
203    [_primary_term] => 1
204)
205```
206
207### Get a document
208
209Let's get the document that we just indexed.  This will simply return the document:
210
211```php
212$params = [
213    'index' => 'my_index',
214    'id'    => 'my_id'
215];
216
217$response = $client->get($params);
218print_r($response);
219```
220
221The response contains some metadata (index, version, etc.) as well as a `_source` field, which is the original document
222that you sent to Elasticsearch.
223
224```php
225Array
226(
227    [_index] => my_index
228    [_type] => _doc
229    [_id] => my_id
230    [_version] => 1
231    [_seq_no] => 0
232    [_primary_term] => 1
233    [found] => 1
234    [_source] => Array
235        (
236            [testField] => abc
237        )
238
239)
240```
241
242If you want to retrieve the `_source` field directly, there is the `getSource` method:
243
244```php
245$params = [
246    'index' => 'my_index',
247    'id'    => 'my_id'
248];
249
250$source = $client->getSource($params);
251print_r($source);
252```
253
254The response will be just the `_source` value:
255
256```php
257Array
258(
259    [testField] => abc
260)
261```
262
263### Search for a document
264
265Searching is a hallmark of Elasticsearch, so let's perform a search.  We are going to use the Match query as a demonstration:
266
267```php
268$params = [
269    'index' => 'my_index',
270    'body'  => [
271        'query' => [
272            'match' => [
273                'testField' => 'abc'
274            ]
275        ]
276    ]
277];
278
279$response = $client->search($params);
280print_r($response);
281```
282
283The response is a little different from the previous responses.  We see some metadata (`took`, `timed_out`, etc.) and
284an array named `hits`.  This represents your search results.  Inside of `hits` is another array named `hits`, which contains
285individual search results:
286
287```php
288Array
289(
290    [took] => 33
291    [timed_out] =>
292    [_shards] => Array
293        (
294            [total] => 1
295            [successful] => 1
296            [skipped] => 0
297            [failed] => 0
298        )
299
300    [hits] => Array
301        (
302            [total] => Array
303                (
304                    [value] => 1
305                    [relation] => eq
306                )
307
308            [max_score] => 0.2876821
309            [hits] => Array
310                (
311                    [0] => Array
312                        (
313                            [_index] => my_index
314                            [_type] => _doc
315                            [_id] => my_id
316                            [_score] => 0.2876821
317                            [_source] => Array
318                                (
319                                    [testField] => abc
320                                )
321
322                        )
323
324                )
325
326        )
327
328)
329```
330
331### Delete a document
332
333Alright, let's go ahead and delete the document that we added previously:
334
335```php
336$params = [
337    'index' => 'my_index',
338    'id'    => 'my_id'
339];
340
341$response = $client->delete($params);
342print_r($response);
343```
344
345You'll notice this is identical syntax to the `get` syntax.  The only difference is the operation: `delete` instead of
346`get`.  The response will confirm the document was deleted:
347
348```php
349Array
350(
351    [_index] => my_index
352    [_type] => _doc
353    [_id] => my_id
354    [_version] => 2
355    [result] => deleted
356    [_shards] => Array
357        (
358            [total] => 1
359            [successful] => 1
360            [failed] => 0
361        )
362
363    [_seq_no] => 1
364    [_primary_term] => 1
365)
366```
367
368
369### Delete an index
370
371Due to the dynamic nature of Elasticsearch, the first document we added automatically built an index with some default settings.  Let's delete that index because we want to specify our own settings later:
372
373```php
374$deleteParams = [
375    'index' => 'my_index'
376];
377$response = $client->indices()->delete($deleteParams);
378print_r($response);
379```
380
381The response:
382
383
384```php
385Array
386(
387    [acknowledged] => 1
388)
389```
390
391### Create an index
392
393Now that we are starting fresh (no data or index), let's add a new index with some custom settings:
394
395```php
396$params = [
397    'index' => 'my_index',
398    'body'  => [
399        'settings' => [
400            'number_of_shards' => 2,
401            'number_of_replicas' => 0
402        ]
403    ]
404];
405
406$response = $client->indices()->create($params);
407print_r($response);
408```
409
410Elasticsearch will now create that index with your chosen settings, and return an acknowledgement:
411
412```php
413Array
414(
415    [acknowledged] => 1
416)
417```
418
419Unit Testing using Mock a Elastic Client
420========================================
421```php
422use GuzzleHttp\Ring\Client\MockHandler;
423use Elasticsearch\ClientBuilder;
424
425// The connection class requires 'body' to be a file stream handle
426// Depending on what kind of request you do, you may need to set more values here
427$handler = new MockHandler([
428  'status' => 200,
429  'transfer_stats' => [
430     'total_time' => 100
431  ],
432  'body' => fopen('somefile.json'),
433  'effective_url' => 'localhost'
434]);
435$builder = ClientBuilder::create();
436$builder->setHosts(['somehost']);
437$builder->setHandler($handler);
438$client = $builder->build();
439// Do a request and you'll get back the 'body' response above
440```
441
442Contributing
443============
444
445If you want to contribute to this project you need to subscribe to a [Contributor Agreement](https://www.elastic.co/contributor-agreement).
446If you want to send a PR for version `Y` please use the `Y.x` branch. For instance if you want to send a PR for **elasticsearch-php 7** use the `7.x` branch.
447
448Never send PR to `master` unless you want to contribute to the development version of the client (`master` represents the next major version).
449
450Each PR should include a **unit test** using [PHPUnit](https://phpunit.de/). If you are not familiar with PHPUnit you can have a look at this [reference](https://phpunit.readthedocs.io/en/7.0/).
451
452Wrap up
453=======
454
455That was just a crash-course overview of the client and its syntax.  If you are familiar with Elasticsearch, you'll notice that the methods are named just like REST endpoints.
456
457You'll also notice that the client is configured in a manner that facilitates easy discovery via the IDE.  All core actions are available under the `$client` object (indexing, searching, getting, etc.).  Index and cluster management are located under the `$client->indices()` and `$client->cluster()` objects, respectively.
458
459Check out the rest of the [Documentation](https://www.elastic.co/guide/en/elasticsearch/client/php-api/current/index.html) to see how the entire client works.
460
461
462Available Licenses
463-------
464
465Starting with version 1.3.1, Elasticsearch-PHP is available under two licenses: Apache v2.0 and LGPL v2.1.  Versions
466prior to 1.3.1 are still licensed with only Apache v2.0.
467
468The user may choose which license they wish to use.  Since there is no discriminating executable or distribution bundle
469to differentiate licensing, the user should document their license choice externally, in case the library is re-distributed.
470If no explicit choice is made, assumption is that redistribution obeys rules of both licenses.
471
472### Contributions
473All contributions to the library are to be so that they can be licensed under both licenses.
474
475Apache v2.0 License:
476>Copyright 2013-2016 Elasticsearch
477>
478>Licensed under the Apache License, Version 2.0 (the "License");
479>you may not use this file except in compliance with the License.
480>You may obtain a copy of the License at
481>
482>    http://www.apache.org/licenses/LICENSE-2.0
483>
484>Unless required by applicable law or agreed to in writing, software
485>distributed under the License is distributed on an "AS IS" BASIS,
486>WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
487>See the License for the specific language governing permissions and
488>limitations under the License.
489
490LGPL v2.1 Notice:
491>Copyright (C) 2013-2016 Elasticsearch
492>
493>This library is free software; you can redistribute it and/or
494>modify it under the terms of the GNU Lesser General Public
495>License as published by the Free Software Foundation; either
496>version 2.1 of the License, or (at your option) any later version.
497>
498>This library is distributed in the hope that it will be useful,
499>but WITHOUT ANY WARRANTY; without even the implied warranty of
500>MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
501>Lesser General Public License for more details.
502>
503>You should have received a copy of the GNU Lesser General Public
504>License along with this library; if not, write to the Free Software
505>Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
506