Skip to content

Commit 2f30ede

Browse files
documentation
1 parent 6d7fca0 commit 2f30ede

File tree

2 files changed

+135
-2
lines changed

2 files changed

+135
-2
lines changed

docs/reference/dsl_how_to_guides.md

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1425,6 +1425,125 @@ print(response.took)
14251425
If you want to inspect the contents of the `response` objects, just use its `to_dict` method to get access to the raw data for pretty printing.
14261426

14271427

1428+
## ES|QL Queries
1429+
1430+
When working with `Document` classes, you can use the ES|QL query language to retrieve documents. Consider the following `Employee` document definition:
1431+
1432+
```python
1433+
from elasticsearch.dsl import Document, InnerDoc, M
1434+
1435+
class Address(InnerDoc):
1436+
address: M[str]
1437+
city: M[str]
1438+
zip_code: M[str]
1439+
1440+
class Employee(Document):
1441+
emp_no: M[int]
1442+
first_name: M[str]
1443+
last_name: M[str]
1444+
height: M[float]
1445+
still_hired: M[bool]
1446+
address: M[Address]
1447+
1448+
class Index:
1449+
name = 'employees'
1450+
```
1451+
1452+
All instances of `Document` include the `esql_from()` method, which creates a base query for the associated index. The following example creates a base query for employees:
1453+
1454+
```python
1455+
query = Employee.esql_from()
1456+
```
1457+
1458+
This query includes a `FROM` command with the index name, and a `KEEP` command that retrieves all the document attributes. To run this query, you can pass it to the `esql_execute()` method:
1459+
1460+
```python
1461+
for emp in Employee.esql_execute(query):
1462+
print(f"{emp.name} from {emp.address.city} is {emp.height:.2f}m tall")
1463+
```
1464+
1465+
In this example, the `esql_execute()` class method executes the query and returns all the documents in the index, up to the maximum of 1000 results allowed by ES|QL. Here is a possible output from this example:
1466+
1467+
```
1468+
Kevin Macias from North Robert is 1.60m tall
1469+
Drew Harris from Boltonshire is 1.68m tall
1470+
Julie Williams from Maddoxshire is 1.99m tall
1471+
Christopher Jones from Stevenbury is 1.98m tall
1472+
Anthony Lopez from Port Sarahtown is 2.42m tall
1473+
Tricia Stone from North Sueshire is 2.39m tall
1474+
Katherine Ramirez from Kimberlyton is 1.83m tall
1475+
...
1476+
```
1477+
1478+
To search for specific documents you can extend the base query with additional ES|QL commands that narrow the search. The next example searches for documents that include specific employees that are 2m tall or more, sorted by their last name. It also limits the results 4:
1479+
1480+
```python
1481+
query = (
1482+
Employee.esql_from()
1483+
.where(Employee.height >= 2)
1484+
.sort(Employee.last_name)
1485+
.limit(4)
1486+
)
1487+
```
1488+
1489+
When running this query, with the same for-loop shown above, possible results would be:
1490+
1491+
```
1492+
Michael Adkins from North Stacey is 2.48m tall
1493+
Kimberly Allen from Toddside is 2.24m tall
1494+
Crystal Austin from East Michaelchester is 2.30m tall
1495+
Rebecca Berger from Lake Adrianside is 2.40m tall
1496+
```
1497+
1498+
### Additional fields
1499+
1500+
ES|QL provides a few ways to add new fields to a query, for example through the `EVAL` command. The following example shows a query that adds a calculated field:
1501+
1502+
```python
1503+
from elasticsearch.esql import E, functions
1504+
1505+
query = (
1506+
Employee.esql_from()
1507+
.eval(height_cm=functions.round(Employee.height * 100))
1508+
.where(E("height_cm") >= 200)
1509+
.sort(Employee.last_name)
1510+
.limit(10)
1511+
)
1512+
```
1513+
1514+
In this example we are adding the height converted to centimeters to the query. This value is available to other query clauses, but it is not returned when the query is executed as shown in all previous examples.
1515+
1516+
Note how in the `WHERE` clause the new field is given as `E("height_cm")`. The `E()` wrapper tells the query builder that the argument is an ES|QL field name and not a string literal. This is done automatically for document fields that are given as class attributes, such as `Employee.first_name`, so `E()` is only needed for fields that are not in the document.
1517+
1518+
To receive the additional fields that are not part of the document in the query results, the `return_additional=True` argument can be passed to `esql_execute()`. When using this option, the results are given as a tuple with the document as first element, and a dictionary with the additional fields as second element:
1519+
1520+
```python
1521+
for emp, additional in Employee.esql_execute(query, return_additional=True):
1522+
print(emp.name, additional)
1523+
```
1524+
1525+
Example output:
1526+
1527+
```
1528+
Michael Adkins {'height_cm': 248.0}
1529+
Kimberly Allen {'height_cm': 224.0}
1530+
Crystal Austin {'height_cm': 230.0}
1531+
Rebecca Berger {'height_cm': 240.0}
1532+
Katherine Blake {'height_cm': 214.0}
1533+
Edward Butler {'height_cm': 246.0}
1534+
Steven Carlson {'height_cm': 242.0}
1535+
Mark Carter {'height_cm': 240.0}
1536+
Joseph Castillo {'height_cm': 229.0}
1537+
Alexander Cohen {'height_cm': 245.0}
1538+
```
1539+
1540+
### Missing fields
1541+
1542+
The base query returned by the `esql_from()` method includes a `KEEP` command with the complete list of fields that are part of the document. If the query adds a `DROP` command, or a more restrictive `KEEP`, then the `esql_execute()` method will raise an exception, because it will not be able construct the document instances.
1543+
1544+
To prevent errors, it is recommended that the `KEEP` and `DROP` commands are not used when working with `Document` instances.
1545+
1546+
If a query has missing fields, it can be forced to execute without errors by passing the `ignore_missing_fields=True` argument to `esql_execute()`. When this option is used, returned documents will have any missing fields set to `None`.
14281547

14291548
## Using asyncio with Elasticsearch Python DSL [asyncio]
14301549

docs/reference/dsl_tutorials.md

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,15 +83,15 @@ Let’s have a simple Python class representing an article in a blogging system:
8383

8484
```python
8585
from datetime import datetime
86-
from elasticsearch.dsl import Document, Date, Integer, Keyword, Text, connections
86+
from elasticsearch.dsl import Document, Date, Integer, Keyword, Text, connections, mapped_field
8787

8888
# Define a default Elasticsearch client
8989
connections.create_connection(hosts="https://localhost:9200")
9090

9191
class Article(Document):
9292
title: str = mapped_field(Text(analyzer='snowball', fields={'raw': Keyword()}))
9393
body: str = mapped_field(Text(analyzer='snowball'))
94-
tags: str = mapped_field(Keyword())
94+
tags: list[str] = mapped_field(Keyword())
9595
published_from: datetime
9696
lines: int
9797

@@ -216,6 +216,20 @@ response = ubq.execute()
216216
As you can see, the `Update By Query` object provides many of the savings offered by the `Search` object, and additionally allows one to update the results of the search based on a script assigned in the same manner.
217217

218218

219+
## Querying with ES|QL
220+
221+
The DSL module is also integrated with the ES|QL query builder. Using `Article` document from above, we can search for articles that include `"world"` with the following ES|QL query:
222+
223+
```python
224+
from elasticsearch.esql import functions
225+
226+
query = Article.esql_from().where(functions.match(Article.title, 'world')).limit(10)
227+
for a in Article.esql_execute(query):
228+
print(a.title)
229+
```
230+
231+
Review the [ES|QL Query Builder section](esql-query-builder.md) to learn more about building ES|QL queries in Python.
232+
219233
## Migration from the standard client [_migration_from_the_standard_client]
220234

221235
You don’t have to port your entire application to get the benefits of the DSL module, you can start gradually by creating a `Search` object from your existing `dict`, modifying it using the API and serializing it back to a `dict`:

0 commit comments

Comments
 (0)