From ES|QL to PHP objects

Starting from elasticsearch-php v8.13.0 you can execute ES|QL queries and map the result to a PHP object of stdClass or a custom class.

ES|QL

ES|QL is a new Elasticsearch Query Language introduced in Elasticsearch 8.11.0. Right now, it is available in technical preview. It provides a powerful way to filter, transform, and analyze data stored in Elasticsearch.

It makes use of "pipes" (|) to manipulate and transform data in a step-by-step fashion. This approach allows users to compose a series of operations, where the output of one operation becomes the input for the next, enabling complex data transformations and analysis.

For instance, the following query returns the first 3 documents (rows) of the sample_data index:

FROM sample_data
| LIMIT 3
ES|QL produces tables

Use case

To illustrate the ES|QL features developed in the official PHP client, we stored in Elasticsearch a CSV file of 81,828 books (54.4 MB) including the following information:

Title;Descrition;Author;Year;Publisher;Ratings

We extracted this list from the public available Amazon Books Reviews dataset.

We created a books index with the following Elasticsearch mappings:

'mappings' : {
    'properties': {
        'title': {
            'type': 'text'
        },
        'description': {
            'type': 'text'
        },
        'author': {
            'type': 'text'
        },
        'year': {
            'type': 'short'
        },
        'publisher': {
            'type': 'keyword'
        },
        'rating': {
            'type': 'half_float'
        }
    }
}

The rating value is the average of the ranking reviews taken from the Books_rating.csv file of 2.9 GB.

Here you can find the PHP script that we used to bulk import all the books in Elasticsearch. The bulk operation took 7 sec and 28 MB RAM using PHP 8.2.17. With the proposed mapping the index size in Elasticsearch is about 62 MB.

Map into an object or a custom class

We can execute ES|QL query in PHP using the esql()->query() endpoint. The result of this query is a a table data structure. This is expressed in JSON using the columns and values fields. In the columns field we have the name and type definition.

Here is an example of ES|QL query to retrieve the top-10 books written by Stephen King ordered by the user ranking reviews:

$query = <<<EOD
    FROM books
    | WHERE author == "Stephen King"
    | SORT rating DESC
    | LIMIT 10
EOD;

$result = $client->esql()->query([
    'body' => ['query' => $query]
]);

The JSON result from Elasticsearch looks as follows:

{
    "columns": [
        { "name": "author", "type": "text" },
        { "name": "description", "type": "text" },
        { "name": "publisher", "type": "keyword" },
        { "name": "rating", "type": "double" },
        { "name": "title", "type": "text" },
        { "name": "year", "type": "integer" }
    ],
    "values": [
        [
            "Stephen King",
            "The author ...",
            "Turtleback",
            5.0,
            "How writers write",
            2002
        ],
        [
            "Stephen King",
            "In Blockade Billy, a retired coach...",
            "Simon and Schuster",
            5.0,
            "Blockade",
            2010
        ],
        [
            "Stephen King",
            "A chilling collection of twenty horror stories.",
            "Signet Book",
            4.55859375,
            "Night Shift (Signet)",
            1979
        ],
        ...
    ]
}

In this example we have 6 properties (author, description, publisher, rating, title, year) related to a book and 10 results, all books by Stephen King.

A list of all the supported types in ES|QL is reported here.

The $result response object can be accessed as an array, a string or as an object (see here for more information).

Using the object interface, we can access the values using properties and indexes. For instance, $result->values[0][4] returns the title (4) of the first book (0) in the list, $result->values[1][3] returns the rank score (3) of the second book (1), etc. Remember, the index of an array in PHP starts from zero.

This interface can be good enough for some use cases but most of the time we would like to have an array of objects as result.

To map the result into an array of objects we can use the new mapTo() feature of elasticsearch-php.

This function is available directly in the Elasticsearch response object. That means you can access it as follows:

$books = $result->mapTo(); // Array of stdClass
foreach ($books as $book) {
    printf(
        "%s, %s, %d, Rating: %.2f\n",
        $book->author,
        $book->title,
        $book->year,
        $book->rating
    );
}

If you have a custom Book class, you can map the result using it, as follows:

class Book
{
    public string $author;
    public string $title;
    public string $description;
    public int $year;
    public float $rating;
}

$books = $result->mapTo(Book::class); // Array of Book

If your class has other properties in addition to the ones included in the ES|QL result, this will work as well. The mapTo() function will use only the properties returned as columns of the ES|QL result.

You can download all the examples reported in this article here.

Ready to build RAG into your apps? Want to try different LLMs with a vector database?
Check out our sample notebooks for LangChain, Cohere and more on Github, and join the Elasticsearch Engineer training starting soon!
Recommended Articles